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

Last change on this file since 5725 was 5725, checked in by sandervl, 24 years ago

destroy menu window after it has been used (instead of just hiding it)

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