source: trunk/src/user32/win32dlg.cpp@ 8797

Last change on this file since 8797 was 8797, checked in by sandervl, 23 years ago

Removed focus fix from 2001-11-20; controls of child dialogs can receive input focus (CVP wizard dialogs)

File size: 37.0 KB
Line 
1/* $Id: win32dlg.cpp,v 1.77 2002-06-28 12:38:00 sandervl Exp $ */
2/*
3 * Win32 Dialog Code for OS/2
4 *
5 * Copyright 1999-2001 Sander van Leeuwen (sandervl@xs4all.nl) (Wine port & OS/2 adaption)
6 *
7 * Based on Wine code (990815; windows\dialog.c)
8 *
9 * Copyright 1993, 1994, 1996 Alexandre Julliard
10 *
11 * Project Odin Software License can be found in LICENSE.TXT
12 *
13 */
14#include <os2win.h>
15#include <windowsx.h>
16#include <stdlib.h>
17#include <string.h>
18#include <misc.h>
19#include <win32dlg.h>
20#include <win\winproc.h>
21#include "oslibmsg.h"
22#include "oslibwin.h"
23#include "win32wdesktop.h"
24#include "controls.h"
25#include "syscolor.h"
26#include "hook.h"
27#include <math.h>
28#include <unicode.h>
29
30#define DBG_LOCALLOG DBG_win32dlg
31#include "dbglocal.h"
32
33#define DEFAULT_DLGFONT "9.WarpSans"
34
35#define GET_SHORT(ptr) (*(SHORT *)(ptr))
36
37//******************************************************************************
38//******************************************************************************
39Win32Dialog::Win32Dialog(HINSTANCE hInst, LPCSTR dlgTemplate, HWND owner,
40 DLGPROC dlgProc, LPARAM param, BOOL isUnicode)
41 : Win32BaseWindow()
42{
43 RECT rect;
44 WORD style;
45 ATOM classAtom;
46
47 this->isUnicode = isUnicode;
48 hUserFont = 0;
49 hMenu = 0;
50 hwndFocus = 0;
51 Win32DlgProc = 0;
52 msgResult = 0;
53 userDlgData = 0;
54 idResult = 0;
55 dialogFlags = 0;
56 fDialogInit = FALSE;
57 memset(&dlgInfo, 0, sizeof(dlgInfo));
58
59 dprintf(("********* CREATE DIALOG ************"));
60 if(fInitialized == FALSE) {
61 if(DIALOG_Init() == FALSE) {
62 dprintf(("DIALOG_Init FAILED!"));
63 DebugInt3();
64 SetLastError(ERROR_GEN_FAILURE);
65 return;
66 }
67 fInitialized = TRUE;
68 }
69 xUnit = xBaseUnit;
70 yUnit = yBaseUnit;
71
72 /* Parse dialog template */
73 dlgTemplate = parseTemplate(dlgTemplate, &dlgInfo);
74
75 /* Load menu */
76 if (dlgInfo.menuName)
77 {
78 hMenu = LoadMenuW( hInst, (LPCWSTR)dlgInfo.menuName );
79 }
80
81 dprintf(("Dialog style %x", LOWORD(dlgInfo.style)));
82
83 /* Create custom font if needed */
84 if (dlgInfo.style & DS_SETFONT)
85 {
86 /* The font height must be negative as it is a point size */
87 /* and must be converted to pixels first */
88 /* (see CreateFont() documentation in the Windows SDK). */
89 int pixels;
90 if (((short)dlgInfo.pointSize) < 0)
91 pixels = -((short)dlgInfo.pointSize);
92 else
93 {
94 HDC hdc = GetDC(0);
95 pixels = dlgInfo.pointSize * GetDeviceCaps(hdc, LOGPIXELSY)/72;
96 ReleaseDC(0, hdc);
97 }
98
99 hUserFont = CreateFontW(-pixels, 0, 0, 0,
100 dlgInfo.weight, dlgInfo.italic, FALSE,
101 FALSE, DEFAULT_CHARSET, 0, 0, PROOF_QUALITY,
102 FF_DONTCARE, (LPCWSTR)dlgInfo.faceName );
103 if (hUserFont)
104 {
105 SIZE charSize;
106 getCharSize(hUserFont,&charSize);
107 xUnit = charSize.cx;
108 yUnit = charSize.cy;
109 }
110 }
111
112 //Set help id
113 setWindowContextHelpId(dlgInfo.helpId);
114
115 /* Create dialog main window */
116 rect.left = rect.top = 0;
117 rect.right = dlgInfo.cx * xUnit / 4;
118 rect.bottom = dlgInfo.cy * yUnit / 8;
119 if (dlgInfo.style & DS_MODALFRAME)
120 dlgInfo.exStyle |= WS_EX_DLGMODALFRAME;
121
122 AdjustWindowRectEx( &rect, dlgInfo.style, hMenu ? TRUE : FALSE , dlgInfo.exStyle );
123 rect.right -= rect.left;
124 rect.bottom -= rect.top;
125
126 if ((INT16)dlgInfo.x == CW_USEDEFAULT16)
127 {
128 rect.left = rect.top = CW_USEDEFAULT;
129 }
130 else
131 {
132 if (dlgInfo.style & DS_CENTER)
133 {
134 rect.left = (GetSystemMetrics(SM_CXSCREEN) - rect.right) / 2;
135 rect.top = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom) / 2;
136 }
137 else
138 {
139 rect.left += dlgInfo.x * xUnit / 4;
140 rect.top += dlgInfo.y * yUnit / 8;
141 }
142 if ( !(dlgInfo.style & WS_CHILD) )
143 {
144 INT dX, dY;
145
146 if( !(dlgInfo.style & DS_ABSALIGN) && owner)
147 ClientToScreen(owner, (POINT *)&rect );
148
149 /* try to fit it into the desktop */
150
151 if( (dX = rect.left + rect.right + GetSystemMetrics(SM_CXDLGFRAME)
152 - GetSystemMetrics(SM_CXSCREEN)) > 0 ) rect.left -= dX;
153 if( (dY = rect.top + rect.bottom + GetSystemMetrics(SM_CYDLGFRAME)
154 - GetSystemMetrics(SM_CYSCREEN)) > 0 ) rect.top -= dY;
155 if( rect.left < 0 ) rect.left = 0;
156 if( rect.top < 0 ) rect.top = 0;
157 }
158 }
159
160 /* Create the dialog window */
161
162 /* Find the class atom */
163 if (!HIWORD(dlgInfo.className))
164 {
165 classAtom = (ATOM)LOWORD(dlgInfo.className);
166 }
167 else
168 if (!(classAtom = GlobalFindAtomW((LPWSTR)dlgInfo.className)))
169 {
170 SetLastError(ERROR_INVALID_PARAMETER);
171 return;
172 }
173 CREATESTRUCTA cs;
174 cs.lpCreateParams = NULL;
175 cs.hInstance = hInst;
176 cs.hMenu = hMenu;
177 cs.hwndParent = owner;
178 cs.x = rect.left;
179 cs.y = rect.top;
180 cs.cx = rect.right;
181 cs.cy = rect.bottom;
182 cs.style = dlgInfo.style & ~WS_VISIBLE;
183
184 if(!isUnicode) {
185 if(dlgInfo.caption) {
186 cs.lpszName = UnicodeToAsciiString((LPWSTR)dlgInfo.caption);
187 }
188 else cs.lpszName = 0;
189 if(dlgInfo.className) {
190 cs.lpszClass = UnicodeToAsciiString((LPWSTR)dlgInfo.className);
191 }
192 else cs.lpszClass = 0;
193 }
194 else {
195 cs.lpszName = dlgInfo.caption;
196 cs.lpszClass = dlgInfo.className;
197 }
198 cs.dwExStyle = dlgInfo.exStyle;
199 if (dlgInfo.style & DS_CONTEXTHELP) cs.dwExStyle |= WS_EX_CONTEXTHELP;
200
201 //Mask away WS_CAPTION style for dialogs with DS_CONTROL style
202 //(necessary for OFN_ENABLETEMPLATE file open dialogs)
203 //(verified this behaviour in NT4, SP6)
204 if (dlgInfo.style & DS_CONTROL) cs.style &= ~(WS_CAPTION);
205
206 fIsDialog = TRUE;
207 WINPROC_SetProc((HWINDOWPROC *)&Win32DlgProc, (WNDPROC)dlgProc, (isUnicode) ? WIN_PROC_32W : WIN_PROC_32A, WIN_PROC_WINDOW);
208
209 this->tmpParam = param;
210 this->tmpDlgTemplate = (LPSTR)dlgTemplate;
211
212 if (CreateWindowExA(&cs, classAtom) == FALSE)
213 {
214 if (hUserFont) DeleteObject( hUserFont );
215 if (hMenu) DestroyMenu( hMenu );
216 SetLastError(ERROR_OUTOFMEMORY); //TODO: Wrong error
217 return;
218 }
219 SetLastError(0);
220 return;
221}
222//******************************************************************************
223//******************************************************************************
224Win32Dialog::~Win32Dialog()
225{
226 if (hUserFont) DeleteObject( hUserFont );
227 if (hMenu) DestroyMenu( hMenu );
228
229 WINPROC_FreeProc(Win32DlgProc, WIN_PROC_WINDOW);
230}
231//******************************************************************************
232//******************************************************************************
233ULONG Win32Dialog::MsgCreate(HWND hwndOS2)
234{
235 CREATESTRUCTA *cs = tmpcs; //pointer to CREATESTRUCT used in CreateWindowExA method
236 LPARAM param = tmpParam;
237 LPSTR dlgTemplate = tmpDlgTemplate;
238
239 if(Win32BaseWindow::MsgCreate(hwndOS2) == FALSE) {
240 dprintf(("********* DIALOG CREATION FAILED! (main dialog window) ************"));
241 return FALSE;
242 }
243
244 if(!isUnicode) {
245 if(cs->lpszName) FreeAsciiString((LPSTR)cs->lpszName);
246 if(HIWORD(cs->lpszClass)) {
247 FreeAsciiString((LPSTR)cs->lpszClass);
248 }
249 }
250
251 if (hUserFont)
252 SendMessageA(getWindowHandle(), WM_SETFONT, (WPARAM)hUserFont, 0 );
253
254 /* Create controls */
255 if (createControls(dlgTemplate, hInstance))
256 {
257 dprintf(("********* DIALOG CONTROLS CREATED ************"));
258 /* Send initialisation messages and set focus */
259 hwndFocus = GetNextDlgTabItem( getWindowHandle(), 0, FALSE );
260 dprintf(("dlg ctor: GetNextDlgTabItem returned %x, capture hwnd = %x", hwndFocus, GetCapture()));
261
262 fDialogInit = TRUE; //WM_NCCALCSIZE can now be sent to dialog procedure
263
264 HWND hwndPreInitFocus = GetFocus();
265 if(SendMessageA(getWindowHandle(), WM_INITDIALOG, (WPARAM)hwndFocus, param))
266 {
267 /* check where the focus is again,
268 * some controls status might have changed in WM_INITDIALOG */
269 hwndFocus = GetNextDlgTabItem( getWindowHandle(), 0, FALSE );
270 if(hwndFocus) {
271 SetFocus(hwndFocus);
272 }
273 }
274 else
275 {
276 /* If the dlgproc has returned FALSE (indicating handling of keyboard focus)
277 but the focus has not changed, set the focus where we expect it. */
278 if ( (getStyle() & WS_VISIBLE) && ( GetFocus() == hwndPreInitFocus ) )
279 {
280 hwndFocus = GetNextDlgTabItem( getWindowHandle(), 0, FALSE);
281 if( hwndFocus )
282 SetFocus( hwndFocus );
283 }
284 }
285
286 if (dlgInfo.style & WS_VISIBLE && !(getStyle() & WS_VISIBLE))
287 {
288 ShowWindow( SW_SHOWNORMAL ); /* SW_SHOW doesn't always work */
289////Note: this was removed in Wine
290//// UpdateWindow( getWindowHandle() );
291 }
292 SetLastError(ERROR_SUCCESS);
293 dprintf(("********* DIALOG CREATED ************"));
294 return TRUE;
295 }
296 dprintf(("********* DIALOG CREATION FAILED! ************"));
297 return FALSE;
298}
299//******************************************************************************
300//******************************************************************************
301BOOL Win32Dialog::MapDialogRect(LPRECT rect)
302{
303 rect->left = (rect->left * xUnit) / 4;
304 rect->right = (rect->right * xUnit) / 4;
305 rect->top = (rect->top * yUnit) / 8;
306 rect->bottom = (rect->bottom * yUnit) / 8;
307 return TRUE;
308}
309/***********************************************************************
310 * DIALOG_DoDialogBox
311 */
312INT Win32Dialog::doDialogBox()
313{
314 Win32BaseWindow *topOwner;
315 MSG msg;
316 INT retval;
317
318 dprintf(("doDialogBox %x", getWindowHandle()));
319 /* Owner must be a top-level window */
320 if(getOwner() == NULL) {
321 windowDesktop->addRef();
322 topOwner = windowDesktop;
323 }
324 else topOwner = GetWindowFromHandle(getOwner()->GetTopParent());
325
326 if(topOwner == NULL) {
327 dprintf(("Dialog box has no top owner!!!"));
328 return -1;
329 }
330
331 if (!dialogFlags & DF_END) /* was EndDialog called in WM_INITDIALOG ? */
332 {
333 HWND hwndOldDialog;
334 BOOL bOldOwner;
335
336 fIsModalDialog = TRUE;
337 topOwner->EnableWindow(FALSE);
338
339 bOldOwner = topOwner->IsModalDialogOwner();
340 topOwner->setModalDialogOwner(TRUE);
341 hwndOldDialog = topOwner->getOS2HwndModalDialog();
342 topOwner->setOS2HwndModalDialog(OS2HwndFrame);
343 ShowWindow(SW_SHOW);
344
345 //CB: 100% CPU usage, need a better solution with OSLibWinGetMsg
346 // is WM_ENTERIDLE used and leaving away breaks an application?
347 // this style was useful for Win3.1 but today there are threads
348 // solution: send only few WM_ENTERIDLE messages
349 while (TRUE)
350 {
351 if (!PeekMessageA(&msg,0,0,0,PM_NOREMOVE))
352 {
353 if(!(getStyle() & DS_NOIDLEMSG))
354 SendMessageA(topOwner->getWindowHandle(), WM_ENTERIDLE,MSGF_DIALOGBOX,getWindowHandle());
355 GetMessageA(&msg,0,0,0);
356 }
357 else PeekMessageA(&msg,0,0,0,PM_REMOVE);
358
359 /* Call message filters */
360 if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
361 {
362 LPMSG pmsg = (LPMSG)HeapAlloc( GetProcessHeap(), 0, sizeof(MSG) );
363 if (pmsg)
364 {
365 BOOL ret;
366 *pmsg = msg;
367 ret = (HOOK_CallHooksA( WH_SYSMSGFILTER, MSGF_DIALOGBOX, 0,
368 (LPARAM) pmsg ) ||
369 HOOK_CallHooksA( WH_MSGFILTER, MSGF_DIALOGBOX, 0,
370 (LPARAM) pmsg ));
371
372 HeapFree( GetProcessHeap(), 0, pmsg );
373 if (ret)
374 {
375 /* Message filtered -> remove it from the queue */
376 /* if it's still there. */
377 continue;
378 }
379 }
380 }
381
382 if(msg.message == WM_QUIT)
383 {
384 dprintf(("Win32Dialog::doDialogBox: received WM_QUIT"));
385 break;
386 }
387 if (!IsDialogMessageA( getWindowHandle(), &msg))
388 {
389 TranslateMessage( &msg );
390 DispatchMessageA( &msg );
391 }
392 if (dialogFlags & DF_END)
393 break;
394 }
395 topOwner->setModalDialogOwner(bOldOwner);
396 topOwner->setOS2HwndModalDialog(hwndOldDialog);
397 if (!bOldOwner) topOwner->EnableWindow(TRUE);
398 }
399 RELEASE_WNDOBJ(topOwner);
400 retval = idResult;
401 DestroyWindow();
402 return retval;
403}
404/***********************************************************************
405 * DIALOG_Init
406 *
407 * Initialisation of the dialog manager.
408 */
409BOOL Win32Dialog::DIALOG_Init(void)
410{
411 HDC hdc;
412 SIZE size;
413
414 /* Calculate the dialog base units */
415 if (!(hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL ))) return FALSE;
416 if (!getCharSizeFromDC( hdc, 0, &size )) return FALSE;
417 DeleteDC( hdc );
418 xBaseUnit = size.cx;
419 yBaseUnit = size.cy;
420
421 return TRUE;
422}
423/***********************************************************************
424 * DIALOG_GetCharSizeFromDC
425 *
426 *
427 * Calculates the *true* average size of English characters in the
428 * specified font as oppposed to the one returned by GetTextMetrics.
429 */
430BOOL Win32Dialog::getCharSizeFromDC( HDC hDC, HFONT hUserFont, SIZE * pSize )
431{
432 BOOL Success = FALSE;
433 HFONT hFontPrev = 0;
434 pSize->cx = xBaseUnit;
435 pSize->cy = yBaseUnit;
436
437 if ( hDC )
438 {
439 /* select the font */
440 TEXTMETRICA tm;
441 memset(&tm,0,sizeof(tm));
442 if (hUserFont) hFontPrev = SelectFont(hDC,hUserFont);
443 if (GetTextMetricsA(hDC,&tm))
444 {
445 pSize->cx = tm.tmAveCharWidth;
446 pSize->cy = tm.tmHeight;
447
448 /* if variable width font */
449 if (tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
450 {
451 SIZE total;
452 static const char szAvgChars[53] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
453
454 /* Calculate a true average as opposed to the one returned
455 * by tmAveCharWidth. This works better when dealing with
456 * proportional spaced fonts and (more important) that's
457 * how Microsoft's dialog creation code calculates the size
458 * of the font
459 */
460#ifdef __WIN32OS2__
461 if (GetTextExtentPointA(hDC,szAvgChars,sizeof(szAvgChars)-1,&total))
462 {
463 /* round up */
464 pSize->cx = ((2*total.cx/(sizeof(szAvgChars)-1)) + 1)/2;
465 Success = TRUE;
466 }
467#else
468 if (GetTextExtentPointA(hDC,szAvgChars,sizeof(szAvgChars),&total))
469 {
470 /* round up */
471 pSize->cx = ((2*total.cx/sizeof(szAvgChars)) + 1)/2;
472 Success = TRUE;
473 }
474#endif
475 }
476 else
477 {
478 Success = TRUE;
479 }
480 }
481
482 /* select the original font */
483 if (hFontPrev) SelectFont(hDC,hFontPrev);
484 }
485 return (Success);
486}
487/***********************************************************************
488 * DIALOG_GetCharSize
489 *
490 *
491 * Calculates the *true* average size of English characters in the
492 * specified font as oppposed to the one returned by GetTextMetrics.
493 * A convenient variant of DIALOG_GetCharSizeFromDC.
494 */
495BOOL Win32Dialog::getCharSize( HFONT hUserFont, SIZE * pSize )
496{
497 HDC hDC = CreateCompatibleDC(0);
498 BOOL Success = getCharSizeFromDC( hDC, hUserFont, pSize );
499 DeleteDC(hDC);
500 return Success;
501}
502/***********************************************************************
503 * DIALOG_ParseTemplate32
504 *
505 * Fill a DLG_TEMPLATE structure from the dialog template, and return
506 * a pointer to the first control.
507 */
508LPCSTR Win32Dialog::parseTemplate( LPCSTR dlgtemplate, DLG_TEMPLATE * result )
509{
510 const WORD *p = (const WORD *)dlgtemplate;
511
512 result->style = GET_DWORD(p); p += 2;
513 if (result->style == 0xffff0001) /* DIALOGEX resource */
514 {
515 result->dialogEx = TRUE;
516 result->helpId = GET_DWORD(p); p += 2;
517 result->exStyle = GET_DWORD(p); p += 2;
518 result->style = GET_DWORD(p); p += 2;
519 }
520 else
521 {
522 result->dialogEx = FALSE;
523 result->helpId = 0;
524 result->exStyle = GET_DWORD(p); p += 2;
525 }
526 result->nbItems = GET_WORD(p); p++;
527 //x & y are signed words
528 result->x = GET_SHORT(p); p++;
529 result->y = GET_SHORT(p); p++;
530 result->cx = GET_WORD(p); p++;
531 result->cy = GET_WORD(p); p++;
532
533 /* Get the menu name */
534
535 switch(GET_WORD(p))
536 {
537 case 0x0000:
538 result->menuName = NULL;
539 p++;
540 break;
541 case 0xffff:
542 result->menuName = (LPCSTR)(UINT)GET_WORD( p + 1 );
543 p += 2;
544 break;
545 default:
546 result->menuName = (LPCSTR)p;
547 p += lstrlenW( (LPCWSTR)p ) + 1;
548 break;
549 }
550
551 /* Get the class name */
552 switch(GET_WORD(p))
553 {
554 case 0x0000:
555 result->className = (LPCSTR)DIALOG_CLASS_NAMEW;
556 p++;
557 break;
558 case 0xffff:
559 result->className = (LPCSTR)(UINT)GET_WORD( p + 1 );
560 p += 2;
561 break;
562 default:
563 result->className = (LPCSTR)p;
564 p += lstrlenW( (LPCWSTR)p ) + 1;
565 break;
566 }
567
568 /* Get the window caption */
569
570 result->caption = (LPCSTR)p;
571 p += lstrlenW( (LPCWSTR)p ) + 1;
572
573 /* Get the font name */
574
575 if (result->style & DS_SETFONT)
576 {
577 result->pointSize = GET_WORD(p);
578 p++;
579 if (result->dialogEx)
580 {
581 result->weight = GET_WORD(p); p++;
582 result->italic = LOBYTE(GET_WORD(p)); p++;
583 }
584 else
585 {
586 result->weight = FW_DONTCARE;
587 result->italic = FALSE;
588 }
589 result->faceName = (LPCSTR)p;
590 p += lstrlenW( (LPCWSTR)p ) + 1;
591 }
592
593 /* First control is on dword boundary */
594 return (LPCSTR)((((int)p) + 3) & ~3);
595}
596/***********************************************************************
597 * DIALOG_GetControl32
598 *
599 * Return the class and text of the control pointed to by ptr,
600 * fill the header structure and return a pointer to the next control.
601 */
602WORD *Win32Dialog::getControl(const WORD *p, DLG_CONTROL_INFO *info, BOOL dialogEx)
603{
604 if (dialogEx)
605 {
606 info->helpId = GET_DWORD(p); p += 2;
607 info->exStyle = GET_DWORD(p); p += 2;
608 info->style = GET_DWORD(p); p += 2;
609 }
610 else
611 {
612 info->helpId = 0;
613 info->style = GET_DWORD(p); p += 2;
614 info->exStyle = GET_DWORD(p); p += 2;
615 }
616 //SvL: x & y are signed words!
617 info->x = GET_SHORT(p); p++;
618 info->y = GET_SHORT(p); p++;
619 info->cx = GET_WORD(p); p++;
620 info->cy = GET_WORD(p); p++;
621
622 if (dialogEx)
623 {
624 /* id is a DWORD for DIALOGEX */
625 info->id = GET_DWORD(p);
626 p += 2;
627 }
628 else
629 {
630 info->id = GET_WORD(p);
631 p++;
632 }
633
634 if (GET_WORD(p) == 0xffff)
635 {
636 static const WCHAR class_names[6][10] =
637 {
638 { 'B','u','t','t','o','n', }, /* 0x80 */
639 { 'E','d','i','t', }, /* 0x81 */
640 { 'S','t','a','t','i','c', }, /* 0x82 */
641 { 'L','i','s','t','B','o','x', }, /* 0x83 */
642 { 'S','c','r','o','l','l','B','a','r', }, /* 0x84 */
643 { 'C','o','m','b','o','B','o','x', } /* 0x85 */
644 };
645 WORD id = GET_WORD(p+1);
646 if ((id >= 0x80) && (id <= 0x85))
647 info->className = (LPCSTR)class_names[id - 0x80];
648 else
649 {
650 info->className = NULL;
651 dprintf(("Unknown built-in class id %04x\n", id ));
652 }
653 p += 2;
654 }
655 else
656 {
657 info->className = (LPCSTR)p;
658 p += lstrlenW( (LPCWSTR)p ) + 1;
659 }
660
661 if (GET_WORD(p) == 0xffff) /* Is it an integer id? */
662 {
663 info->windowName = (LPCSTR)(UINT)GET_WORD(p + 1);
664 //Wine add 3 (bytes) here. But that causes problems with certain
665 //InstallShield installers.
666 p += 2;
667 }
668 else
669 {
670 info->windowName = (LPCSTR)p;
671 p += lstrlenW( (LPCWSTR)p ) + 1;
672 }
673
674 if (GET_WORD(p))
675 {
676 info->data = (LPVOID)(p + 1);
677 p += GET_WORD(p) / sizeof(WORD);
678 }
679 else info->data = NULL;
680 p++;
681
682 /* Next control is on dword boundary */
683 return (WORD *)((((int)p) + 3) & ~3);
684}
685
686
687/***********************************************************************
688 * DIALOG_CreateControls
689 *
690 * Create the control windows for a dialog.
691 */
692BOOL Win32Dialog::createControls(LPCSTR dlgtemplate, HINSTANCE hInst)
693{
694 DLG_CONTROL_INFO info;
695 HWND hwndCtrl, hwndDefButton = 0;
696 INT items = dlgInfo.nbItems;
697
698 while (items--)
699 {
700 dlgtemplate = (LPCSTR)getControl( (WORD *)dlgtemplate, &info, dlgInfo.dialogEx );
701
702 dprintf(("Create CONTROL %d", info.id));
703
704 hwndCtrl = ::CreateWindowExW( info.exStyle | WS_EX_NOPARENTNOTIFY,
705 (LPWSTR)info.className,
706 (LPWSTR)info.windowName,
707 info.style | WS_CHILD,
708 MulDiv(info.x, xUnit, 4),
709 MulDiv(info.y, yUnit, 8),
710 MulDiv(info.cx, xUnit, 4),
711 MulDiv(info.cy, yUnit, 8),
712 getWindowHandle(), (HMENU)info.id,
713 hInst, info.data );
714
715 if (!hwndCtrl) return FALSE;
716
717 /* Send initialisation messages to the control */
718 if (hUserFont) ::SendMessageA( hwndCtrl, WM_SETFONT, (WPARAM)hUserFont, 0 );
719
720 if (::SendMessageA(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
721 {
722 /* If there's already a default push-button, set it back */
723 /* to normal and use this one instead. */
724 if (hwndDefButton)
725 ::SendMessageA( hwndDefButton, BM_SETSTYLE,
726 BS_PUSHBUTTON,FALSE );
727 hwndDefButton = hwndCtrl;
728 idResult = ::GetWindowWord( hwndCtrl, GWW_ID );
729 }
730 dprintf(("Create CONTROL %d DONE", info.id));
731 }
732 return TRUE;
733}
734/***********************************************************************
735 * DEFDLG_Proc
736 *
737 * Implementation of DefDlgProc(). Only handle messages that need special
738 * handling for dialogs.
739 */
740LRESULT Win32Dialog::DefDlg_Proc(UINT msg, WPARAM wParam, LPARAM lParam)
741{
742 switch(msg)
743 {
744 case WM_ERASEBKGND:
745 {
746 RECT rect;
747 int rc;
748
749 if (!windowClass) return 0;
750
751 rc = GetClipBox( (HDC)wParam, &rect );
752 if ((rc == SIMPLEREGION) || (rc == COMPLEXREGION))
753 {
754 HBRUSH hBrush = SendMessageA(getWindowHandle(), WM_CTLCOLORDLG, wParam, getWindowHandle());
755 if(GetObjectType(hBrush) != OBJ_BRUSH) {
756 DefWndControlColor(CTLCOLOR_DLG, (HDC)wParam);
757 }
758 FillRect( (HDC)wParam, &rect, hBrush);
759 }
760
761 return 1;
762 }
763
764 case WM_NCDESTROY:
765 /* Free dialog heap (if created) */
766#if 0
767 if (dlgInfo->hDialogHeap)
768 {
769 GlobalUnlock16(dlgInfo->hDialogHeap);
770 GlobalFree16(dlgInfo->hDialogHeap);
771 dlgInfo->hDialogHeap = 0;
772 }
773#endif
774 /* Delete font */
775 if (hUserFont)
776 {
777 DeleteObject( hUserFont );
778 hUserFont = 0;
779 }
780
781 /* Delete menu */
782 if (hMenu)
783 {
784 DestroyMenu( hMenu );
785 hMenu = 0;
786 }
787
788 /* Delete window procedure */
789 Win32DlgProc = 0;
790 dialogFlags |= DF_END; /* just in case */
791
792 /* Window clean-up */
793 return DefWindowProcA(msg, wParam, lParam );
794
795 case WM_SHOWWINDOW:
796 if (!wParam) saveFocus();
797 return DefWindowProcA(msg, wParam, lParam );
798
799 case WM_ACTIVATE:
800 if (wParam) {
801 restoreFocus();
802 }
803 else saveFocus();
804 return 0;
805
806 case WM_SETFOCUS:
807 restoreFocus();
808 return 0;
809
810 case DM_SETDEFID:
811 if (dialogFlags & DF_END)
812 return 1;
813
814 setDefButton(wParam ? GetDlgItem( getWindowHandle(), wParam ) : 0 );
815 return 1;
816
817 case DM_GETDEFID:
818 {
819 HWND hwndDefId;
820 if (dialogFlags & DF_END) return 0;
821 if (idResult)
822 return MAKELONG( idResult, DC_HASDEFID );
823 if ((hwndDefId = findDefButton()) != 0)
824 return MAKELONG( GetDlgCtrlID( hwndDefId ), DC_HASDEFID);
825
826 return 0;
827 }
828
829 case WM_NEXTDLGCTL:
830 {
831 HWND hwndDest = (HWND)wParam;
832 if (!lParam)
833 hwndDest = GetNextDlgTabItem(getWindowHandle(), GetFocus(), wParam);
834 if (hwndDest) setFocus( hwndDest );
835 setDefButton( hwndDest );
836 return 0;
837 }
838
839 case WM_ENTERMENULOOP:
840 case WM_LBUTTONDOWN:
841 case WM_NCLBUTTONDOWN:
842 {
843 HWND hwndCurFocus = GetFocus();
844 if (hwndCurFocus)
845 {
846 Win32BaseWindow *wndFocus = Win32BaseWindow::GetWindowFromHandle(hwndFocus);
847
848 if(wndFocus)
849 {
850 /* always make combo box hide its listbox control */
851 if( CONTROLS_IsControl( wndFocus, COMBOBOX_CONTROL ) )
852 SendMessageA(wndFocus->getWindowHandle(), CB_SHOWDROPDOWN, FALSE, 0 );
853 else
854 if( CONTROLS_IsControl( wndFocus, EDIT_CONTROL ) &&
855 CONTROLS_IsControl( wndFocus->getParent(), COMBOBOX_CONTROL ))
856 SendMessageA(wndFocus->getWindowHandle(), CB_SHOWDROPDOWN, FALSE, 0 );
857 RELEASE_WNDOBJ(wndFocus);
858 }
859 }
860 return DefWindowProcA( msg, wParam, lParam );
861 }
862
863 case WM_GETFONT:
864 return hUserFont;
865
866 case WM_CLOSE:
867 PostMessageA(getWindowHandle(), WM_COMMAND, IDCANCEL, (LPARAM)GetDlgItem( getWindowHandle(), IDCANCEL ) );
868 return 0;
869
870 case WM_NOTIFYFORMAT:
871 return DefWindowProcA(msg, wParam, lParam );
872 }
873 return 0;
874}
875//******************************************************************************
876//******************************************************************************
877LRESULT Win32Dialog::DefDlgProcA(UINT Msg, WPARAM wParam, LPARAM lParam)
878{
879 BOOL result = FALSE;
880
881 msgResult = 0;
882
883 //Dialogs never receive these messages
884 if (Msg == WM_CREATE || Msg == WM_NCCREATE) {
885 return (LRESULT)1;
886 }
887 //Never send a WM_NCCALCSIZE to a dialog before it has received it's WM_INITDIALOG message
888 //(causes problems for sysinf32.exe)
889 if(!fDialogInit && Msg == WM_NCCALCSIZE) {
890 return DefWindowProcA(Msg, wParam, lParam );
891 }
892
893 if (Win32DlgProc) { /* Call dialog procedure */
894 result = Win32DlgProc(getWindowHandle(), Msg, wParam, lParam);
895 }
896
897 if (!result && IsWindow())
898 {
899 /* callback didn't process this message */
900 switch(Msg)
901 {
902 case WM_ERASEBKGND:
903 case WM_SHOWWINDOW:
904 case WM_ACTIVATE:
905 case WM_SETFOCUS:
906 case DM_SETDEFID:
907 case DM_GETDEFID:
908 case WM_NEXTDLGCTL:
909 case WM_GETFONT:
910 case WM_CLOSE:
911 case WM_NCDESTROY:
912 case WM_ENTERMENULOOP:
913 case WM_LBUTTONDOWN:
914 case WM_NCLBUTTONDOWN:
915 return DefDlg_Proc(Msg, (WPARAM)wParam, lParam);
916
917 case WM_INITDIALOG:
918 case WM_VKEYTOITEM:
919 case WM_COMPAREITEM:
920 case WM_CHARTOITEM:
921 break;
922
923 default:
924 return DefWindowProcA(Msg, wParam, lParam );
925 }
926 }
927 return DefDlg_Epilog(Msg, result);
928}
929//******************************************************************************
930//******************************************************************************
931LRESULT Win32Dialog::DefDlgProcW(UINT Msg, WPARAM wParam, LPARAM lParam)
932{
933 BOOL result = FALSE;
934
935 msgResult = 0;
936
937 //Dialogs never receive these messages
938 if (Msg == WM_CREATE || Msg == WM_NCCREATE) {
939 return (LRESULT)1;
940 }
941 //Never send a WM_NCCALCSIZE to a dialog before it has received it's WM_INITDIALOG message
942 //(causes problems for sysinf32.exe)
943 if(!fDialogInit && Msg == WM_NCCALCSIZE) {
944 return DefWindowProcW(Msg, wParam, lParam );
945 }
946
947 if (Win32DlgProc) { /* Call dialog procedure */
948 result = Win32DlgProc(getWindowHandle(), Msg, wParam, lParam);
949 }
950
951 if (!result && IsWindow())
952 {
953 /* callback didn't process this message */
954 switch(Msg)
955 {
956 case WM_ERASEBKGND:
957 case WM_SHOWWINDOW:
958 case WM_ACTIVATE:
959 case WM_SETFOCUS:
960 case DM_SETDEFID:
961 case DM_GETDEFID:
962 case WM_NEXTDLGCTL:
963 case WM_GETFONT:
964 case WM_CLOSE:
965 case WM_NCDESTROY:
966 case WM_ENTERMENULOOP:
967 case WM_LBUTTONDOWN:
968 case WM_NCLBUTTONDOWN:
969 return DefDlg_Proc(Msg, (WPARAM)wParam, lParam);
970
971 case WM_INITDIALOG:
972 case WM_VKEYTOITEM:
973 case WM_COMPAREITEM:
974 case WM_CHARTOITEM:
975 break;
976
977 default:
978 return DefWindowProcW(Msg, wParam, lParam );
979 }
980 }
981 return DefDlg_Epilog(Msg, result);
982}
983/***********************************************************************
984 * DEFDLG_Epilog
985 */
986LRESULT Win32Dialog::DefDlg_Epilog(UINT msg, BOOL fResult)
987{
988 /* see SDK 3.1 */
989 if ((msg >= WM_CTLCOLORMSGBOX && msg <= WM_CTLCOLORSTATIC) ||
990 msg == WM_CTLCOLOR || msg == WM_COMPAREITEM ||
991 msg == WM_VKEYTOITEM || msg == WM_CHARTOITEM ||
992 msg == WM_QUERYDRAGICON || msg == WM_INITDIALOG)
993 return fResult;
994
995 return msgResult;
996}
997/***********************************************************************
998 * DEFDLG_SetFocus
999 *
1000 * Set the focus to a control of the dialog, selecting the text if
1001 * the control is an edit dialog.
1002 */
1003void Win32Dialog::setFocus(HWND hwndCtrl )
1004{
1005 HWND hwndPrev = GetFocus();
1006
1007 if (IsChild( hwndPrev ))
1008 {
1009 if (::SendMessageA( hwndPrev, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
1010 ::SendMessageA( hwndPrev, EM_SETSEL, TRUE, MAKELONG( -1, 0 ) );
1011 }
1012 if (::SendMessageA(hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
1013 ::SendMessageA(hwndCtrl, EM_SETSEL, FALSE, MAKELONG( 0, -1 ) );
1014 SetFocus( hwndCtrl );
1015}
1016
1017
1018/***********************************************************************
1019 * DEFDLG_SaveFocus
1020 */
1021BOOL Win32Dialog::saveFocus()
1022{
1023 HWND hwndCurrentFocus = GetFocus();
1024
1025 if (!hwndCurrentFocus || !IsChild( hwndCurrentFocus )) return FALSE;
1026
1027 hwndFocus = hwndCurrentFocus;
1028 /* Remove default button */
1029 return TRUE;
1030}
1031
1032
1033/***********************************************************************
1034 * DEFDLG_RestoreFocus
1035 */
1036BOOL Win32Dialog::restoreFocus()
1037{
1038 if (!hwndFocus || IsWindowIconic()) return FALSE;
1039
1040 if (!::IsWindow( hwndFocus )) return FALSE;
1041
1042 /* Don't set the focus back to controls if EndDialog is already called.*/
1043 if (!(dialogFlags & DF_END))
1044 setFocus(hwndFocus);
1045
1046 /* This used to set infoPtr->hwndFocus to NULL for no apparent reason,
1047 sometimes losing focus when receiving WM_SETFOCUS messages. */
1048 return TRUE;
1049}
1050
1051
1052/***********************************************************************
1053 * DEFDLG_FindDefButton
1054 *
1055 * Find the current default push-button.
1056 */
1057HWND Win32Dialog::findDefButton()
1058{
1059 HWND hwndChild = GetWindow( GW_CHILD );
1060 while (hwndChild)
1061 {
1062 if (::SendMessageA( hwndChild, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON)
1063 break;
1064 hwndChild = ::GetWindow( hwndChild, GW_HWNDNEXT );
1065 }
1066 return hwndChild;
1067}
1068
1069
1070/***********************************************************************
1071 * DEFDLG_SetDefButton
1072 *
1073 * Set the new default button to be hwndNew.
1074 */
1075BOOL Win32Dialog::setDefButton(HWND hwndNew )
1076{
1077 if (hwndNew &&
1078 !(::SendMessageA(hwndNew, WM_GETDLGCODE, 0, 0 ) & DLGC_UNDEFPUSHBUTTON))
1079 return FALSE; /* Destination is not a push button */
1080
1081 if (idResult) /* There's already a default pushbutton */
1082 {
1083 HWND hwndOld = GetDlgItem( getWindowHandle(), idResult );
1084 if (::SendMessageA( hwndOld, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
1085 ::SendMessageA( hwndOld, BM_SETSTYLE, BS_PUSHBUTTON, TRUE );
1086 }
1087 if (hwndNew)
1088 {
1089 ::SendMessageA( hwndNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE );
1090 idResult = GetDlgCtrlID( hwndNew );
1091 }
1092 else idResult = 0;
1093 return TRUE;
1094}
1095//******************************************************************************
1096//******************************************************************************
1097BOOL Win32Dialog::endDialog(int retval)
1098{
1099 HWND hwnd = getWindowHandle();
1100
1101 dialogFlags |= DF_END;
1102 idResult = retval;
1103
1104// BOOL wasEnabled = (dlgInfo.flags & DF_OWNERENABLED);
1105
1106// if (wasEnabled && (owner = GetWindow( hwnd, GW_OWNER )))
1107// DIALOG_EnableOwner( owner );
1108
1109 /* Windows sets the focus to the dialog itself in EndDialog */
1110
1111 if (::IsChild(hwnd, GetFocus()))
1112 ::SetFocus( hwnd );
1113
1114 /* Don't have to send a ShowWindow(SW_HIDE), just do
1115 SetWindowPos with SWP_HIDEWINDOW as done in Windows */
1116
1117 ::SetWindowPos(hwnd, (HWND)0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE
1118 | SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW);
1119
1120 /* unblock dialog loop */
1121 PostMessageA(hwnd, WM_NULL, 0, 0);
1122 return TRUE;
1123}
1124//******************************************************************************
1125//******************************************************************************
1126LONG Win32Dialog::SetWindowLong(int index, ULONG value, BOOL fUnicode)
1127{
1128 LONG oldval;
1129
1130 dprintf2(("Win32Dialog::SetWindowLongA %x %d %x", getWindowHandle(), index, value));
1131 switch(index)
1132 {
1133 case DWL_DLGPROC:
1134 {
1135 //Note: Type of SetWindowLong determines new window proc type
1136 // UNLESS the new window proc has already been registered
1137 // (use the old type in that case)
1138 // (VERIFIED in NT 4, SP6)
1139 WINDOWPROCTYPE type = WINPROC_GetProcType((HWINDOWPROC)value);
1140 if(type == WIN_PROC_INVALID) {
1141 type = (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A;
1142 }
1143 oldval = (LONG)WINPROC_GetProc(Win32DlgProc, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A);
1144 WINPROC_SetProc((HWINDOWPROC *)&Win32DlgProc, (WNDPROC)value, type, WIN_PROC_WINDOW);
1145 return oldval;
1146 }
1147 case DWL_MSGRESULT:
1148 oldval = msgResult;
1149 msgResult = value;
1150 return oldval;
1151 case DWL_USER:
1152 oldval = userDlgData;
1153 userDlgData = value;
1154 return oldval;
1155 default:
1156 return Win32BaseWindow::SetWindowLong(index, value, fUnicode);
1157 }
1158}
1159//******************************************************************************
1160//******************************************************************************
1161ULONG Win32Dialog::GetWindowLong(int index, BOOL fUnicode)
1162{
1163 dprintf2(("Win32Dialog::GetWindowLongA %x %d", getWindowHandle(), index));
1164 switch(index)
1165 {
1166 case DWL_DLGPROC:
1167 return (ULONG)WINPROC_GetProc(Win32DlgProc, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A);
1168 case DWL_MSGRESULT:
1169 return msgResult;
1170 case DWL_USER:
1171 return userDlgData;
1172 default:
1173 return Win32BaseWindow::GetWindowLong(index, fUnicode);
1174 }
1175}
1176//******************************************************************************
1177//******************************************************************************
1178BOOL DIALOG_Register()
1179{
1180 WNDCLASSA wndClass;
1181
1182 ZeroMemory(&wndClass,sizeof(WNDCLASSA));
1183 wndClass.style = CS_GLOBALCLASS | CS_SAVEBITS;
1184 wndClass.lpfnWndProc = (WNDPROC)DefDlgProcA;
1185 wndClass.cbClsExtra = 0;
1186 wndClass.cbWndExtra = 0;
1187 wndClass.hCursor = LoadCursorA(0,IDC_ARROWA);
1188 wndClass.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
1189 wndClass.lpszClassName = DIALOG_CLASS_NAMEA;
1190
1191 return RegisterClassA(&wndClass);
1192}
1193//******************************************************************************
1194//******************************************************************************
1195BOOL DIALOG_Unregister()
1196{
1197 if (GlobalFindAtomA(DIALOG_CLASS_NAMEA))
1198 return UnregisterClassA(DIALOG_CLASS_NAMEA,(HINSTANCE)NULL);
1199 else return FALSE;
1200}
1201//******************************************************************************
1202//******************************************************************************
1203BOOL Win32Dialog::fInitialized = FALSE;
1204int Win32Dialog::xBaseUnit = 10;
1205int Win32Dialog::yBaseUnit = 20;
Note: See TracBrowser for help on using the repository browser.