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