2 * Default dialog procedure
4 * Copyright 1993, 1996 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "user_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dialog);
35 /***********************************************************************
38 static DLGPROC DEFDLG_GetDlgProc( HWND hwnd )
41 WND *wndPtr = WIN_GetPtr( hwnd );
43 if (!wndPtr) return 0;
44 if (wndPtr == WND_OTHER_PROCESS)
46 ERR( "cannot get dlg proc %p from other process\n", hwnd );
49 ret = *(DLGPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
50 WIN_ReleasePtr( wndPtr );
54 /***********************************************************************
57 * Set the focus to a control of the dialog, selecting the text if
58 * the control is an edit dialog.
60 static void DEFDLG_SetFocus( HWND hwndDlg, HWND hwndCtrl )
62 if (SendMessageW( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
63 SendMessageW( hwndCtrl, EM_SETSEL, 0, -1 );
68 /***********************************************************************
71 static void DEFDLG_SaveFocus( HWND hwnd )
74 HWND hwndFocus = GetFocus();
76 if (!hwndFocus || !IsChild( hwnd, hwndFocus )) return;
77 if (!(infoPtr = DIALOG_get_info( hwnd, FALSE ))) return;
78 infoPtr->hwndFocus = hwndFocus;
79 /* Remove default button */
83 /***********************************************************************
86 static void DEFDLG_RestoreFocus( HWND hwnd )
90 if (IsIconic( hwnd )) return;
91 if (!(infoPtr = DIALOG_get_info( hwnd, FALSE ))) return;
92 /* Don't set the focus back to controls if EndDialog is already called.*/
93 if (infoPtr->flags & DF_END) return;
94 if (!IsWindow(infoPtr->hwndFocus) || infoPtr->hwndFocus == hwnd) {
95 /* If no saved focus control exists, set focus to the first visible,
96 non-disabled, WS_TABSTOP control in the dialog */
97 infoPtr->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE );
98 if (!IsWindow( infoPtr->hwndFocus )) return;
100 DEFDLG_SetFocus( hwnd, infoPtr->hwndFocus );
102 /* This used to set infoPtr->hwndFocus to NULL for no apparent reason,
103 sometimes losing focus when receiving WM_SETFOCUS messages. */
107 /***********************************************************************
108 * DEFDLG_FindDefButton
110 * Find the current default push-button.
112 static HWND DEFDLG_FindDefButton( HWND hwndDlg )
114 HWND hwndChild, hwndTmp;
116 hwndChild = GetWindow( hwndDlg, GW_CHILD );
119 if (SendMessageW( hwndChild, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON)
122 /* Recurse into WS_EX_CONTROLPARENT controls */
123 if (GetWindowLongW( hwndChild, GWL_EXSTYLE ) & WS_EX_CONTROLPARENT)
125 LONG dsStyle = GetWindowLongW( hwndChild, GWL_STYLE );
126 if ((dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED) &&
127 (hwndTmp = DEFDLG_FindDefButton(hwndChild)) != NULL)
130 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
136 /***********************************************************************
139 * Set the default button id.
141 static BOOL DEFDLG_SetDefId( HWND hwndDlg, DIALOGINFO *dlgInfo, WPARAM wParam)
143 DWORD dlgcode=0; /* initialize just to avoid a warning */
144 HWND hwndOld, hwndNew = GetDlgItem(hwndDlg, wParam);
145 INT old_id = dlgInfo->idResult;
147 dlgInfo->idResult = wParam;
149 !((dlgcode=SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 ))
150 & (DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON)))
151 return FALSE; /* Destination is not a push button */
153 /* Make sure the old default control is a valid push button ID */
154 hwndOld = GetDlgItem( hwndDlg, old_id );
155 if (!hwndOld || !(SendMessageW( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON))
156 hwndOld = DEFDLG_FindDefButton( hwndDlg );
157 if (hwndOld && hwndOld != hwndNew)
158 SendMessageW( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
162 if(dlgcode & DLGC_UNDEFPUSHBUTTON)
163 SendMessageW( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
169 /***********************************************************************
170 * DEFDLG_SetDefButton
172 * Set the new default button to be hwndNew.
174 static BOOL DEFDLG_SetDefButton( HWND hwndDlg, DIALOGINFO *dlgInfo, HWND hwndNew )
176 DWORD dlgcode=0; /* initialize just to avoid a warning */
177 HWND hwndOld = GetDlgItem( hwndDlg, dlgInfo->idResult );
180 !((dlgcode=SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 ))
181 & (DLGC_UNDEFPUSHBUTTON | DLGC_DEFPUSHBUTTON)))
184 * Need to draw only default push button rectangle.
185 * Since the next control is not a push button, need to draw the push
186 * button rectangle for the default control.
189 dlgcode = SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 );
192 /* Make sure the old default control is a valid push button ID */
193 if (!hwndOld || !(SendMessageW( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON))
194 hwndOld = DEFDLG_FindDefButton( hwndDlg );
195 if (hwndOld && hwndOld != hwndNew)
196 SendMessageW( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
200 if(dlgcode & DLGC_UNDEFPUSHBUTTON)
201 SendMessageW( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
207 /***********************************************************************
210 * Implementation of DefDlgProc(). Only handle messages that need special
211 * handling for dialogs.
213 static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
214 LPARAM lParam, DIALOGINFO *dlgInfo )
220 HBRUSH brush = (HBRUSH)SendMessageW( hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd );
221 if (!brush) brush = (HBRUSH)DefWindowProcW( hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd );
225 HDC hdc = (HDC)wParam;
226 GetClientRect( hwnd, &rect );
227 DPtoLP( hdc, (LPPOINT)&rect, 2 );
228 FillRect( hdc, &rect, brush );
237 if (dlgInfo->hUserFont) DeleteObject( dlgInfo->hUserFont );
238 if (dlgInfo->hMenu) DestroyMenu( dlgInfo->hMenu );
239 HeapFree( GetProcessHeap(), 0, dlgInfo );
241 wndPtr = WIN_GetPtr( hwnd );
242 wndPtr->dlgInfo = NULL;
243 WIN_ReleasePtr( wndPtr );
245 /* Window clean-up */
246 return DefWindowProcA( hwnd, msg, wParam, lParam );
249 if (!wParam) DEFDLG_SaveFocus( hwnd );
250 return DefWindowProcA( hwnd, msg, wParam, lParam );
253 if (wParam) DEFDLG_RestoreFocus( hwnd );
254 else DEFDLG_SaveFocus( hwnd );
258 DEFDLG_RestoreFocus( hwnd );
262 if (dlgInfo && !(dlgInfo->flags & DF_END))
263 DEFDLG_SetDefId( hwnd, dlgInfo, wParam );
267 if (dlgInfo && !(dlgInfo->flags & DF_END))
270 if (dlgInfo->idResult)
271 return MAKELONG( dlgInfo->idResult, DC_HASDEFID );
272 if ((hwndDefId = DEFDLG_FindDefButton( hwnd )))
273 return MAKELONG( GetDlgCtrlID( hwndDefId ), DC_HASDEFID);
280 HWND hwndDest = (HWND)wParam;
282 hwndDest = GetNextDlgTabItem(hwnd, GetFocus(), wParam);
283 if (hwndDest) DEFDLG_SetFocus( hwnd, hwndDest );
284 DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest );
288 case WM_ENTERMENULOOP:
290 case WM_NCLBUTTONDOWN:
292 HWND hwndFocus = GetFocus();
295 /* always make combo box hide its listbox control */
296 if (!SendMessageW( hwndFocus, CB_SHOWDROPDOWN, FALSE, 0 ))
297 SendMessageW( GetParent(hwndFocus), CB_SHOWDROPDOWN, FALSE, 0 );
300 return DefWindowProcA( hwnd, msg, wParam, lParam );
303 return dlgInfo ? (LRESULT)dlgInfo->hUserFont : 0;
306 PostMessageA( hwnd, WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED),
307 (LPARAM)GetDlgItem( hwnd, IDCANCEL ) );
313 /***********************************************************************
316 * Get the DIALOGINFO structure of a window, allocating it if needed
317 * and 'create' is TRUE.
319 DIALOGINFO *DIALOG_get_info( HWND hwnd, BOOL create )
324 wndPtr = WIN_GetPtr( hwnd );
325 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
327 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
331 dlgInfo = wndPtr->dlgInfo;
333 if (!dlgInfo && create)
335 if (!(dlgInfo = HeapAlloc( GetProcessHeap(), 0, sizeof(*dlgInfo) )))
337 dlgInfo->hwndFocus = 0;
338 dlgInfo->hUserFont = 0;
340 dlgInfo->xBaseUnit = 0;
341 dlgInfo->yBaseUnit = 0;
342 dlgInfo->idResult = 0;
344 wndPtr->dlgInfo = dlgInfo;
348 WIN_ReleasePtr( wndPtr );
352 /***********************************************************************
353 * DefDlgProcA (USER32.@)
355 LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
361 /* Perform DIALOGINFO initialization if not done */
362 if(!(dlgInfo = DIALOG_get_info( hwnd, TRUE ))) return 0;
364 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, 0 );
366 if ((dlgproc = DEFDLG_GetDlgProc( hwnd ))) /* Call dialog procedure */
367 result = WINPROC_CallDlgProcA( dlgproc, hwnd, msg, wParam, lParam );
369 if (!result && IsWindow(hwnd))
371 /* callback didn't process this message */
385 case WM_ENTERMENULOOP:
387 case WM_NCLBUTTONDOWN:
388 return DEFDLG_Proc( hwnd, msg, wParam, lParam, dlgInfo );
396 return DefWindowProcA( hwnd, msg, wParam, lParam );
400 if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
401 msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
402 msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
403 msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
406 return GetWindowLongPtrW( hwnd, DWLP_MSGRESULT );
410 /***********************************************************************
411 * DefDlgProcW (USER32.@)
413 LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
419 /* Perform DIALOGINFO initialization if not done */
420 if(!(dlgInfo = DIALOG_get_info( hwnd, TRUE ))) return 0;
422 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, 0 );
424 if ((dlgproc = DEFDLG_GetDlgProc( hwnd ))) /* Call dialog procedure */
425 result = WINPROC_CallDlgProcW( dlgproc, hwnd, msg, wParam, lParam );
427 if (!result && IsWindow(hwnd))
429 /* callback didn't process this message */
443 case WM_ENTERMENULOOP:
445 case WM_NCLBUTTONDOWN:
446 return DEFDLG_Proc( hwnd, msg, wParam, lParam, dlgInfo );
454 return DefWindowProcW( hwnd, msg, wParam, lParam );
458 if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
459 msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
460 msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
461 msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
464 return GetWindowLongPtrW( hwnd, DWLP_MSGRESULT );