Release 970112
[wine] / windows / defdlg.c
1 /*
2  * Default dialog procedure
3  *
4  * Copyright 1993, 1996 Alexandre Julliard
5  *
6  */
7
8 #include "windows.h"
9 #include "dialog.h"
10 #include "win.h"
11 #include "winproc.h"
12
13
14 /***********************************************************************
15  *           DEFDLG_SetFocus
16  *
17  * Set the focus to a control of the dialog, selecting the text if
18  * the control is an edit dialog.
19  */
20 static void DEFDLG_SetFocus( HWND32 hwndDlg, HWND32 hwndCtrl )
21 {
22     HWND32 hwndPrev = GetFocus32();
23
24     if (IsChild( hwndDlg, hwndPrev ))
25     {
26         if (SendMessage16( hwndPrev, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
27             SendMessage16( hwndPrev, EM_SETSEL16, TRUE, MAKELONG( -1, 0 ) );
28     }
29     if (SendMessage16( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
30         SendMessage16( hwndCtrl, EM_SETSEL16, FALSE, MAKELONG( 0, -1 ) );
31     SetFocus32( hwndCtrl );
32 }
33
34
35 /***********************************************************************
36  *           DEFDLG_SaveFocus
37  */
38 static BOOL32 DEFDLG_SaveFocus( HWND32 hwnd, DIALOGINFO *infoPtr )
39 {
40     HWND32 hwndFocus = GetFocus32();
41
42     if (!hwndFocus || !IsChild( hwnd, hwndFocus )) return FALSE;
43     infoPtr->hwndFocus = hwndFocus;
44       /* Remove default button */
45     return TRUE;
46 }
47
48
49 /***********************************************************************
50  *           DEFDLG_RestoreFocus
51  */
52 static BOOL32 DEFDLG_RestoreFocus( HWND32 hwnd, DIALOGINFO *infoPtr )
53 {
54     if (!infoPtr->hwndFocus || IsIconic(hwnd)) return FALSE;
55     if (!IsWindow( infoPtr->hwndFocus )) return FALSE;
56     DEFDLG_SetFocus( hwnd, infoPtr->hwndFocus );
57     infoPtr->hwndFocus = 0;
58     return TRUE;
59 }
60
61
62 /***********************************************************************
63  *           DEFDLG_FindDefButton
64  *
65  * Find the current default push-button.
66  */
67 static HWND32 DEFDLG_FindDefButton( HWND32 hwndDlg )
68 {
69     HWND32 hwndChild = GetWindow( hwndDlg, GW_CHILD );
70     while (hwndChild)
71     {
72         if (SendMessage16( hwndChild, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON)
73             break;
74         hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
75     }
76     return hwndChild;
77 }
78
79
80 /***********************************************************************
81  *           DEFDLG_SetDefButton
82  *
83  * Set the new default button to be hwndNew.
84  */
85 static BOOL32 DEFDLG_SetDefButton( HWND32 hwndDlg, DIALOGINFO *dlgInfo,
86                                    HWND32 hwndNew )
87 {
88     if (hwndNew &&
89         !(SendMessage16(hwndNew, WM_GETDLGCODE, 0, 0 ) & DLGC_UNDEFPUSHBUTTON))
90         return FALSE;  /* Destination is not a push button */
91     
92     if (dlgInfo->idResult)  /* There's already a default pushbutton */
93     {
94         HWND32 hwndOld = GetDlgItem( hwndDlg, dlgInfo->idResult );
95         if (SendMessage32A( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
96             SendMessage32A( hwndOld, BM_SETSTYLE32, BS_PUSHBUTTON, TRUE );
97     }
98     if (hwndNew)
99     {
100         SendMessage32A( hwndNew, BM_SETSTYLE32, BS_DEFPUSHBUTTON, TRUE );
101         dlgInfo->idResult = GetDlgCtrlID( hwndNew );
102     }
103     else dlgInfo->idResult = 0;
104     return TRUE;
105 }
106
107
108 /***********************************************************************
109  *           DEFDLG_Proc
110  *
111  * Implementation of DefDlgProc(). Only handle messages that need special
112  * handling for dialogs.
113  */
114 static LRESULT DEFDLG_Proc( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
115                             LPARAM lParam, DIALOGINFO *dlgInfo )
116 {
117     HWND32 hwndDefId;
118
119     switch(msg)
120     {
121         case WM_ERASEBKGND:
122             FillWindow( hwnd, hwnd, (HDC16)wParam, (HBRUSH16)CTLCOLOR_DLG );
123             return 1;
124
125         case WM_NCDESTROY:
126
127               /* Free dialog heap (if created) */
128             if (dlgInfo->hDialogHeap)
129             {
130                 GlobalUnlock16(dlgInfo->hDialogHeap);
131                 GlobalFree16(dlgInfo->hDialogHeap);
132                 dlgInfo->hDialogHeap = 0;
133             }
134
135               /* Delete font */
136             if (dlgInfo->hUserFont)
137             {
138                 DeleteObject32( dlgInfo->hUserFont );
139                 dlgInfo->hUserFont = 0;
140             }
141
142               /* Delete menu */
143             if (dlgInfo->hMenu)
144             {           
145                 DestroyMenu32( dlgInfo->hMenu );
146                 dlgInfo->hMenu = 0;
147             }
148
149             /* Delete window procedure */
150             WINPROC_FreeProc( dlgInfo->dlgProc );
151             dlgInfo->dlgProc = (HWINDOWPROC)0;
152             dlgInfo->fEnd    = TRUE;    /* just in case */
153
154               /* Window clean-up */
155             return DefWindowProc32A( hwnd, msg, wParam, lParam );
156
157         case WM_SHOWWINDOW:
158             if (!wParam) DEFDLG_SaveFocus( hwnd, dlgInfo );
159             return DefWindowProc32A( hwnd, msg, wParam, lParam );
160
161         case WM_ACTIVATE:
162             if (wParam) DEFDLG_RestoreFocus( hwnd, dlgInfo );
163             else DEFDLG_SaveFocus( hwnd, dlgInfo );
164             return 0;
165
166         case WM_SETFOCUS:
167             DEFDLG_RestoreFocus( hwnd, dlgInfo );
168             return 0;
169
170         case DM_SETDEFID:
171             if (dlgInfo->fEnd) return 1;
172             DEFDLG_SetDefButton( hwnd, dlgInfo,
173                                  wParam ? GetDlgItem( hwnd, wParam ) : 0 );
174             return 1;
175
176         case DM_GETDEFID:
177             if (dlgInfo->fEnd) return 0;
178             if (dlgInfo->idResult)
179               return MAKELONG( dlgInfo->idResult, DC_HASDEFID );
180             hwndDefId = DEFDLG_FindDefButton( hwnd );
181             if (hwndDefId)
182               return MAKELONG( GetDlgCtrlID( hwndDefId ), DC_HASDEFID);
183             return 0;
184
185         case WM_NEXTDLGCTL:
186             {
187                 HWND32 hwndDest = (HWND32)wParam;
188                 if (!lParam)
189                     hwndDest = GetNextDlgTabItem32(hwnd, GetFocus32(), wParam);
190                 if (hwndDest) DEFDLG_SetFocus( hwnd, hwndDest );
191                 DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest );
192             }
193             return 0;
194
195         case WM_GETFONT: 
196             return dlgInfo->hUserFont;
197
198         case WM_CLOSE:
199             EndDialog( hwnd, TRUE );
200             DestroyWindow( hwnd );
201             return 0;
202     }
203     return 0;
204 }
205
206 /***********************************************************************
207  *           DEFDLG_Signoff
208  */
209 static LRESULT DEFDLG_Signoff(DIALOGINFO* dlgInfo, UINT32 msg, BOOL16 fResult)
210 {
211     /* see SDK 3.1 */
212
213     if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
214          msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
215          msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
216          msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
217         return fResult; 
218
219     return dlgInfo->msgResult;
220 }
221
222 /***********************************************************************
223  *           DefDlgProc16   (USER.308)
224  */
225 LRESULT DefDlgProc16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam )
226 {
227     DIALOGINFO * dlgInfo;
228     BOOL16 result = FALSE;
229     WND * wndPtr = WIN_FindWndPtr( hwnd );
230     
231     if (!wndPtr) return 0;
232     dlgInfo = (DIALOGINFO *)&wndPtr->wExtra;
233     dlgInfo->msgResult = 0;
234
235     if (dlgInfo->dlgProc)       /* Call dialog procedure */
236         result = (BOOL16)CallWindowProc16( (WNDPROC16)dlgInfo->dlgProc,
237                                            hwnd, msg, wParam, lParam );
238
239     /* Check if window was destroyed by dialog procedure */
240
241     if( !result && IsWindow(hwnd))
242     {
243         /* callback didn't process this message */
244
245         switch(msg)
246         {
247             case WM_ERASEBKGND:
248             case WM_SHOWWINDOW:
249             case WM_ACTIVATE:
250             case WM_SETFOCUS:
251             case DM_SETDEFID:
252             case DM_GETDEFID:
253             case WM_NEXTDLGCTL:
254             case WM_GETFONT:
255             case WM_CLOSE:
256             case WM_NCDESTROY:
257                 return DEFDLG_Proc( (HWND32)hwnd, msg, 
258                                     (WPARAM32)wParam, lParam, dlgInfo );
259             case WM_INITDIALOG:
260             case WM_VKEYTOITEM:
261             case WM_COMPAREITEM:
262             case WM_CHARTOITEM:
263                 break;
264
265             default:
266                 return DefWindowProc16( hwnd, msg, wParam, lParam );
267         }
268     }   
269     return DEFDLG_Signoff(dlgInfo, msg, result);
270 }
271
272
273 /***********************************************************************
274  *           DefDlgProc32A   (USER32.119)
275  */
276 LRESULT DefDlgProc32A( HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
277 {
278     DIALOGINFO * dlgInfo;
279     BOOL16 result = FALSE;
280     WND * wndPtr = WIN_FindWndPtr( hwnd );
281     
282     if (!wndPtr) return 0;
283     dlgInfo = (DIALOGINFO *)&wndPtr->wExtra;
284     dlgInfo->msgResult = 0;
285
286     if (dlgInfo->dlgProc)       /* Call dialog procedure */
287         result = (BOOL16)CallWindowProc32A( (WNDPROC32)dlgInfo->dlgProc,
288                                             hwnd, msg, wParam, lParam );
289
290     /* Check if window was destroyed by dialog procedure */
291
292     if( !result && IsWindow(hwnd))
293     {
294         /* callback didn't process this message */
295
296         switch(msg)
297         {
298             case WM_ERASEBKGND:
299             case WM_SHOWWINDOW:
300             case WM_ACTIVATE:
301             case WM_SETFOCUS:
302             case DM_SETDEFID:
303             case DM_GETDEFID:
304             case WM_NEXTDLGCTL:
305             case WM_GETFONT:
306             case WM_CLOSE:
307             case WM_NCDESTROY:
308                  return DEFDLG_Proc( (HWND32)hwnd, msg,
309                                      (WPARAM32)wParam, lParam, dlgInfo );
310             case WM_INITDIALOG:
311             case WM_VKEYTOITEM:
312             case WM_COMPAREITEM:
313             case WM_CHARTOITEM:
314                  break;
315
316             default:
317                  return DefWindowProc32A( hwnd, msg, wParam, lParam );
318         }
319     }
320     return DEFDLG_Signoff(dlgInfo, msg, result);
321 }
322
323
324 /***********************************************************************
325  *           DefDlgProc32W   (USER32.120)
326  */
327 LRESULT DefDlgProc32W( HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
328 {
329     DIALOGINFO * dlgInfo;
330     BOOL16 result = FALSE;
331     WND * wndPtr = WIN_FindWndPtr( hwnd );
332     
333     if (!wndPtr) return 0;
334     dlgInfo = (DIALOGINFO *)&wndPtr->wExtra;
335     dlgInfo->msgResult = 0;
336
337     if (dlgInfo->dlgProc)       /* Call dialog procedure */
338         result = (BOOL16)CallWindowProc32W( (WNDPROC32)dlgInfo->dlgProc,
339                                             hwnd, msg, wParam, lParam );
340
341     /* Check if window was destroyed by dialog procedure */
342
343     if( !result && IsWindow(hwnd))
344     {
345         /* callback didn't process this message */
346
347         switch(msg)
348         {
349             case WM_ERASEBKGND:
350             case WM_SHOWWINDOW:
351             case WM_ACTIVATE:
352             case WM_SETFOCUS:
353             case DM_SETDEFID:
354             case DM_GETDEFID:
355             case WM_NEXTDLGCTL:
356             case WM_GETFONT:
357             case WM_CLOSE:
358             case WM_NCDESTROY:
359                  return DEFDLG_Proc( (HWND32)hwnd, msg,
360                                      (WPARAM32)wParam, lParam, dlgInfo );
361             case WM_INITDIALOG:
362             case WM_VKEYTOITEM:
363             case WM_COMPAREITEM:
364             case WM_CHARTOITEM:
365                  break;
366
367             default:
368                  return DefWindowProc32W( hwnd, msg, wParam, lParam );
369         }
370     }
371     return DEFDLG_Signoff(dlgInfo, msg, result);
372 }