uiautomationcore/tests: Add tests for cached value helper functions in the COM API.
[wine.git] / dlls / user32 / defdlg.c
blob88b64ee469c1ddbae9ddd8656c5ca866c299a3c8
1 /*
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
21 #include "user_private.h"
22 #include "controls.h"
25 /***********************************************************************
26 * DEFDLG_SetFocus
28 * Set the focus to a control of the dialog, selecting the text if
29 * the control is an edit dialog that has DLGC_HASSETSEL.
31 static void DEFDLG_SetFocus( HWND hwndCtrl )
33 if (SendMessageW( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
34 SendMessageW( hwndCtrl, EM_SETSEL, 0, -1 );
35 NtUserSetFocus( hwndCtrl );
39 /***********************************************************************
40 * DEFDLG_SaveFocus
42 static void DEFDLG_SaveFocus( HWND hwnd )
44 DIALOGINFO *infoPtr;
45 HWND hwndFocus = GetFocus();
47 if (!hwndFocus || !IsChild( hwnd, hwndFocus )) return;
48 if (!(infoPtr = DIALOG_get_info( hwnd, FALSE ))) return;
49 infoPtr->hwndFocus = hwndFocus;
50 /* Remove default button */
54 /***********************************************************************
55 * DEFDLG_RestoreFocus
57 static void DEFDLG_RestoreFocus( HWND hwnd, BOOL justActivate )
59 DIALOGINFO *infoPtr;
61 if (IsIconic( hwnd )) return;
62 if (!(infoPtr = DIALOG_get_info( hwnd, FALSE ))) return;
63 /* Don't set the focus back to controls if EndDialog is already called.*/
64 if (infoPtr->flags & DF_END) return;
65 if (!IsWindow(infoPtr->hwndFocus) || infoPtr->hwndFocus == hwnd) {
66 if (justActivate) return;
67 /* If no saved focus control exists, set focus to the first visible,
68 non-disabled, WS_TABSTOP control in the dialog */
69 infoPtr->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE );
70 /* If there are no WS_TABSTOP controls, set focus to the first visible,
71 non-disabled control in the dialog */
72 if (!infoPtr->hwndFocus) infoPtr->hwndFocus = GetNextDlgGroupItem( hwnd, 0, FALSE );
73 if (!IsWindow( infoPtr->hwndFocus )) return;
75 if (justActivate)
76 NtUserSetFocus( infoPtr->hwndFocus );
77 else
78 DEFDLG_SetFocus( infoPtr->hwndFocus );
79 infoPtr->hwndFocus = NULL;
83 /***********************************************************************
84 * DEFDLG_FindDefButton
86 * Find the current default push-button.
88 static HWND DEFDLG_FindDefButton( HWND hwndDlg )
90 HWND hwndChild, hwndTmp;
92 hwndChild = GetWindow( hwndDlg, GW_CHILD );
93 while (hwndChild)
95 if (SendMessageW( hwndChild, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON)
96 break;
98 /* Recurse into WS_EX_CONTROLPARENT controls */
99 if (GetWindowLongW( hwndChild, GWL_EXSTYLE ) & WS_EX_CONTROLPARENT)
101 LONG dsStyle = GetWindowLongW( hwndChild, GWL_STYLE );
102 if ((dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED) &&
103 (hwndTmp = DEFDLG_FindDefButton(hwndChild)) != NULL)
104 return hwndTmp;
106 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
108 return hwndChild;
112 /***********************************************************************
113 * DEFDLG_SetDefId
115 * Set the default button id.
117 static BOOL DEFDLG_SetDefId( HWND hwndDlg, DIALOGINFO *dlgInfo, WPARAM wParam)
119 DWORD dlgcode=0; /* initialize just to avoid a warning */
120 HWND hwndOld, hwndNew = GetDlgItem(hwndDlg, wParam);
121 INT old_id = dlgInfo->idResult;
123 dlgInfo->idResult = wParam;
124 if (hwndNew &&
125 !((dlgcode=SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 ))
126 & (DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON)))
127 return FALSE; /* Destination is not a push button */
129 /* Make sure the old default control is a valid push button ID */
130 hwndOld = GetDlgItem( hwndDlg, old_id );
131 if (!hwndOld || !(SendMessageW( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON))
132 hwndOld = DEFDLG_FindDefButton( hwndDlg );
133 if (hwndOld && hwndOld != hwndNew)
134 SendMessageW( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
136 if (hwndNew)
138 if(dlgcode & DLGC_UNDEFPUSHBUTTON)
139 SendMessageW( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
141 return TRUE;
145 /***********************************************************************
146 * DEFDLG_SetDefButton
148 * Set the new default button to be hwndNew.
150 static BOOL DEFDLG_SetDefButton( HWND hwndDlg, DIALOGINFO *dlgInfo, HWND hwndNew )
152 DWORD dlgcode=0; /* initialize just to avoid a warning */
153 HWND hwndOld = GetDlgItem( hwndDlg, dlgInfo->idResult );
155 if (hwndNew &&
156 !((dlgcode=SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 ))
157 & (DLGC_UNDEFPUSHBUTTON | DLGC_DEFPUSHBUTTON)))
160 * Need to draw only default push button rectangle.
161 * Since the next control is not a push button, need to draw the push
162 * button rectangle for the default control.
164 hwndNew = hwndOld;
165 dlgcode = SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 );
168 /* Make sure the old default control is a valid push button ID */
169 if (!hwndOld || !(SendMessageW( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON))
170 hwndOld = DEFDLG_FindDefButton( hwndDlg );
171 if (hwndOld && hwndOld != hwndNew)
172 SendMessageW( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
174 if (hwndNew)
176 if(dlgcode & DLGC_UNDEFPUSHBUTTON)
177 SendMessageW( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
179 return TRUE;
183 /***********************************************************************
184 * DEFDLG_Proc
186 * Implementation of DefDlgProc(). Only handle messages that need special
187 * handling for dialogs.
189 static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
190 LPARAM lParam, DIALOGINFO *dlgInfo )
192 switch(msg)
194 case WM_ERASEBKGND:
196 HBRUSH brush = (HBRUSH)SendMessageW( hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd );
197 if (!brush) brush = (HBRUSH)DefWindowProcW( hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd );
198 if (brush)
200 RECT rect;
201 HDC hdc = (HDC)wParam;
202 GetClientRect( hwnd, &rect );
203 DPtoLP( hdc, (LPPOINT)&rect, 2 );
204 FillRect( hdc, &rect, brush );
206 return 1;
208 case WM_NCDESTROY:
209 if (dlgInfo)
211 if (dlgInfo->hUserFont) DeleteObject( dlgInfo->hUserFont );
212 if (dlgInfo->hMenu) NtUserDestroyMenu( dlgInfo->hMenu );
213 HeapFree( GetProcessHeap(), 0, dlgInfo );
215 NtUserSetDialogInfo( hwnd, NULL );
217 /* Window clean-up */
218 return DefWindowProcA( hwnd, msg, wParam, lParam );
220 case WM_SHOWWINDOW:
221 if (!wParam) DEFDLG_SaveFocus( hwnd );
222 return DefWindowProcA( hwnd, msg, wParam, lParam );
224 case WM_ACTIVATE:
225 if (wParam) DEFDLG_RestoreFocus( hwnd, TRUE );
226 else DEFDLG_SaveFocus( hwnd );
227 return 0;
229 case WM_SETFOCUS:
230 DEFDLG_RestoreFocus( hwnd, FALSE );
231 return 0;
233 case DM_SETDEFID:
234 if (dlgInfo && !(dlgInfo->flags & DF_END))
235 DEFDLG_SetDefId( hwnd, dlgInfo, wParam );
236 return 1;
238 case DM_GETDEFID:
239 if (dlgInfo && !(dlgInfo->flags & DF_END))
241 HWND hwndDefId;
242 if (dlgInfo->idResult)
243 return MAKELONG( dlgInfo->idResult, DC_HASDEFID );
244 if ((hwndDefId = DEFDLG_FindDefButton( hwnd )))
245 return MAKELONG( GetDlgCtrlID( hwndDefId ), DC_HASDEFID);
247 return 0;
249 case WM_NEXTDLGCTL:
250 if (dlgInfo)
252 HWND hwndDest = (HWND)wParam;
253 if (!lParam)
254 hwndDest = GetNextDlgTabItem(hwnd, GetFocus(), wParam);
255 if (hwndDest) DEFDLG_SetFocus( hwndDest );
256 DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest );
258 return 0;
260 case WM_ENTERMENULOOP:
261 case WM_LBUTTONDOWN:
262 case WM_NCLBUTTONDOWN:
264 HWND hwndFocus = GetFocus();
265 if (hwndFocus)
267 /* always make combo box hide its listbox control */
268 if (!SendMessageW( hwndFocus, CB_SHOWDROPDOWN, FALSE, 0 ))
269 SendMessageW( GetParent(hwndFocus), CB_SHOWDROPDOWN, FALSE, 0 );
272 return DefWindowProcA( hwnd, msg, wParam, lParam );
274 case WM_GETFONT:
275 return dlgInfo ? (LRESULT)dlgInfo->hUserFont : 0;
277 case WM_CLOSE:
278 PostMessageA( hwnd, WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED),
279 (LPARAM)GetDlgItem( hwnd, IDCANCEL ) );
280 return 0;
282 return 0;
285 /***********************************************************************
286 * DIALOG_get_info
288 * Get the DIALOGINFO structure of a window, allocating it if needed
289 * and 'create' is TRUE.
291 DIALOGINFO *DIALOG_get_info( HWND hwnd, BOOL create )
293 DIALOGINFO* dlgInfo;
295 dlgInfo = NtUserGetDialogInfo( hwnd );
297 if (!dlgInfo && create)
299 if (!(dlgInfo = HeapAlloc( GetProcessHeap(), 0, sizeof(*dlgInfo) )))
300 return NULL;
301 dlgInfo->hwndFocus = 0;
302 dlgInfo->hUserFont = 0;
303 dlgInfo->hMenu = 0;
304 dlgInfo->xBaseUnit = 0;
305 dlgInfo->yBaseUnit = 0;
306 dlgInfo->idResult = IDOK;
307 dlgInfo->flags = 0;
308 NtUserSetDialogInfo( hwnd, dlgInfo );
311 return dlgInfo;
314 static LRESULT USER_DefDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
316 DIALOGINFO *dlgInfo;
317 LRESULT result;
319 /* Perform DIALOGINFO initialization if not done */
320 if(!(dlgInfo = DIALOG_get_info( hwnd, TRUE ))) return 0;
322 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, 0 );
324 result = WINPROC_CallDlgProcA( hwnd, msg, wParam, lParam );
326 if (!result && IsWindow(hwnd))
328 /* callback didn't process this message */
330 switch(msg)
332 case WM_ERASEBKGND:
333 case WM_SHOWWINDOW:
334 case WM_ACTIVATE:
335 case WM_SETFOCUS:
336 case DM_SETDEFID:
337 case DM_GETDEFID:
338 case WM_NEXTDLGCTL:
339 case WM_GETFONT:
340 case WM_CLOSE:
341 case WM_NCDESTROY:
342 case WM_ENTERMENULOOP:
343 case WM_LBUTTONDOWN:
344 case WM_NCLBUTTONDOWN:
345 return DEFDLG_Proc( hwnd, msg, wParam, lParam, dlgInfo );
346 case WM_INITDIALOG:
347 case WM_VKEYTOITEM:
348 case WM_COMPAREITEM:
349 case WM_CHARTOITEM:
350 break;
352 default:
353 return DefWindowProcA( hwnd, msg, wParam, lParam );
357 if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
358 msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
359 msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
360 msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
361 return result;
363 return GetWindowLongPtrW( hwnd, DWLP_MSGRESULT );
366 static LRESULT USER_DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
368 DIALOGINFO *dlgInfo;
369 LRESULT result;
371 /* Perform DIALOGINFO initialization if not done */
372 if(!(dlgInfo = DIALOG_get_info( hwnd, TRUE ))) return 0;
374 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, 0 );
375 result = WINPROC_CallDlgProcW( hwnd, msg, wParam, lParam );
377 if (!result && IsWindow(hwnd))
379 /* callback didn't process this message */
381 switch(msg)
383 case WM_ERASEBKGND:
384 case WM_SHOWWINDOW:
385 case WM_ACTIVATE:
386 case WM_SETFOCUS:
387 case DM_SETDEFID:
388 case DM_GETDEFID:
389 case WM_NEXTDLGCTL:
390 case WM_GETFONT:
391 case WM_CLOSE:
392 case WM_NCDESTROY:
393 case WM_ENTERMENULOOP:
394 case WM_LBUTTONDOWN:
395 case WM_NCLBUTTONDOWN:
396 return DEFDLG_Proc( hwnd, msg, wParam, lParam, dlgInfo );
397 case WM_INITDIALOG:
398 case WM_VKEYTOITEM:
399 case WM_COMPAREITEM:
400 case WM_CHARTOITEM:
401 break;
403 default:
404 return DefWindowProcW( hwnd, msg, wParam, lParam );
408 if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
409 msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
410 msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
411 msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
412 return result;
414 return GetWindowLongPtrW( hwnd, DWLP_MSGRESULT );
417 LRESULT WINAPI USER_DefDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode )
419 if (unicode)
420 return USER_DefDlgProcW( hwnd, msg, wParam, lParam );
421 else
422 return USER_DefDlgProcA( hwnd, msg, wParam, lParam );
425 /***********************************************************************
426 * DefDlgProcA (USER32.@)
428 LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
430 return user_api->pDefDlgProc( hwnd, msg, wParam, lParam, FALSE );
433 /***********************************************************************
434 * DefDlgProcW (USER32.@)
436 LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
438 return user_api->pDefDlgProc( hwnd, msg, wParam, lParam, TRUE );