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