Always calls SetMenu in MDISetMenu.
[wine] / windows / defdlg.c
1 /*
2  * Default dialog procedure
3  *
4  * Copyright 1993, 1996 Alexandre Julliard
5  *
6  */
7
8 #include "windef.h"
9 #include "winbase.h"
10 #include "wingdi.h"
11 #include "wine/winuser16.h"
12 #include "dialog.h"
13 #include "win.h"
14 #include "winproc.h"
15
16
17 /***********************************************************************
18  *           DEFDLG_SetFocus
19  *
20  * Set the focus to a control of the dialog, selecting the text if
21  * the control is an edit dialog.
22  */
23 static void DEFDLG_SetFocus( HWND hwndDlg, HWND hwndCtrl )
24 {
25     HWND hwndPrev = GetFocus();
26
27     if (IsChild( hwndDlg, hwndPrev ))
28     {
29         if (SendMessage16( hwndPrev, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
30             SendMessage16( hwndPrev, EM_SETSEL16, TRUE, MAKELONG( -1, 0 ) );
31     }
32     if (SendMessage16( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
33         SendMessage16( hwndCtrl, EM_SETSEL16, FALSE, MAKELONG( 0, -1 ) );
34     SetFocus( hwndCtrl );
35 }
36
37
38 /***********************************************************************
39  *           DEFDLG_SaveFocus
40  */
41 static BOOL DEFDLG_SaveFocus( HWND hwnd, DIALOGINFO *infoPtr )
42 {
43     HWND hwndFocus = GetFocus();
44
45     if (!hwndFocus || !IsChild( hwnd, hwndFocus )) return FALSE;
46     infoPtr->hwndFocus = hwndFocus;
47       /* Remove default button */
48     return TRUE;
49 }
50
51
52 /***********************************************************************
53  *           DEFDLG_RestoreFocus
54  */
55 static BOOL DEFDLG_RestoreFocus( HWND hwnd, DIALOGINFO *infoPtr )
56 {
57     if (!infoPtr->hwndFocus || IsIconic(hwnd)) return FALSE;
58     if (!IsWindow( infoPtr->hwndFocus )) return FALSE;
59
60     /* Don't set the focus back to controls if EndDialog is already called.*/
61     if (!(infoPtr->flags & DF_END))
62        DEFDLG_SetFocus( hwnd, infoPtr->hwndFocus );
63
64     /* This used to set infoPtr->hwndFocus to NULL for no apparent reason,
65        sometimes losing focus when receiving WM_SETFOCUS messages. */
66     return TRUE;
67 }
68
69
70 /***********************************************************************
71  *           DEFDLG_FindDefButton
72  *
73  * Find the current default push-button.
74  */
75 static HWND DEFDLG_FindDefButton( HWND hwndDlg )
76 {
77     HWND hwndChild = GetWindow( hwndDlg, GW_CHILD );
78     while (hwndChild)
79     {
80         if (SendMessage16( hwndChild, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON)
81             break;
82         hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
83     }
84     return hwndChild;
85 }
86
87
88 /***********************************************************************
89  *           DEFDLG_SetDefButton
90  *
91  * Set the new default button to be hwndNew.
92  */
93 static BOOL DEFDLG_SetDefButton( HWND hwndDlg, DIALOGINFO *dlgInfo,
94                                    HWND hwndNew )
95 {
96     if (hwndNew &&
97         !(SendMessage16(hwndNew, WM_GETDLGCODE, 0, 0 ) & DLGC_UNDEFPUSHBUTTON))
98         return FALSE;  /* Destination is not a push button */
99     
100     if (dlgInfo->idResult)  /* There's already a default pushbutton */
101     {
102         HWND hwndOld = GetDlgItem( hwndDlg, dlgInfo->idResult );
103         if (SendMessageA( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
104             SendMessageA( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
105     }
106     if (hwndNew)
107     {
108         SendMessageA( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
109         dlgInfo->idResult = GetDlgCtrlID( hwndNew );
110     }
111     else dlgInfo->idResult = 0;
112     return TRUE;
113 }
114
115
116 /***********************************************************************
117  *           DEFDLG_Proc
118  *
119  * Implementation of DefDlgProc(). Only handle messages that need special
120  * handling for dialogs.
121  */
122 static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
123                             LPARAM lParam, DIALOGINFO *dlgInfo )
124 {
125     switch(msg)
126     {
127         case WM_ERASEBKGND:
128             FillWindow16( hwnd, hwnd, (HDC16)wParam, (HBRUSH16)CTLCOLOR_DLG );
129             return 1;
130
131         case WM_NCDESTROY:
132
133               /* Free dialog heap (if created) */
134             if (dlgInfo->hDialogHeap)
135             {
136                 GlobalUnlock16(dlgInfo->hDialogHeap);
137                 GlobalFree16(dlgInfo->hDialogHeap);
138                 dlgInfo->hDialogHeap = 0;
139             }
140
141               /* Delete font */
142             if (dlgInfo->hUserFont)
143             {
144                 DeleteObject( dlgInfo->hUserFont );
145                 dlgInfo->hUserFont = 0;
146             }
147
148               /* Delete menu */
149             if (dlgInfo->hMenu)
150             {           
151                 DestroyMenu( dlgInfo->hMenu );
152                 dlgInfo->hMenu = 0;
153             }
154
155             /* Delete window procedure */
156             WINPROC_FreeProc( dlgInfo->dlgProc, WIN_PROC_WINDOW );
157             dlgInfo->dlgProc = (HWINDOWPROC)0;
158             dlgInfo->flags |= DF_END;  /* just in case */
159
160               /* Window clean-up */
161             return DefWindowProcA( hwnd, msg, wParam, lParam );
162
163         case WM_SHOWWINDOW:
164             if (!wParam) DEFDLG_SaveFocus( hwnd, dlgInfo );
165             return DefWindowProcA( hwnd, msg, wParam, lParam );
166
167         case WM_ACTIVATE:
168             if (wParam) DEFDLG_RestoreFocus( hwnd, dlgInfo );
169             else DEFDLG_SaveFocus( hwnd, dlgInfo );
170             return 0;
171
172         case WM_SETFOCUS:
173             DEFDLG_RestoreFocus( hwnd, dlgInfo );
174             return 0;
175
176         case DM_SETDEFID:
177             if (dlgInfo->flags & DF_END) return 1;
178             DEFDLG_SetDefButton( hwnd, dlgInfo,
179                                  wParam ? GetDlgItem( hwnd, wParam ) : 0 );
180             return 1;
181
182         case DM_GETDEFID:
183             {
184                 HWND hwndDefId;
185                 if (dlgInfo->flags & DF_END) return 0;
186                 if (dlgInfo->idResult)
187                     return MAKELONG( dlgInfo->idResult, DC_HASDEFID );
188                 if ((hwndDefId = DEFDLG_FindDefButton( hwnd )))
189                     return MAKELONG( GetDlgCtrlID( hwndDefId ), DC_HASDEFID);
190             }
191             return 0;
192
193         case WM_NEXTDLGCTL:
194             {
195                 HWND hwndDest = (HWND)wParam;
196                 if (!lParam)
197                     hwndDest = GetNextDlgTabItem(hwnd, GetFocus(), wParam);
198                 if (hwndDest) DEFDLG_SetFocus( hwnd, hwndDest );
199                 DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest );
200             }
201             return 0;
202
203         case WM_ENTERMENULOOP:
204         case WM_LBUTTONDOWN:
205         case WM_NCLBUTTONDOWN:
206             {
207                 HWND hwndFocus = GetFocus();
208                 if (hwndFocus)
209                 {
210                     WND *wnd = WIN_FindWndPtr( hwndFocus );
211
212                     if( wnd )
213                     {
214                         /* always make combo box hide its listbox control */
215
216                         if( WIDGETS_IsControl( wnd, BIC32_COMBO ) )
217                             SendMessageA( hwndFocus, CB_SHOWDROPDOWN,
218                                             FALSE, 0 );
219                         else if( WIDGETS_IsControl( wnd, BIC32_EDIT ) &&
220                                  WIDGETS_IsControl( wnd->parent,
221                                                       BIC32_COMBO ))
222                             SendMessageA( wnd->parent->hwndSelf, 
223                                             CB_SHOWDROPDOWN, FALSE, 0 );
224                     }
225                     WIN_ReleaseWndPtr(wnd);
226                 }
227             }
228             return DefWindowProcA( hwnd, msg, wParam, lParam );
229
230         case WM_GETFONT: 
231             return dlgInfo->hUserFont;
232
233         case WM_CLOSE:
234             PostMessageA( hwnd, WM_COMMAND, IDCANCEL,
235                             (LPARAM)GetDlgItem( hwnd, IDCANCEL ) );
236             return 0;
237     
238         case WM_NOTIFYFORMAT:
239             return DefWindowProcA( hwnd, msg, wParam, lParam );
240     }
241     return 0;
242 }
243
244 /***********************************************************************
245  *           DEFDLG_Epilog
246  */
247 static LRESULT DEFDLG_Epilog(DIALOGINFO* dlgInfo, UINT msg, BOOL fResult)
248 {
249     /* see SDK 3.1 */
250
251     if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
252          msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
253          msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
254          msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
255         return fResult; 
256
257     return dlgInfo->msgResult;
258 }
259
260 /***********************************************************************
261  *           DefDlgProc16   (USER.308)
262  */
263 LRESULT WINAPI DefDlgProc16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
264                              LPARAM lParam )
265 {
266     DIALOGINFO * dlgInfo;
267     BOOL result = FALSE;
268     WND * wndPtr = WIN_FindWndPtr( hwnd );
269     
270     if (!wndPtr) return 0;
271     dlgInfo = (DIALOGINFO *)&wndPtr->wExtra;
272     dlgInfo->msgResult = 0;
273
274     if (dlgInfo->dlgProc) {     /* Call dialog procedure */
275         result = CallWindowProc16( (WNDPROC16)dlgInfo->dlgProc,
276                                            hwnd, msg, wParam, lParam );
277         /* 16 bit dlg procs only return BOOL16 */
278         if( WINPROC_GetProcType( dlgInfo->dlgProc ) == WIN_PROC_16 )
279             result = LOWORD(result);
280     }
281
282     if (!result && IsWindow(hwnd))
283     {
284         /* callback didn't process this message */
285
286         switch(msg)
287         {
288             case WM_ERASEBKGND:
289             case WM_SHOWWINDOW:
290             case WM_ACTIVATE:
291             case WM_SETFOCUS:
292             case DM_SETDEFID:
293             case DM_GETDEFID:
294             case WM_NEXTDLGCTL:
295             case WM_GETFONT:
296             case WM_CLOSE:
297             case WM_NCDESTROY:
298             case WM_ENTERMENULOOP:
299             case WM_LBUTTONDOWN:
300             case WM_NCLBUTTONDOWN:
301                 WIN_ReleaseWndPtr(wndPtr);
302                 return DEFDLG_Proc( (HWND)hwnd, msg, 
303                                     (WPARAM)wParam, lParam, dlgInfo );
304             case WM_INITDIALOG:
305             case WM_VKEYTOITEM:
306             case WM_COMPAREITEM:
307             case WM_CHARTOITEM:
308                 break;
309
310             default:
311                 WIN_ReleaseWndPtr(wndPtr);
312                 return DefWindowProc16( hwnd, msg, wParam, lParam );
313         }
314     }   
315     WIN_ReleaseWndPtr(wndPtr);
316     return DEFDLG_Epilog(dlgInfo, msg, result);
317 }
318
319
320 /***********************************************************************
321  *           DefDlgProcA   (USER32.120)
322  */
323 LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg,
324                               WPARAM wParam, LPARAM lParam )
325 {
326     DIALOGINFO * dlgInfo;
327     BOOL result = FALSE;
328     WND * wndPtr = WIN_FindWndPtr( hwnd );
329     
330     if (!wndPtr) return 0;
331     dlgInfo = (DIALOGINFO *)&wndPtr->wExtra;
332     dlgInfo->msgResult = 0;
333
334     if (dlgInfo->dlgProc) {      /* Call dialog procedure */
335         result = CallWindowProcA( (WNDPROC)dlgInfo->dlgProc,
336                                             hwnd, msg, wParam, lParam );
337         /* 16 bit dlg procs only return BOOL16 */
338         if( WINPROC_GetProcType( dlgInfo->dlgProc ) == WIN_PROC_16 )
339             result = LOWORD(result);
340     }
341
342     if (!result && IsWindow(hwnd))
343     {
344         /* callback didn't process this message */
345
346         switch(msg)
347         {
348             case WM_ERASEBKGND:
349             case WM_SHOWWINDOW:
350             case WM_ACTIVATE:
351             case WM_SETFOCUS:
352             case DM_SETDEFID:
353             case DM_GETDEFID:
354             case WM_NEXTDLGCTL:
355             case WM_GETFONT:
356             case WM_CLOSE:
357             case WM_NCDESTROY:
358             case WM_ENTERMENULOOP:
359             case WM_LBUTTONDOWN:
360             case WM_NCLBUTTONDOWN:
361                  WIN_ReleaseWndPtr(wndPtr);
362                  return DEFDLG_Proc( (HWND)hwnd, msg,
363                                      (WPARAM)wParam, lParam, dlgInfo );
364             case WM_INITDIALOG:
365             case WM_VKEYTOITEM:
366             case WM_COMPAREITEM:
367             case WM_CHARTOITEM:
368                  break;
369
370             default:
371                  WIN_ReleaseWndPtr(wndPtr);
372                  return DefWindowProcA( hwnd, msg, wParam, lParam );
373         }
374     }
375     WIN_ReleaseWndPtr(wndPtr);
376     return DEFDLG_Epilog(dlgInfo, msg, result);
377 }
378
379
380 /***********************************************************************
381  *           DefDlgProcW   (USER32.121)
382  */
383 LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam,
384                               LPARAM lParam )
385 {
386     DIALOGINFO * dlgInfo;
387     BOOL result = FALSE;
388     WND * wndPtr = WIN_FindWndPtr( hwnd );
389     
390     if (!wndPtr) return 0;
391     dlgInfo = (DIALOGINFO *)&wndPtr->wExtra;
392     dlgInfo->msgResult = 0;
393
394     if (dlgInfo->dlgProc) {      /* Call dialog procedure */
395         result = CallWindowProcW( (WNDPROC)dlgInfo->dlgProc,
396                                             hwnd, msg, wParam, lParam );
397         /* 16 bit dlg procs only return BOOL16 */
398         if( WINPROC_GetProcType( dlgInfo->dlgProc ) == WIN_PROC_16 )
399             result = LOWORD(result);
400     }
401
402     if (!result && IsWindow(hwnd))
403     {
404         /* callback didn't process this message */
405
406         switch(msg)
407         {
408             case WM_ERASEBKGND:
409             case WM_SHOWWINDOW:
410             case WM_ACTIVATE:
411             case WM_SETFOCUS:
412             case DM_SETDEFID:
413             case DM_GETDEFID:
414             case WM_NEXTDLGCTL:
415             case WM_GETFONT:
416             case WM_CLOSE:
417             case WM_NCDESTROY:
418             case WM_ENTERMENULOOP:
419             case WM_LBUTTONDOWN:
420             case WM_NCLBUTTONDOWN:
421                  WIN_ReleaseWndPtr(wndPtr);
422                  return DEFDLG_Proc( (HWND)hwnd, msg,
423                                      (WPARAM)wParam, lParam, dlgInfo );
424             case WM_INITDIALOG:
425             case WM_VKEYTOITEM:
426             case WM_COMPAREITEM:
427             case WM_CHARTOITEM:
428                  break;
429
430             default:
431                  WIN_ReleaseWndPtr(wndPtr);
432                  return DefWindowProcW( hwnd, msg, wParam, lParam );
433         }
434     }
435     WIN_ReleaseWndPtr(wndPtr);
436     return DEFDLG_Epilog(dlgInfo, msg, result);
437 }