Implemented the mmTask* functions.
[wine.git] / windows / defdlg.c
blobdef5b8af7b892bde6503cf19c2caafb1cfa00ac0
1 /*
2 * Default dialog procedure
4 * Copyright 1993, 1996 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "wine/winuser16.h"
27 #include "controls.h"
28 #include "win.h"
29 #include "winproc.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dialog);
35 /***********************************************************************
36 * DEFDLG_GetDlgProc
38 static WNDPROC DEFDLG_GetDlgProc( HWND hwnd )
40 WNDPROC ret;
41 WND *wndPtr = WIN_GetPtr( hwnd );
43 if (!wndPtr) return 0;
44 if (wndPtr == WND_OTHER_PROCESS)
46 ERR( "cannot get dlg proc %p from other process\n", hwnd );
47 return 0;
49 ret = *(WNDPROC *)((char *)wndPtr->wExtra + DWL_DLGPROC);
50 WIN_ReleasePtr( wndPtr );
51 return ret;
54 /***********************************************************************
55 * DEFDLG_SetFocus
57 * Set the focus to a control of the dialog, selecting the text if
58 * the control is an edit dialog.
60 static void DEFDLG_SetFocus( HWND hwndDlg, HWND hwndCtrl )
62 HWND hwndPrev = GetFocus();
64 if (IsChild( hwndDlg, hwndPrev ))
66 if (SendMessageW( hwndPrev, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
67 SendMessageW( hwndPrev, EM_SETSEL, -1, 0 );
69 if (SendMessageW( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
70 SendMessageW( hwndCtrl, EM_SETSEL, 0, -1 );
71 SetFocus( hwndCtrl );
75 /***********************************************************************
76 * DEFDLG_SaveFocus
78 static void DEFDLG_SaveFocus( HWND hwnd )
80 DIALOGINFO *infoPtr;
81 HWND hwndFocus = GetFocus();
83 if (!hwndFocus || !IsChild( hwnd, hwndFocus )) return;
84 if (!(infoPtr = DIALOG_get_info( hwnd, FALSE ))) return;
85 infoPtr->hwndFocus = hwndFocus;
86 /* Remove default button */
90 /***********************************************************************
91 * DEFDLG_RestoreFocus
93 static void DEFDLG_RestoreFocus( HWND hwnd )
95 DIALOGINFO *infoPtr;
97 if (IsIconic( hwnd )) return;
98 if (!(infoPtr = DIALOG_get_info( hwnd, FALSE ))) return;
99 if (!IsWindow( infoPtr->hwndFocus )) return;
100 /* Don't set the focus back to controls if EndDialog is already called.*/
101 if (!(infoPtr->flags & DF_END))
103 DEFDLG_SetFocus( hwnd, infoPtr->hwndFocus );
104 return;
106 /* This used to set infoPtr->hwndFocus to NULL for no apparent reason,
107 sometimes losing focus when receiving WM_SETFOCUS messages. */
111 /***********************************************************************
112 * DEFDLG_FindDefButton
114 * Find the current default push-button.
116 static HWND DEFDLG_FindDefButton( HWND hwndDlg )
118 HWND hwndChild = GetWindow( hwndDlg, GW_CHILD );
119 while (hwndChild)
121 if (SendMessageW( hwndChild, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON)
122 break;
123 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
125 return hwndChild;
129 /***********************************************************************
130 * DEFDLG_SetDefId
132 * Set the default button id.
134 static BOOL DEFDLG_SetDefId( HWND hwndDlg, DIALOGINFO *dlgInfo, WPARAM wParam)
136 DWORD dlgcode=0; /* initialize just to avoid a warning */
137 HWND hwndOld, hwndNew = GetDlgItem(hwndDlg, wParam);
138 INT old_id = dlgInfo->idResult;
140 dlgInfo->idResult = wParam;
141 if (hwndNew &&
142 !((dlgcode=SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 ))
143 & (DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON)))
144 return FALSE; /* Destination is not a push button */
146 /* Make sure the old default control is a valid push button ID */
147 hwndOld = GetDlgItem( hwndDlg, old_id );
148 if (!hwndOld || !(SendMessageA( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON))
149 hwndOld = DEFDLG_FindDefButton( hwndDlg );
150 if (hwndOld && hwndOld != hwndNew)
151 SendMessageA( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
153 if (hwndNew)
155 if(dlgcode & DLGC_UNDEFPUSHBUTTON)
156 SendMessageA( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
158 return TRUE;
162 /***********************************************************************
163 * DEFDLG_SetDefButton
165 * Set the new default button to be hwndNew.
167 static BOOL DEFDLG_SetDefButton( HWND hwndDlg, DIALOGINFO *dlgInfo, HWND hwndNew )
169 DWORD dlgcode=0; /* initialize just to avoid a warning */
170 HWND hwndOld = GetDlgItem( hwndDlg, dlgInfo->idResult );
172 if (hwndNew &&
173 !((dlgcode=SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 ))
174 & (DLGC_UNDEFPUSHBUTTON | DLGC_DEFPUSHBUTTON)))
177 * Need to draw only default push button rectangle.
178 * Since the next control is not a push button, need to draw the push
179 * button rectangle for the default control.
181 hwndNew = hwndOld;
182 dlgcode = SendMessageW(hwndNew, WM_GETDLGCODE, 0, 0 );
185 /* Make sure the old default control is a valid push button ID */
186 if (!hwndOld || !(SendMessageA( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON))
187 hwndOld = DEFDLG_FindDefButton( hwndDlg );
188 if (hwndOld && hwndOld != hwndNew)
189 SendMessageA( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
191 if (hwndNew)
193 if(dlgcode & DLGC_UNDEFPUSHBUTTON)
194 SendMessageA( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
196 return TRUE;
200 /***********************************************************************
201 * DEFDLG_Proc
203 * Implementation of DefDlgProc(). Only handle messages that need special
204 * handling for dialogs.
206 static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
207 LPARAM lParam, DIALOGINFO *dlgInfo )
209 switch(msg)
211 case WM_ERASEBKGND:
213 HBRUSH brush = (HBRUSH)SendMessageW( hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd );
214 if (!brush) brush = (HBRUSH)DefWindowProcW( hwnd, WM_CTLCOLORDLG, wParam, (LPARAM)hwnd );
215 if (brush)
217 RECT rect;
218 HDC hdc = (HDC)wParam;
219 GetClientRect( hwnd, &rect );
220 DPtoLP( hdc, (LPPOINT)&rect, 2 );
221 FillRect( hdc, &rect, brush );
223 return 1;
225 case WM_NCDESTROY:
226 if ((dlgInfo = (DIALOGINFO *)SetWindowLongW( hwnd, DWL_WINE_DIALOGINFO, 0 )))
228 /* Free dialog heap (if created) */
229 if (dlgInfo->hDialogHeap)
231 GlobalUnlock16(dlgInfo->hDialogHeap);
232 GlobalFree16(dlgInfo->hDialogHeap);
234 if (dlgInfo->hUserFont) DeleteObject( dlgInfo->hUserFont );
235 if (dlgInfo->hMenu) DestroyMenu( dlgInfo->hMenu );
236 WINPROC_FreeProc( DEFDLG_GetDlgProc( hwnd ), WIN_PROC_WINDOW );
237 HeapFree( GetProcessHeap(), 0, dlgInfo );
239 /* Window clean-up */
240 return DefWindowProcA( hwnd, msg, wParam, lParam );
242 case WM_SHOWWINDOW:
243 if (!wParam) DEFDLG_SaveFocus( hwnd );
244 return DefWindowProcA( hwnd, msg, wParam, lParam );
246 case WM_ACTIVATE:
247 if (wParam) DEFDLG_RestoreFocus( hwnd );
248 else DEFDLG_SaveFocus( hwnd );
249 return 0;
251 case WM_SETFOCUS:
252 DEFDLG_RestoreFocus( hwnd );
253 return 0;
255 case DM_SETDEFID:
256 if (dlgInfo && !(dlgInfo->flags & DF_END))
257 DEFDLG_SetDefId( hwnd, dlgInfo, wParam );
258 return 1;
260 case DM_GETDEFID:
261 if (dlgInfo && !(dlgInfo->flags & DF_END))
263 HWND hwndDefId;
264 if (dlgInfo->idResult)
265 return MAKELONG( dlgInfo->idResult, DC_HASDEFID );
266 if ((hwndDefId = DEFDLG_FindDefButton( hwnd )))
267 return MAKELONG( GetDlgCtrlID( hwndDefId ), DC_HASDEFID);
269 return 0;
271 case WM_NEXTDLGCTL:
272 if (dlgInfo)
274 HWND hwndDest = (HWND)wParam;
275 if (!lParam)
276 hwndDest = GetNextDlgTabItem(hwnd, GetFocus(), wParam);
277 if (hwndDest) DEFDLG_SetFocus( hwnd, hwndDest );
278 DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest );
280 return 0;
282 case WM_ENTERMENULOOP:
283 case WM_LBUTTONDOWN:
284 case WM_NCLBUTTONDOWN:
286 HWND hwndFocus = GetFocus();
287 if (hwndFocus)
289 /* always make combo box hide its listbox control */
290 if (!SendMessageA( hwndFocus, CB_SHOWDROPDOWN, FALSE, 0 ))
291 SendMessageA( GetParent(hwndFocus), CB_SHOWDROPDOWN, FALSE, 0 );
294 return DefWindowProcA( hwnd, msg, wParam, lParam );
296 case WM_GETFONT:
297 return dlgInfo ? (LRESULT)dlgInfo->hUserFont : 0;
299 case WM_CLOSE:
300 PostMessageA( hwnd, WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED),
301 (LPARAM)GetDlgItem( hwnd, IDCANCEL ) );
302 return 0;
304 case WM_NOTIFYFORMAT:
305 return DefWindowProcA( hwnd, msg, wParam, lParam );
307 return 0;
310 /***********************************************************************
311 * DEFDLG_Epilog
313 static LRESULT DEFDLG_Epilog(HWND hwnd, UINT msg, BOOL fResult)
315 /* see SDK 3.1 */
317 if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
318 msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
319 msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
320 msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
321 return fResult;
323 return GetWindowLongA( hwnd, DWL_MSGRESULT );
326 /***********************************************************************
327 * DIALOG_get_info
329 * Get the DIALOGINFO structure of a window, allocating it if needed
330 * and 'create' is TRUE.
332 DIALOGINFO *DIALOG_get_info( HWND hwnd, BOOL create )
334 WND* wndPtr;
335 DIALOGINFO* dlgInfo = (DIALOGINFO *)GetWindowLongW( hwnd, DWL_WINE_DIALOGINFO );
337 if(!dlgInfo && create)
339 if (!(dlgInfo = HeapAlloc( GetProcessHeap(), 0, sizeof(*dlgInfo) ))) return NULL;
340 dlgInfo->hwndFocus = 0;
341 dlgInfo->hUserFont = 0;
342 dlgInfo->hMenu = 0;
343 dlgInfo->xBaseUnit = 0;
344 dlgInfo->yBaseUnit = 0;
345 dlgInfo->idResult = 0;
346 dlgInfo->flags = 0;
347 dlgInfo->hDialogHeap = 0;
348 wndPtr = WIN_GetPtr( hwnd );
349 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
351 wndPtr->flags |= WIN_ISDIALOG;
352 WIN_ReleasePtr( wndPtr );
353 SetWindowLongW( hwnd, DWL_WINE_DIALOGINFO, (LONG)dlgInfo );
355 else
357 HeapFree( GetProcessHeap(), 0, dlgInfo );
358 return NULL;
361 return dlgInfo;
364 /***********************************************************************
365 * DefDlgProc (USER.308)
367 LRESULT WINAPI DefDlgProc16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
368 LPARAM lParam )
370 DIALOGINFO *dlgInfo;
371 WNDPROC16 dlgproc;
372 HWND hwnd32 = WIN_Handle32( hwnd );
373 BOOL result = FALSE;
375 /* Perform DIALOGINFO intialization if not done */
376 if(!(dlgInfo = DIALOG_get_info(hwnd32, TRUE))) return -1;
378 SetWindowLongW( hwnd32, DWL_MSGRESULT, 0 );
380 if ((dlgproc = (WNDPROC16)DEFDLG_GetDlgProc( hwnd32 )))
382 /* Call dialog procedure */
383 result = CallWindowProc16( dlgproc, hwnd, msg, wParam, lParam );
384 /* 16 bit dlg procs only return BOOL16 */
385 if( WINPROC_GetProcType( (WNDPROC)dlgproc ) == WIN_PROC_16 )
386 result = LOWORD(result);
389 if (!result && IsWindow(hwnd32))
391 /* callback didn't process this message */
393 switch(msg)
395 case WM_ERASEBKGND:
396 case WM_SHOWWINDOW:
397 case WM_ACTIVATE:
398 case WM_SETFOCUS:
399 case DM_SETDEFID:
400 case DM_GETDEFID:
401 case WM_NEXTDLGCTL:
402 case WM_GETFONT:
403 case WM_CLOSE:
404 case WM_NCDESTROY:
405 case WM_ENTERMENULOOP:
406 case WM_LBUTTONDOWN:
407 case WM_NCLBUTTONDOWN:
408 return DEFDLG_Proc( hwnd32, msg, (WPARAM)wParam, lParam, dlgInfo );
409 case WM_INITDIALOG:
410 case WM_VKEYTOITEM:
411 case WM_COMPAREITEM:
412 case WM_CHARTOITEM:
413 break;
415 default:
416 return DefWindowProc16( hwnd, msg, wParam, lParam );
419 return DEFDLG_Epilog( hwnd32, msg, result);
423 /***********************************************************************
424 * DefDlgProcA (USER32.@)
426 LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
428 DIALOGINFO *dlgInfo;
429 WNDPROC dlgproc;
430 BOOL result = FALSE;
432 /* Perform DIALOGINFO initialization if not done */
433 if(!(dlgInfo = DIALOG_get_info( hwnd, TRUE ))) return -1;
435 SetWindowLongW( hwnd, DWL_MSGRESULT, 0 );
437 if ((dlgproc = DEFDLG_GetDlgProc( hwnd )))
439 /* Call dialog procedure */
440 result = CallWindowProcA( dlgproc, hwnd, msg, wParam, lParam );
441 /* 16 bit dlg procs only return BOOL16 */
442 if( WINPROC_GetProcType( dlgproc ) == WIN_PROC_16 )
443 result = LOWORD(result);
446 if (!result && IsWindow(hwnd))
448 /* callback didn't process this message */
450 switch(msg)
452 case WM_ERASEBKGND:
453 case WM_SHOWWINDOW:
454 case WM_ACTIVATE:
455 case WM_SETFOCUS:
456 case DM_SETDEFID:
457 case DM_GETDEFID:
458 case WM_NEXTDLGCTL:
459 case WM_GETFONT:
460 case WM_CLOSE:
461 case WM_NCDESTROY:
462 case WM_ENTERMENULOOP:
463 case WM_LBUTTONDOWN:
464 case WM_NCLBUTTONDOWN:
465 return DEFDLG_Proc( hwnd, msg, wParam, lParam, dlgInfo );
466 case WM_INITDIALOG:
467 case WM_VKEYTOITEM:
468 case WM_COMPAREITEM:
469 case WM_CHARTOITEM:
470 break;
472 default:
473 return DefWindowProcA( hwnd, msg, wParam, lParam );
476 return DEFDLG_Epilog(hwnd, msg, result);
480 /***********************************************************************
481 * DefDlgProcW (USER32.@)
483 LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
485 DIALOGINFO *dlgInfo;
486 BOOL result = FALSE;
487 WNDPROC dlgproc;
489 /* Perform DIALOGINFO intialization if not done */
490 if(!(dlgInfo = DIALOG_get_info( hwnd, TRUE ))) return -1;
492 SetWindowLongW( hwnd, DWL_MSGRESULT, 0 );
494 if ((dlgproc = DEFDLG_GetDlgProc( hwnd )))
496 /* Call dialog procedure */
497 result = CallWindowProcW( dlgproc, hwnd, msg, wParam, lParam );
498 /* 16 bit dlg procs only return BOOL16 */
499 if( WINPROC_GetProcType( dlgproc ) == WIN_PROC_16 )
500 result = LOWORD(result);
503 if (!result && IsWindow(hwnd))
505 /* callback didn't process this message */
507 switch(msg)
509 case WM_ERASEBKGND:
510 case WM_SHOWWINDOW:
511 case WM_ACTIVATE:
512 case WM_SETFOCUS:
513 case DM_SETDEFID:
514 case DM_GETDEFID:
515 case WM_NEXTDLGCTL:
516 case WM_GETFONT:
517 case WM_CLOSE:
518 case WM_NCDESTROY:
519 case WM_ENTERMENULOOP:
520 case WM_LBUTTONDOWN:
521 case WM_NCLBUTTONDOWN:
522 return DEFDLG_Proc( hwnd, msg, wParam, lParam, dlgInfo );
523 case WM_INITDIALOG:
524 case WM_VKEYTOITEM:
525 case WM_COMPAREITEM:
526 case WM_CHARTOITEM:
527 break;
529 default:
530 return DefWindowProcW( hwnd, msg, wParam, lParam );
533 return DEFDLG_Epilog(hwnd, msg, result);