1 /*
2 * Default dialog procedure
3 *
4 * Copyright 1993, 1996 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "wine/winuser16.h"
27 #include "controls.h"
28 #include "win.h"
29 #include "user_private.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(dialog);
33
34
35 /***********************************************************************
36 * DEFDLG_GetDlgProc
37 */
38 static DLGPROC DEFDLG_GetDlgProc( HWND hwnd )
39 {
40 DLGPROC ret;
41 WND *wndPtr = WIN_GetPtr( hwnd );
42
43 if (!wndPtr) return 0;
44 if (wndPtr == WND_OTHER_PROCESS)
45 {
46 ERR( "cannot get dlg proc %p from other process\n", hwnd );
47 return 0;
48 }
49 ret = *(DLGPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
50 WIN_ReleasePtr( wndPtr );
51 return ret;
52 }
53
54 /***********************************************************************
55 * DEFDLG_SetFocus
56 *
57 * Set the focus to a control of the dialog, selecting the text if
58 * the control is an edit dialog.
59 */
60 static void DEFDLG_SetFocus( HWND hwndDlg, HWND hwndCtrl )
61 {
62 if (SendMessageW( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
63 SendMessageW( hwndCtrl, EM_SETSEL, 0, -1 );
64 SetFocus( hwndCtrl );
65 }
66
67
68 /***********************************************************************
69 * DEFDLG_SaveFocus
70 */
71 static void DEFDLG_SaveFocus( HWND hwnd )
72 {
73 DIALOGINFO *infoPtr;
74 HWND hwndFocus = GetFocus();
75
76 if (!hwndFocus || !IsChild( hwnd, hwndFocus )) return;
77 if (!(infoPtr = DIALOG_get_info( hwnd, FALSE ))) return;
78 infoPtr->hwndFocus = hwndFocus;
79 /* Remove default button */
80 }
81
82
83 /***********************************************************************
84 * DEFDLG_RestoreFocus
85 */
86 static void DEFDLG_RestoreFocus( HWND hwnd )
87 {
88 DIALOGINFO *infoPtr;
89
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;
99 }
100 DEFDLG_SetFocus( hwnd, infoPtr->hwndFocus );
101
102 /* This used to set infoPtr->hwndFocus to NULL for no apparent reason,
103 sometimes losing focus when receiving WM_SETFOCUS messages. */
104 }
105
106
107 /***********************************************************************
108 * DEFDLG_FindDefButton
109 *
110 * Find the current default push-button.
111 */
112 static HWND DEFDLG_FindDefButton( HWND hwndDlg )
113 {
114 HWND hwndChild, hwndTmp;
115
116 hwndChild = GetWindow( hwndDlg, GW_CHILD );
117 while (hwndChild)
118 {
119 if (SendMessageW( hwndChild, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON)
120 break;
121
122 /* Recurse into WS_EX_CONTROLPARENT controls */
123 if (GetWindowLongW( hwndChild, GWL_EXSTYLE ) & WS_EX_CONTROLPARENT)
124 {
125 LONG dsStyle = GetWindowLongW( hwndChild, GWL_STYLE );
126 if ((dsStyle & WS_VISIBLE) && !(dsStyle & WS_DISABLED) &&
127 (hwndTmp = DEFDLG_FindDefButton(hwndChild)) != NULL)
128 return hwndTmp;
129 }
130 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
131 }
132 return hwndChild;
133 }
134
135
136 /***********************************************************************
137 * DEFDLG_SetDefId
138 *
139 * Set the default button id.
140 */
141 static BOOL DEFDLG_SetDefId( HWND hwndDlg, DIALOGINFO *dlgInfo, WPARAM wParam)
142 {
143 DWORD dlgcode=0; /* initialize just to avoid a warning */
144 HWND hwndOld, hwndNew = GetDlgItem(hwndDlg, wParam);
145 INT old_id = dlgInfo->idResult;
146
147 dlgInfo->idResult = wParam;
148 if (hwndNew &&
149 !((dlgcode=SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 ))
150 & (DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON)))
151 return FALSE; /* Destination is not a push button */
152
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 );
159
160 if (hwndNew)
161 {
162 if(dlgcode & DLGC_UNDEFPUSHBUTTON)
163 SendMessageW( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
164 }
165 return TRUE;
166 }
167
168
169 /***********************************************************************
170 * DEFDLG_SetDefButton
171 *
172 * Set the new default button to be hwndNew.
173 */
174 static BOOL DEFDLG_SetDefButton( HWND hwndDlg, DIALOGINFO *dlgInfo, HWND hwndNew )
175 {
176 DWORD dlgcode=0; /* initialize just to avoid a warning */
177 HWND hwndOld = GetDlgItem( hwndDlg, dlgInfo->idResult );
178
179 if (hwndNew &&
180 !((dlgcode=SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 ))
181 & (DLGC_UNDEFPUSHBUTTON | DLGC_DEFPUSHBUTTON)))
182 {
183 /**
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.
187 */
188 hwndNew = hwndOld;
189 dlgcode = SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 );
190 }
191
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 );
197
198 if (hwndNew)
199 {
200 if(dlgcode & DLGC_UNDEFPUSHBUTTON)
201 SendMessageW( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
202 }
203 return TRUE;
204 }
205
206
207 /***********************************************************************
208 * DEFDLG_Proc
209 *
210 * Implementation of DefDlgProc(). Only handle messages that need special
211 * handling for dialogs.
212 */
213 static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
214 LPARAM lParam, DIALOGINFO *dlgInfo )
215 {
216 switch(msg)
217 {
218 case WM_ERASEBKGND:
219 {
220 HBRUSH brush = (HBRUSH)SendMessageW( hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd );
221 if (!brush) brush = (HBRUSH)DefWindowProcW( hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd );
222 if (brush)
223 {
224 RECT rect;
225 HDC hdc = (HDC)wParam;
226 GetClientRect( hwnd, &rect );
227 DPtoLP( hdc, (LPPOINT)&rect, 2 );
228 FillRect( hdc, &rect, brush );
229 }
230 return 1;
231 }
232 case WM_NCDESTROY:
233 if ((dlgInfo = (DIALOGINFO *)SetWindowLongPtrW( hwnd, DWLP_WINE_DIALOGINFO, 0 )))
234 {
235 /* Free dialog heap (if created) */
236 if (dlgInfo->hDialogHeap)
237 {
238 GlobalUnlock16(dlgInfo->hDialogHeap);
239 GlobalFree16(dlgInfo->hDialogHeap);
240 }
241 if (dlgInfo->hUserFont) DeleteObject( dlgInfo->hUserFont );
242 if (dlgInfo->hMenu) DestroyMenu( dlgInfo->hMenu );
243 HeapFree( GetProcessHeap(), 0, dlgInfo );
244 }
245 /* Window clean-up */
246 return DefWindowProcA( hwnd, msg, wParam, lParam );
247
248 case WM_SHOWWINDOW:
249 if (!wParam) DEFDLG_SaveFocus( hwnd );
250 return DefWindowProcA( hwnd, msg, wParam, lParam );
251
252 case WM_ACTIVATE:
253 if (wParam) DEFDLG_RestoreFocus( hwnd );
254 else DEFDLG_SaveFocus( hwnd );
255 return 0;
256
257 case WM_SETFOCUS:
258 DEFDLG_RestoreFocus( hwnd );
259 return 0;
260
261 case DM_SETDEFID:
262 if (dlgInfo && !(dlgInfo->flags & DF_END))
263 DEFDLG_SetDefId( hwnd, dlgInfo, wParam );
264 return 1;
265
266 case DM_GETDEFID:
267 if (dlgInfo && !(dlgInfo->flags & DF_END))
268 {
269 HWND hwndDefId;
270 if (dlgInfo->idResult)
271 return MAKELONG( dlgInfo->idResult, DC_HASDEFID );
272 if ((hwndDefId = DEFDLG_FindDefButton( hwnd )))
273 return MAKELONG( GetDlgCtrlID( hwndDefId ), DC_HASDEFID);
274 }
275 return 0;
276
277 case WM_NEXTDLGCTL:
278 if (dlgInfo)
279 {
280 HWND hwndDest = (HWND)wParam;
281 if (!lParam)
282 hwndDest = GetNextDlgTabItem(hwnd, GetFocus(), wParam);
283 if (hwndDest) DEFDLG_SetFocus( hwnd, hwndDest );
284 DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest );
285 }
286 return 0;
287
288 case WM_ENTERMENULOOP:
289 case WM_LBUTTONDOWN:
290 case WM_NCLBUTTONDOWN:
291 {
292 HWND hwndFocus = GetFocus();
293 if (hwndFocus)
294 {
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 );
298 }
299 }
300 return DefWindowProcA( hwnd, msg, wParam, lParam );
301
302 case WM_GETFONT:
303 return dlgInfo ? (LRESULT)dlgInfo->hUserFont : 0;
304
305 case WM_CLOSE:
306 PostMessageA( hwnd, WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED),
307 (LPARAM)GetDlgItem( hwnd, IDCANCEL ) );
308 return 0;
309 }
310 return 0;
311 }
312
313 /***********************************************************************
314 * DEFDLG_Epilog
315 */
316 static LRESULT DEFDLG_Epilog(HWND hwnd, UINT msg, BOOL fResult)
317 {
318 /* see SDK 3.1 */
319
320 if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
321 msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
322 msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
323 msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
324 return fResult;
325
326 return GetWindowLongPtrW( hwnd, DWLP_MSGRESULT );
327 }
328
329 /***********************************************************************
330 * DIALOG_get_info
331 *
332 * Get the DIALOGINFO structure of a window, allocating it if needed
333 * and 'create' is TRUE.
334 */
335 DIALOGINFO *DIALOG_get_info( HWND hwnd, BOOL create )
336 {
337 WND* wndPtr;
338 DIALOGINFO* dlgInfo = (DIALOGINFO *)GetWindowLongPtrW( hwnd, DWLP_WINE_DIALOGINFO );
339
340 if(!dlgInfo && create)
341 {
342 if (!(dlgInfo = HeapAlloc( GetProcessHeap(), 0, sizeof(*dlgInfo) ))) return NULL;
343 dlgInfo->hwndFocus = 0;
344 dlgInfo->hUserFont = 0;
345 dlgInfo->hMenu = 0;
346 dlgInfo->xBaseUnit = 0;
347 dlgInfo->yBaseUnit = 0;
348 dlgInfo->idResult = 0;
349 dlgInfo->flags = 0;
350 dlgInfo->hDialogHeap = 0;
351 wndPtr = WIN_GetPtr( hwnd );
352 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
353 {
354 wndPtr->flags |= WIN_ISDIALOG;
355 WIN_ReleasePtr( wndPtr );
356 SetWindowLongPtrW( hwnd, DWLP_WINE_DIALOGINFO, (ULONG_PTR)dlgInfo );
357 }
358 else
359 {
360 HeapFree( GetProcessHeap(), 0, dlgInfo );
361 return NULL;
362 }
363 }
364 return dlgInfo;
365 }
366
367 /***********************************************************************
368 * DefDlgProc (USER.308)
369 */
370 LRESULT WINAPI DefDlgProc16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
371 LPARAM lParam )
372 {
373 DIALOGINFO *dlgInfo;
374 DLGPROC16 dlgproc;
375 HWND hwnd32 = WIN_Handle32( hwnd );
376 BOOL result = FALSE;
377
378 /* Perform DIALOGINFO initialization if not done */
379 if(!(dlgInfo = DIALOG_get_info(hwnd32, TRUE))) return -1;
380
381 SetWindowLongPtrW( hwnd32, DWLP_MSGRESULT, 0 );
382
383 if ((dlgproc = (DLGPROC16)DEFDLG_GetDlgProc( hwnd32 ))) /* Call dialog procedure */
384 result = WINPROC_CallDlgProc16( dlgproc, hwnd, msg, wParam, lParam );
385
386 if (!result && IsWindow(hwnd32))
387 {
388 /* callback didn't process this message */
389
390 switch(msg)
391 {
392 case WM_ERASEBKGND:
393 case WM_SHOWWINDOW:
394 case WM_ACTIVATE:
395 case WM_SETFOCUS:
396 case DM_SETDEFID:
397 case DM_GETDEFID:
398 case WM_NEXTDLGCTL:
399 case WM_GETFONT:
400 case WM_CLOSE:
401 case WM_NCDESTROY:
402 case WM_ENTERMENULOOP:
403 case WM_LBUTTONDOWN:
404 case WM_NCLBUTTONDOWN:
405 return DEFDLG_Proc( hwnd32, msg, (WPARAM)wParam, lParam, dlgInfo );
406 case WM_INITDIALOG:
407 case WM_VKEYTOITEM:
408 case WM_COMPAREITEM:
409 case WM_CHARTOITEM:
410 break;
411
412 default:
413 return DefWindowProc16( hwnd, msg, wParam, lParam );
414 }
415 }
416 return DEFDLG_Epilog( hwnd32, msg, result);
417 }
418
419
420 /***********************************************************************
421 * DefDlgProcA (USER32.@)
422 */
423 LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
424 {
425 DIALOGINFO *dlgInfo;
426 DLGPROC dlgproc;
427 BOOL result = FALSE;
428
429 /* Perform DIALOGINFO initialization if not done */
430 if(!(dlgInfo = DIALOG_get_info( hwnd, TRUE ))) return -1;
431
432 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, 0 );
433
434 if ((dlgproc = DEFDLG_GetDlgProc( hwnd ))) /* Call dialog procedure */
435 result = WINPROC_CallDlgProcA( dlgproc, hwnd, msg, wParam, lParam );
436
437 if (!result && IsWindow(hwnd))
438 {
439 /* callback didn't process this message */
440
441 switch(msg)
442 {
443 case WM_ERASEBKGND:
444 case WM_SHOWWINDOW:
445 case WM_ACTIVATE:
446 case WM_SETFOCUS:
447 case DM_SETDEFID:
448 case DM_GETDEFID:
449 case WM_NEXTDLGCTL:
450 case WM_GETFONT:
451 case WM_CLOSE:
452 case WM_NCDESTROY:
453 case WM_ENTERMENULOOP:
454 case WM_LBUTTONDOWN:
455 case WM_NCLBUTTONDOWN:
456 return DEFDLG_Proc( hwnd, msg, wParam, lParam, dlgInfo );
457 case WM_INITDIALOG:
458 case WM_VKEYTOITEM:
459 case WM_COMPAREITEM:
460 case WM_CHARTOITEM:
461 break;
462
463 default:
464 return DefWindowProcA( hwnd, msg, wParam, lParam );
465 }
466 }
467 return DEFDLG_Epilog(hwnd, msg, result);
468 }
469
470
471 /***********************************************************************
472 * DefDlgProcW (USER32.@)
473 */
474 LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
475 {
476 DIALOGINFO *dlgInfo;
477 BOOL result = FALSE;
478 DLGPROC dlgproc;
479
480 /* Perform DIALOGINFO initialization if not done */
481 if(!(dlgInfo = DIALOG_get_info( hwnd, TRUE ))) return -1;
482
483 SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, 0 );
484
485 if ((dlgproc = DEFDLG_GetDlgProc( hwnd ))) /* Call dialog procedure */
486 result = WINPROC_CallDlgProcW( dlgproc, hwnd, msg, wParam, lParam );
487
488 if (!result && IsWindow(hwnd))
489 {
490 /* callback didn't process this message */
491
492 switch(msg)
493 {
494 case WM_ERASEBKGND:
495 case WM_SHOWWINDOW:
496 case WM_ACTIVATE:
497 case WM_SETFOCUS:
498 case DM_SETDEFID:
499 case DM_GETDEFID:
500 case WM_NEXTDLGCTL:
501 case WM_GETFONT:
502 case WM_CLOSE:
503 case WM_NCDESTROY:
504 case WM_ENTERMENULOOP:
505 case WM_LBUTTONDOWN:
506 case WM_NCLBUTTONDOWN:
507 return DEFDLG_Proc( hwnd, msg, wParam, lParam, dlgInfo );
508 case WM_INITDIALOG:
509 case WM_VKEYTOITEM:
510 case WM_COMPAREITEM:
511 case WM_CHARTOITEM:
512 break;
513
514 default:
515 return DefWindowProcW( hwnd, msg, wParam, lParam );
516 }
517 }
518 return DEFDLG_Epilog(hwnd, msg, result);
519 }
520
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.