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