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