]> git.saurik.com Git - wxWidgets.git/blame - src/msw/toplevel.cpp
don't crash when trying to dump struct members which are NULL pointers
[wxWidgets.git] / src / msw / toplevel.cpp
CommitLineData
82c9f85c
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: msw/toplevel.cpp
3// Purpose: implements wxTopLevelWindow for MSW
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 24.09.01
7// RCS-ID: $Id$
8// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
65571936 9// License: wxWindows licence
82c9f85c
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
82c9f85c
VZ
21 #pragma implementation "toplevel.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#ifndef WX_PRECOMP
3a922bb4
RL
32 #include "wx/app.h"
33 #include "wx/toplevel.h"
28b68852 34 #include "wx/dialog.h"
82c9f85c
VZ
35 #include "wx/string.h"
36 #include "wx/log.h"
37 #include "wx/intl.h"
14dd645e 38 #include "wx/frame.h"
706d74ab 39 #include "wx/containr.h" // wxSetFocusToChild()
82c9f85c
VZ
40#endif //WX_PRECOMP
41
2b5f62a0 42#include "wx/module.h"
dc92adaf 43#include "wx/dynlib.h"
2b5f62a0 44
82c9f85c 45#include "wx/msw/private.h"
3d487566 46#if defined(__WXWINCE__) && !defined(__HANDHELDPC__)
80a81a12
JS
47 #include <ole2.h>
48 #include <shellapi.h>
3874e500 49 // Standard SDK doesn't have aygshell.dll: see include/wx/msw/wince/libraries.h
a9928e9d 50 #if _WIN32_WCE < 400 || !defined(__WINCE_STANDARDSDK__)
2d36b3d8
JS
51 #include <aygshell.h>
52 #endif
53#include "wx/msw/wince/missing.h"
80a81a12
JS
54#endif
55
d61c1a6f 56#include "wx/msw/missing.h"
4676948b
JS
57#include "wx/msw/winundef.h"
58
716645d3 59#include "wx/display.h"
7e25f59e 60
e121a72a
MB
61#ifndef ICON_BIG
62 #define ICON_BIG 1
63#endif
64
65#ifndef ICON_SMALL
66 #define ICON_SMALL 0
67#endif
68
82c9f85c
VZ
69// ----------------------------------------------------------------------------
70// stubs for missing functions under MicroWindows
71// ----------------------------------------------------------------------------
72
73#ifdef __WXMICROWIN__
74
bfbb0b4c
WS
75// static inline bool IsIconic(HWND WXUNUSED(hwnd)) { return false; }
76static inline bool IsZoomed(HWND WXUNUSED(hwnd)) { return false; }
82c9f85c
VZ
77
78#endif // __WXMICROWIN__
79
12447831
VZ
80// NB: wxDlgProc must be defined here and not in dialog.cpp because the latter
81// is not included by wxUniv build which does need wxDlgProc
61179e28
VZ
82LONG APIENTRY _EXPORT
83wxDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
84
82c9f85c
VZ
85// ----------------------------------------------------------------------------
86// globals
87// ----------------------------------------------------------------------------
88
77ffb593 89// the name of the default wxWidgets class
46fa338b
RR
90#ifdef __WXWINCE__
91extern wxChar *wxCanvasClassName;
92#else
b225f659 93extern const wxChar *wxCanvasClassName;
46fa338b 94#endif
b225f659 95
2b5f62a0
VZ
96// ----------------------------------------------------------------------------
97// wxTLWHiddenParentModule: used to manage the hidden parent window (we need a
98// module to ensure that the window is always deleted)
99// ----------------------------------------------------------------------------
100
101class wxTLWHiddenParentModule : public wxModule
102{
103public:
104 // module init/finalize
105 virtual bool OnInit();
106 virtual void OnExit();
107
108 // get the hidden window (creates on demand)
109 static HWND GetHWND();
110
111private:
112 // the HWND of the hidden parent
113 static HWND ms_hwnd;
114
115 // the class used to create it
116 static const wxChar *ms_className;
117
118 DECLARE_DYNAMIC_CLASS(wxTLWHiddenParentModule)
119};
120
121IMPLEMENT_DYNAMIC_CLASS(wxTLWHiddenParentModule, wxModule)
9dfef5ac 122
82c9f85c
VZ
123// ============================================================================
124// wxTopLevelWindowMSW implementation
125// ============================================================================
126
085ad686
VZ
127BEGIN_EVENT_TABLE(wxTopLevelWindowMSW, wxTopLevelWindowBase)
128 EVT_ACTIVATE(wxTopLevelWindowMSW::OnActivate)
129END_EVENT_TABLE()
130
82c9f85c
VZ
131// ----------------------------------------------------------------------------
132// wxTopLevelWindowMSW creation
133// ----------------------------------------------------------------------------
134
135void wxTopLevelWindowMSW::Init()
136{
137 m_iconized =
bfbb0b4c 138 m_maximizeOnShow = false;
b225f659 139
c641b1d2
VS
140 // Data to save/restore when calling ShowFullScreen
141 m_fsStyle = 0;
142 m_fsOldWindowStyle = 0;
bfbb0b4c
WS
143 m_fsIsMaximized = false;
144 m_fsIsShowing = false;
085ad686
VZ
145
146 m_winLastFocused = (wxWindow *)NULL;
fb8a56b7 147
3180bc0e 148#if defined(__SMARTPHONE__) && defined(__WXWINCE__)
fb8a56b7
WS
149 m_MenuBarHWND = 0;
150#endif
b225f659
VZ
151}
152
b2d5a7ee 153WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const
b225f659 154{
b2d5a7ee
VZ
155 // let the base class deal with the common styles but fix the ones which
156 // don't make sense for us (we also deal with the borders ourselves)
157 WXDWORD msflags = wxWindow::MSWGetStyle
158 (
159 (style & ~wxBORDER_MASK) | wxBORDER_NONE, exflags
31e7e89f 160 ) & ~WS_CHILD & ~WS_VISIBLE;
b225f659 161
aa29eefa
JS
162 // For some reason, WS_VISIBLE needs to be defined on creation for
163 // SmartPhone 2003. The title can fail to be displayed otherwise.
164#if defined(__SMARTPHONE__) || (defined(__WXWINCE__) && _WIN32_WCE < 400)
c1855476 165 msflags |= WS_VISIBLE;
aa29eefa 166 ((wxTopLevelWindowMSW*)this)->wxWindowBase::Show(true);
c1855476
RR
167#endif
168
b225f659 169 // first select the kind of window being created
dfb06c62
VZ
170 //
171 // note that if we don't set WS_POPUP, Windows assumes WS_OVERLAPPED and
0fcd3b92
VZ
172 // creates a window with both caption and border, hence we need to use
173 // WS_POPUP in a few cases just to avoid having caption/border which we
174 // don't want
0e082993 175
3180bc0e 176#if !(defined(__SMARTPHONE__) && defined(__WXWINCE__))
0e082993
VZ
177 // border and caption styles
178 if ( style & wxRESIZE_BORDER )
179 msflags |= WS_THICKFRAME;
f8d56830
JS
180 else if ( exflags && ((style & wxBORDER_DOUBLE) || (style & wxBORDER_RAISED)) )
181 *exflags |= WS_EX_DLGMODALFRAME;
0e082993
VZ
182 else if ( !(style & wxBORDER_NONE) )
183 msflags |= WS_BORDER;
dfb06c62
VZ
184 else
185 msflags |= WS_POPUP;
82eda5ec 186#endif
0e082993 187
9ceeecb9 188 // normally we consider that all windows without a caption must be popups,
f76858d8
VZ
189 // but CE is an exception: there windows normally do not have the caption
190 // but shouldn't be made popups as popups can't have menus and don't look
191 // like normal windows anyhow
9ceeecb9
JS
192
193 // TODO: Smartphone appears to like wxCAPTION, but we should check that
194 // we need it.
195#if defined(__SMARTPHONE__) || !defined(__WXWINCE__)
0e082993
VZ
196 if ( style & wxCAPTION )
197 msflags |= WS_CAPTION;
f76858d8 198#ifndef __WXWINCE__
dfb06c62 199 else
b225f659 200 msflags |= WS_POPUP;
f76858d8 201#endif // !__WXWINCE__
9ceeecb9 202#endif
e5aa8b81 203
b225f659
VZ
204 // next translate the individual flags
205 if ( style & wxMINIMIZE_BOX )
206 msflags |= WS_MINIMIZEBOX;
207 if ( style & wxMAXIMIZE_BOX )
208 msflags |= WS_MAXIMIZEBOX;
9ceeecb9
JS
209
210#ifndef __WXWINCE__
b225f659
VZ
211 if ( style & wxSYSTEM_MENU )
212 msflags |= WS_SYSMENU;
9ceeecb9 213#endif
2a47cb1b 214
f76858d8
VZ
215 // NB: under CE these 2 styles are not supported currently, we should
216 // call Minimize()/Maximize() "manually" if we want to support them
b225f659
VZ
217 if ( style & wxMINIMIZE )
218 msflags |= WS_MINIMIZE;
9ceeecb9
JS
219
220#if !defined(__POCKETPC__)
b225f659
VZ
221 if ( style & wxMAXIMIZE )
222 msflags |= WS_MAXIMIZE;
9ceeecb9 223#endif
0e082993 224
b225f659 225 // Keep this here because it saves recoding this function in wxTinyFrame
b225f659
VZ
226 if ( style & (wxTINY_CAPTION_VERT | wxTINY_CAPTION_HORIZ) )
227 msflags |= WS_CAPTION;
82eda5ec 228
b225f659
VZ
229 if ( exflags )
230 {
f76858d8 231 // there is no taskbar under CE, so omit all this
45f27284 232#if !defined(__WXWINCE__)
35bf863b
VZ
233 if ( !(GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) )
234 {
9dfef5ac
VZ
235 if ( style & wxFRAME_TOOL_WINDOW )
236 {
237 // create the palette-like window
35bf863b 238 *exflags |= WS_EX_TOOLWINDOW;
404a4d93
VZ
239
240 // tool windows shouldn't appear on the taskbar (as documented)
241 style |= wxFRAME_NO_TASKBAR;
9dfef5ac
VZ
242 }
243
244 // We have to solve 2 different problems here:
245 //
246 // 1. frames with wxFRAME_NO_TASKBAR flag shouldn't appear in the
247 // taskbar even if they don't have a parent
248 //
249 // 2. frames without this style should appear in the taskbar even
250 // if they're owned (Windows only puts non owned windows into
251 // the taskbar normally)
252 //
253 // The second one is solved here by using WS_EX_APPWINDOW flag, the
254 // first one is dealt with in our MSWGetParent() method
255 // implementation
256 if ( !(style & wxFRAME_NO_TASKBAR) && GetParent() )
257 {
258 // need to force the frame to appear in the taskbar
35bf863b 259 *exflags |= WS_EX_APPWINDOW;
9dfef5ac
VZ
260 }
261 //else: nothing to do [here]
35bf863b 262 }
b554cf63
JS
263
264 if ( GetExtraStyle() & wxFRAME_EX_CONTEXTHELP )
265 *exflags |= WS_EX_CONTEXTHELP;
f76858d8 266#endif // !__WXWINCE__
b225f659
VZ
267
268 if ( style & wxSTAY_ON_TOP )
269 *exflags |= WS_EX_TOPMOST;
b225f659
VZ
270 }
271
272 return msflags;
273}
274
9dfef5ac
VZ
275WXHWND wxTopLevelWindowMSW::MSWGetParent() const
276{
277 // for the frames without wxFRAME_FLOAT_ON_PARENT style we should use NULL
278 // parent HWND or it would be always on top of its parent which is not what
279 // we usually want (in fact, we only want it for frames with the
280 // wxFRAME_FLOAT_ON_PARENT flag)
2b5f62a0 281 HWND hwndParent = NULL;
9dfef5ac
VZ
282 if ( HasFlag(wxFRAME_FLOAT_ON_PARENT) )
283 {
2b5f62a0 284 const wxWindow *parent = GetParent();
9dfef5ac 285
2b5f62a0
VZ
286 if ( !parent )
287 {
288 // this flag doesn't make sense then and will be ignored
289 wxFAIL_MSG( _T("wxFRAME_FLOAT_ON_PARENT but no parent?") );
290 }
291 else
292 {
293 hwndParent = GetHwndOf(parent);
294 }
9dfef5ac 295 }
2b5f62a0 296 //else: don't float on parent, must not be owned
9dfef5ac
VZ
297
298 // now deal with the 2nd taskbar-related problem (see comments above in
299 // MSWGetStyle())
2b5f62a0 300 if ( HasFlag(wxFRAME_NO_TASKBAR) && !hwndParent )
9dfef5ac 301 {
2b5f62a0
VZ
302 // use hidden parent
303 hwndParent = wxTLWHiddenParentModule::GetHWND();
9dfef5ac
VZ
304 }
305
2b5f62a0 306 return (WXHWND)hwndParent;
9dfef5ac
VZ
307}
308
6e8515a3 309bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate,
b225f659
VZ
310 const wxString& title,
311 const wxPoint& pos,
312 const wxSize& size)
313{
314#ifdef __WXMICROWIN__
315 // no dialogs support under MicroWin yet
316 return CreateFrame(title, pos, size);
317#else // !__WXMICROWIN__
318 wxWindow *parent = GetParent();
319
320 // for the dialogs without wxDIALOG_NO_PARENT style, use the top level
321 // app window as parent - this avoids creating modal dialogs without
322 // parent
323 if ( !parent && !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT) )
324 {
325 parent = wxTheApp->GetTopWindow();
e058b98d 326
39cc7a0b 327 if ( parent )
e058b98d 328 {
39cc7a0b
VZ
329 // don't use transient windows as parents, this is dangerous as it
330 // can lead to a crash if the parent is destroyed before the child
331 //
332 // also don't use the window which is currently hidden as then the
333 // dialog would be hidden as well
334 if ( (parent->GetExtraStyle() & wxWS_EX_TRANSIENT) ||
335 !parent->IsShown() )
336 {
337 parent = NULL;
338 }
e058b98d 339 }
b225f659
VZ
340 }
341
434005ca
VZ
342 m_hWnd = (WXHWND)::CreateDialogIndirect
343 (
344 wxGetInstance(),
345 (DLGTEMPLATE*)dlgTemplate,
346 parent ? GetHwndOf(parent) : NULL,
347 (DLGPROC)wxDlgProc
348 );
b225f659
VZ
349
350 if ( !m_hWnd )
351 {
7e99eddf 352 wxFAIL_MSG(wxT("Failed to create dialog. Incorrect DLGTEMPLATE?"));
b225f659 353
7e99eddf 354 wxLogSysError(wxT("Can't create dialog using memory template"));
b225f659 355
bfbb0b4c 356 return false;
b225f659
VZ
357 }
358
b2d5a7ee 359 WXDWORD exflags;
b225f659
VZ
360 (void)MSWGetCreateWindowFlags(&exflags);
361
362 if ( exflags )
363 {
364 ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exflags);
cef338d3
VZ
365 ::SetWindowPos(GetHwnd(),
366 exflags & WS_EX_TOPMOST ? HWND_TOPMOST : 0,
367 0, 0, 0, 0,
b225f659
VZ
368 SWP_NOSIZE |
369 SWP_NOMOVE |
cef338d3 370 (exflags & WS_EX_TOPMOST ? 0 : SWP_NOZORDER) |
b225f659
VZ
371 SWP_NOACTIVATE);
372 }
373
b554cf63 374#if !defined(__WXWINCE__)
b225f659
VZ
375 // For some reason, the system menu is activated when we use the
376 // WS_EX_CONTEXTHELP style, so let's set a reasonable icon
377 if ( exflags & WS_EX_CONTEXTHELP )
378 {
379 wxFrame *winTop = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame);
380 if ( winTop )
381 {
382 wxIcon icon = winTop->GetIcon();
383 if ( icon.Ok() )
384 {
385 ::SendMessage(GetHwnd(), WM_SETICON,
386 (WPARAM)TRUE,
387 (LPARAM)GetHiconOf(icon));
388 }
389 }
390 }
b554cf63 391#endif
b225f659
VZ
392
393 // move the dialog to its initial position without forcing repainting
394 int x, y, w, h;
72a11184 395 (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
4c53c743 396
26268100
RD
397 if ( x == (int)CW_USEDEFAULT )
398 {
399 // centre it on the screen - what else can we do?
400 wxSize sizeDpy = wxGetDisplaySize();
401
402 x = (sizeDpy.x - w) / 2;
403 y = (sizeDpy.y - h) / 2;
404 }
405
a9928e9d 406#if !defined(__WXWINCE__) || defined(__WINCE_STANDARDSDK__)
4c53c743
VZ
407 if ( !::MoveWindow(GetHwnd(), x, y, w, h, FALSE) )
408 {
409 wxLogLastError(wxT("MoveWindow"));
b225f659 410 }
28c191aa 411#endif
b225f659
VZ
412
413 if ( !title.empty() )
414 {
415 ::SetWindowText(GetHwnd(), title);
416 }
417
418 SubclassWin(m_hWnd);
aa29eefa
JS
419
420#ifdef __SMARTPHONE__
421 // Work around title non-display glitch
422 Show(false);
423#endif
b225f659 424
bfbb0b4c 425 return true;
b225f659
VZ
426#endif // __WXMICROWIN__/!__WXMICROWIN__
427}
428
429bool wxTopLevelWindowMSW::CreateFrame(const wxString& title,
430 const wxPoint& pos,
431 const wxSize& size)
432{
b2d5a7ee
VZ
433 WXDWORD exflags;
434 WXDWORD flags = MSWGetCreateWindowFlags(&exflags);
b225f659 435
3d487566 436#if !defined(__HANDHELDPC__) && ((defined(_WIN32_WCE) && _WIN32_WCE < 400) || \
a9928e9d 437 defined(__POCKETPC__) || \
3d487566 438 defined(__SMARTPHONE__))
991420e6
WS
439 // Always expand to fit the screen in PocketPC or SmartPhone
440 wxSize sz(wxDefaultSize);
441 wxUnusedVar(size);
a48e51ce 442#else // other (including normal desktop) Windows
991420e6 443 wxSize sz(size);
960b193e
JS
444#endif
445
aa29eefa
JS
446 bool result = MSWCreate(wxCanvasClassName, title, pos, sz, flags, exflags);
447
448#ifdef __SMARTPHONE__
449 // Work around title non-display glitch
450 Show(false);
451#endif
452 return result;
82c9f85c
VZ
453}
454
455bool wxTopLevelWindowMSW::Create(wxWindow *parent,
456 wxWindowID id,
457 const wxString& title,
458 const wxPoint& pos,
459 const wxSize& size,
460 long style,
461 const wxString& name)
462{
999836aa 463 bool ret wxDUMMY_INITIALIZE(false);
2a47cb1b 464
82c9f85c
VZ
465 // init our fields
466 Init();
2a47cb1b
VZ
467
468 wxSize sizeReal = size;
469 if ( !sizeReal.IsFullySpecified() )
470 {
471 sizeReal.SetDefaults(GetDefaultSize());
472 }
82c9f85c
VZ
473
474 m_windowStyle = style;
475
476 SetName(name);
477
bfbb0b4c 478 m_windowId = id == wxID_ANY ? NewControlId() : id;
82c9f85c
VZ
479
480 wxTopLevelWindows.Append(this);
481
482 if ( parent )
483 parent->AddChild(this);
484
b225f659
VZ
485 if ( GetExtraStyle() & wxTOPLEVEL_EX_DIALOG )
486 {
b225f659
VZ
487 // we have different dialog templates to allows creation of dialogs
488 // with & without captions under MSWindows, resizeable or not (but a
489 // resizeable dialog always has caption - otherwise it would look too
490 // strange)
434005ca
VZ
491
492 // we need 3 additional WORDs for dialog menu, class and title (as we
493 // don't use DS_SETFONT we don't need the fourth WORD for the font)
494 static const int dlgsize = sizeof(DLGTEMPLATE) + (sizeof(WORD) * 3);
495 DLGTEMPLATE *dlgTemplate = (DLGTEMPLATE *)malloc(dlgsize);
496 memset(dlgTemplate, 0, dlgsize);
497
498 // these values are arbitrary, they won't be used normally anyhow
6e8515a3
JS
499 dlgTemplate->x = 34;
500 dlgTemplate->y = 22;
501 dlgTemplate->cx = 144;
502 dlgTemplate->cy = 75;
503
434005ca
VZ
504 // reuse the code in MSWGetStyle() but correct the results slightly for
505 // the dialog
506 dlgTemplate->style = MSWGetStyle(style, NULL);
507
508 // all dialogs are popups
509 dlgTemplate->style |= WS_POPUP;
510
511 // force 3D-look if necessary, it looks impossibly ugly otherwise
512 if ( style & (wxRESIZE_BORDER | wxCAPTION) )
513 dlgTemplate->style |= DS_MODALFRAME;
b225f659 514
2a47cb1b 515 ret = CreateDialog(dlgTemplate, title, pos, sizeReal);
6e8515a3 516 free(dlgTemplate);
b225f659
VZ
517 }
518 else // !dialog
519 {
2a47cb1b 520 ret = CreateFrame(title, pos, sizeReal);
9ca4dd06
VS
521 }
522
9ceeecb9 523#ifndef __WXWINCE__
9ca4dd06
VS
524 if ( ret && !(GetWindowStyleFlag() & wxCLOSE_BOX) )
525 {
526 EnableCloseButton(false);
b225f659 527 }
9ceeecb9 528#endif
9ca4dd06 529
bb655ead
VZ
530 // for some reason we need to manually send ourselves this message as
531 // otherwise the mnemonics are always shown -- even if they're configured
532 // to be hidden until "Alt" is pressed in the control panel
533 //
534 // this could indicate a bug somewhere else but for now this is the only
535 // fix we have
536 if ( ret )
537 {
bfbb0b4c 538 ::SendMessage
bb655ead
VZ
539 (
540 GetHwnd(),
541 WM_UPDATEUISTATE,
542 MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL),
543 0
544 );
545 }
546
9ceeecb9
JS
547 // Native look is full screen window on Smartphones and Standard SDK.
548 // TODO: check that we need this (if we're passing default values to ctor).
549 // Also check that there really is a difference between PocketPC and Smartphone in this regard.
550#if defined(__WXWINCE__) && (defined(__SMARTPHONE__) || defined(__WINCE_STANDARDSDK__))
82eda5ec 551 if ( style & wxMAXIMIZE )
991420e6
WS
552 {
553 this->Maximize();
554 }
82eda5ec
JS
555#endif
556
3180bc0e 557#if defined(__SMARTPHONE__) && defined(__WXWINCE__)
fb8a56b7
WS
558 SetRightMenu(); // to nothing for initialization
559#endif
560
9ca4dd06 561 return ret;
82c9f85c
VZ
562}
563
564wxTopLevelWindowMSW::~wxTopLevelWindowMSW()
565{
d6fb86a8
VZ
566 // after destroying an owned window, Windows activates the next top level
567 // window in Z order but it may be different from our owner (to reproduce
568 // this simply Alt-TAB to another application and back before closing the
569 // owned frame) whereas we always want to yield activation to our parent
570 if ( HasFlag(wxFRAME_FLOAT_ON_PARENT) )
571 {
572 wxWindow *parent = GetParent();
573 if ( parent )
574 {
575 ::BringWindowToTop(GetHwndOf(parent));
576 }
577 }
82c9f85c
VZ
578}
579
82c9f85c
VZ
580// ----------------------------------------------------------------------------
581// wxTopLevelWindowMSW showing
582// ----------------------------------------------------------------------------
583
584void wxTopLevelWindowMSW::DoShowWindow(int nShowCmd)
585{
586 ::ShowWindow(GetHwnd(), nShowCmd);
587
588 m_iconized = nShowCmd == SW_MINIMIZE;
589}
590
591bool wxTopLevelWindowMSW::Show(bool show)
592{
593 // don't use wxWindow version as we want to call DoShowWindow() ourselves
594 if ( !wxWindowBase::Show(show) )
bfbb0b4c 595 return false;
82c9f85c
VZ
596
597 int nShowCmd;
598 if ( show )
599 {
600 if ( m_maximizeOnShow )
601 {
602 // show and maximize
603 nShowCmd = SW_MAXIMIZE;
604
991420e6 605 // This is necessary, or no window appears
aa29eefa 606#if defined( __WINCE_STANDARDSDK__) || defined(__SMARTPHONE__)
991420e6 607 DoShowWindow(SW_SHOW);
a9928e9d
JS
608#endif
609
bfbb0b4c 610 m_maximizeOnShow = false;
82c9f85c
VZ
611 }
612 else // just show
613 {
84cff965
JS
614 if ( GetWindowStyle() & wxFRAME_TOOL_WINDOW )
615 nShowCmd = SW_SHOWNA;
616 else
617 nShowCmd = SW_SHOW;
82c9f85c
VZ
618 }
619 }
620 else // hide
621 {
622 nShowCmd = SW_HIDE;
623 }
624
625 DoShowWindow(nShowCmd);
626
a9928e9d
JS
627#if defined(__WXWINCE__) && (_WIN32_WCE >= 400 && !defined(__POCKETPC__) && !defined(__SMARTPHONE__))
628 // Addornments have to be added when the frame is the correct size
629 wxFrame* frame = wxDynamicCast(this, wxFrame);
630 if (frame && frame->GetMenuBar())
631 frame->GetMenuBar()->AddAdornments(GetWindowStyleFlag());
632#endif
633
82c9f85c
VZ
634 if ( show )
635 {
636 ::BringWindowToTop(GetHwnd());
637
bfbb0b4c 638 wxActivateEvent event(wxEVT_ACTIVATE, true, m_windowId);
82c9f85c
VZ
639 event.SetEventObject( this );
640 GetEventHandler()->ProcessEvent(event);
641 }
642 else // hide
643 {
644 // Try to highlight the correct window (the parent)
645 if ( GetParent() )
646 {
647 HWND hWndParent = GetHwndOf(GetParent());
648 if (hWndParent)
649 ::BringWindowToTop(hWndParent);
650 }
651 }
652
bfbb0b4c 653 return true;
82c9f85c
VZ
654}
655
656// ----------------------------------------------------------------------------
657// wxTopLevelWindowMSW maximize/minimize
658// ----------------------------------------------------------------------------
659
660void wxTopLevelWindowMSW::Maximize(bool maximize)
661{
662 if ( IsShown() )
663 {
664 // just maximize it directly
665 DoShowWindow(maximize ? SW_MAXIMIZE : SW_RESTORE);
666 }
667 else // hidden
668 {
669 // we can't maximize the hidden frame because it shows it as well, so
670 // just remember that we should do it later in this case
a0be434e 671 m_maximizeOnShow = maximize;
82c9f85c
VZ
672 }
673}
674
675bool wxTopLevelWindowMSW::IsMaximized() const
676{
4676948b 677#ifdef __WXWINCE__
bfbb0b4c 678 return false;
4676948b 679#else
82c9f85c 680 return ::IsZoomed(GetHwnd()) != 0;
4676948b 681#endif
82c9f85c
VZ
682}
683
684void wxTopLevelWindowMSW::Iconize(bool iconize)
685{
686 DoShowWindow(iconize ? SW_MINIMIZE : SW_RESTORE);
687}
688
689bool wxTopLevelWindowMSW::IsIconized() const
690{
4676948b 691#ifdef __WXWINCE__
bfbb0b4c 692 return false;
4676948b 693#else
82c9f85c
VZ
694 // also update the current state
695 ((wxTopLevelWindowMSW *)this)->m_iconized = ::IsIconic(GetHwnd()) != 0;
696
697 return m_iconized;
4676948b 698#endif
82c9f85c
VZ
699}
700
701void wxTopLevelWindowMSW::Restore()
702{
703 DoShowWindow(SW_RESTORE);
704}
705
c641b1d2
VS
706// ----------------------------------------------------------------------------
707// wxTopLevelWindowMSW fullscreen
708// ----------------------------------------------------------------------------
709
710bool wxTopLevelWindowMSW::ShowFullScreen(bool show, long style)
711{
716645d3 712 if ( show == IsFullScreen() )
c641b1d2 713 {
716645d3 714 // nothing to do
bfbb0b4c 715 return true;
716645d3
VZ
716 }
717
718 m_fsIsShowing = show;
c641b1d2 719
716645d3
VZ
720 if ( show )
721 {
c641b1d2
VS
722 m_fsStyle = style;
723
724 // zap the frame borders
725
726 // save the 'normal' window style
716645d3 727 m_fsOldWindowStyle = GetWindowLong(GetHwnd(), GWL_STYLE);
c641b1d2
VS
728
729 // save the old position, width & height, maximize state
730 m_fsOldSize = GetRect();
731 m_fsIsMaximized = IsMaximized();
732
733 // decide which window style flags to turn off
734 LONG newStyle = m_fsOldWindowStyle;
735 LONG offFlags = 0;
736
737 if (style & wxFULLSCREEN_NOBORDER)
4676948b
JS
738 {
739 offFlags |= WS_BORDER;
740#ifndef __WXWINCE__
741 offFlags |= WS_THICKFRAME;
742#endif
743 }
c641b1d2 744 if (style & wxFULLSCREEN_NOCAPTION)
716645d3 745 offFlags |= WS_CAPTION | WS_SYSMENU;
c641b1d2 746
716645d3 747 newStyle &= ~offFlags;
c641b1d2
VS
748
749 // change our window style to be compatible with full-screen mode
716645d3 750 ::SetWindowLong(GetHwnd(), GWL_STYLE, newStyle);
c641b1d2 751
716645d3
VZ
752 wxRect rect;
753#if wxUSE_DISPLAY
754 // resize to the size of the display containing us
755 int dpy = wxDisplay::GetFromWindow(this);
756 if ( dpy != wxNOT_FOUND )
757 {
758 rect = wxDisplay(dpy).GetGeometry();
759 }
760 else // fall back to the main desktop
761#else // wxUSE_DISPLAY
762 {
763 // resize to the size of the desktop
764 wxCopyRECTToRect(wxGetWindowRect(::GetDesktopWindow()), rect);
80a81a12
JS
765#ifdef __WXWINCE__
766 // FIXME: size of the bottom menu (toolbar)
767 // should be taken in account
768 rect.height += rect.y;
769 rect.y = 0;
4676948b 770#endif
716645d3
VZ
771 }
772#endif // wxUSE_DISPLAY
c641b1d2 773
716645d3 774 SetSize(rect);
c641b1d2
VS
775
776 // now flush the window style cache and actually go full-screen
716645d3 777 long flags = SWP_FRAMECHANGED;
c641b1d2 778
716645d3
VZ
779 // showing the frame full screen should also show it if it's still
780 // hidden
781 if ( !IsShown() )
782 {
783 // don't call wxWindow version to avoid flicker from calling
784 // ::ShowWindow() -- we're going to show the window at the correct
785 // location directly below -- but do call the wxWindowBase version
786 // to sync the internal m_isShown flag
787 wxWindowBase::Show();
c641b1d2 788
716645d3
VZ
789 flags |= SWP_SHOWWINDOW;
790 }
c641b1d2 791
716645d3
VZ
792 SetWindowPos(GetHwnd(), HWND_TOP,
793 rect.x, rect.y, rect.width, rect.height,
794 flags);
c641b1d2 795
3d487566 796#if !defined(__HANDHELDPC__) && (defined(__WXWINCE__) && (_WIN32_WCE < 400))
80a81a12
JS
797 ::SHFullScreen(GetHwnd(), SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON);
798#endif
799
716645d3
VZ
800 // finally send an event allowing the window to relayout itself &c
801 wxSizeEvent event(rect.GetSize(), GetId());
802 GetEventHandler()->ProcessEvent(event);
803 }
804 else // stop showing full screen
805 {
3d487566 806#if !defined(__HANDHELDPC__) && (defined(__WXWINCE__) && (_WIN32_WCE < 400))
80a81a12
JS
807 ::SHFullScreen(GetHwnd(), SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON);
808#endif
c641b1d2 809 Maximize(m_fsIsMaximized);
716645d3
VZ
810 SetWindowLong(GetHwnd(),GWL_STYLE, m_fsOldWindowStyle);
811 SetWindowPos(GetHwnd(),HWND_TOP,m_fsOldSize.x, m_fsOldSize.y,
c641b1d2 812 m_fsOldSize.width, m_fsOldSize.height, SWP_FRAMECHANGED);
c641b1d2 813 }
716645d3 814
bfbb0b4c 815 return true;
c641b1d2
VS
816}
817
82c9f85c
VZ
818// ----------------------------------------------------------------------------
819// wxTopLevelWindowMSW misc
820// ----------------------------------------------------------------------------
821
822void wxTopLevelWindowMSW::SetIcon(const wxIcon& icon)
823{
f618020a
MB
824 SetIcons( wxIconBundle( icon ) );
825}
826
827void wxTopLevelWindowMSW::SetIcons(const wxIconBundle& icons)
828{
829 wxTopLevelWindowBase::SetIcons(icons);
82c9f85c
VZ
830
831#if defined(__WIN95__) && !defined(__WXMICROWIN__)
f618020a
MB
832 const wxIcon& sml = icons.GetIcon( wxSize( 16, 16 ) );
833 if( sml.Ok() && sml.GetWidth() == 16 && sml.GetHeight() == 16 )
834 {
835 ::SendMessage( GetHwndOf( this ), WM_SETICON, ICON_SMALL,
836 (LPARAM)GetHiconOf(sml) );
837 }
838
839 const wxIcon& big = icons.GetIcon( wxSize( 32, 32 ) );
840 if( big.Ok() && big.GetWidth() == 32 && big.GetHeight() == 32 )
82c9f85c 841 {
f618020a
MB
842 ::SendMessage( GetHwndOf( this ), WM_SETICON, ICON_BIG,
843 (LPARAM)GetHiconOf(big) );
82c9f85c
VZ
844 }
845#endif // __WIN95__
846}
a91cf80c
VZ
847
848bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
849{
4676948b 850#if !defined(__WXMICROWIN__)
a91cf80c 851 // get system (a.k.a. window) menu
068959b9 852 HMENU hmenu = GetSystemMenu(GetHwnd(), FALSE /* get it */);
a91cf80c
VZ
853 if ( !hmenu )
854 {
660b1906
VZ
855 // no system menu at all -- ok if we want to remove the close button
856 // anyhow, but bad if we want to show it
857 return !enable;
a91cf80c
VZ
858 }
859
860 // enabling/disabling the close item from it also automatically
861 // disables/enables the close title bar button
aaf765a5
VZ
862 if ( ::EnableMenuItem(hmenu, SC_CLOSE,
863 MF_BYCOMMAND |
864 (enable ? MF_ENABLED : MF_GRAYED)) == -1 )
a91cf80c
VZ
865 {
866 wxLogLastError(_T("EnableMenuItem(SC_CLOSE)"));
867
bfbb0b4c 868 return false;
a91cf80c 869 }
960b193e 870#ifndef __WXWINCE__
a91cf80c
VZ
871 // update appearance immediately
872 if ( !::DrawMenuBar(GetHwnd()) )
873 {
874 wxLogLastError(_T("DrawMenuBar"));
875 }
960b193e 876#endif
a91cf80c
VZ
877#endif // !__WXMICROWIN__
878
bfbb0b4c 879 return true;
a91cf80c
VZ
880}
881
2a47cb1b
VZ
882#ifndef __WXWINCE__
883
1542ea39
RD
884bool wxTopLevelWindowMSW::SetShape(const wxRegion& region)
885{
bfbb0b4c 886 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false,
6a7e6411
RD
887 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
888
1542ea39
RD
889 // The empty region signifies that the shape should be removed from the
890 // window.
891 if ( region.IsEmpty() )
892 {
893 if (::SetWindowRgn(GetHwnd(), NULL, TRUE) == 0)
894 {
895 wxLogLastError(_T("SetWindowRgn"));
bfbb0b4c 896 return false;
1542ea39 897 }
bfbb0b4c 898 return true;
1542ea39
RD
899 }
900
901 // Windows takes ownership of the region, so
902 // we'll have to make a copy of the region to give to it.
903 DWORD noBytes = ::GetRegionData(GetHrgnOf(region), 0, NULL);
904 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
905 ::GetRegionData(GetHrgnOf(region), noBytes, rgnData);
906 HRGN hrgn = ::ExtCreateRegion(NULL, noBytes, rgnData);
907 delete[] (char*) rgnData;
908
909 // SetWindowRgn expects the region to be in coordinants
910 // relative to the window, not the client area. Figure
911 // out the offset, if any.
912 RECT rect;
913 DWORD dwStyle = ::GetWindowLong(GetHwnd(), GWL_STYLE);
914 DWORD dwExStyle = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE);
915 ::GetClientRect(GetHwnd(), &rect);
916 ::AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
917 ::OffsetRgn(hrgn, -rect.left, -rect.top);
918
919 // Now call the shape API with the new region.
920 if (::SetWindowRgn(GetHwnd(), hrgn, TRUE) == 0)
921 {
922 wxLogLastError(_T("SetWindowRgn"));
bfbb0b4c 923 return false;
1542ea39 924 }
bfbb0b4c 925 return true;
1542ea39
RD
926}
927
2a47cb1b
VZ
928#endif // !__WXWINCE__
929
dc92adaf
VZ
930void wxTopLevelWindowMSW::RequestUserAttention(int flags)
931{
4f79eb79
VZ
932 // check if we can use FlashWindowEx(): unfortunately an explicit test for
933 // FLASHW_STOP, for example, doesn't work because MSVC6 headers do #define
934 // it but don't provide FlashWindowEx() declaration
1a838ff5 935#if (WINVER >= 0x0500 && (defined FLASHW_STOP))
dc92adaf
VZ
936 // available in the headers, check if it is supported by the system
937 typedef BOOL (WINAPI *FlashWindowEx_t)(FLASHWINFO *pfwi);
938 FlashWindowEx_t s_pfnFlashWindowEx = NULL;
939 if ( !s_pfnFlashWindowEx )
940 {
941 wxDynamicLibrary dllUser32(_T("user32.dll"));
942 s_pfnFlashWindowEx = (FlashWindowEx_t)
943 dllUser32.GetSymbol(_T("FlashWindowEx"));
944
945 // we can safely unload user32.dll here, it's goign to remain loaded as
946 // long as the program is running anyhow
947 }
948
949 if ( s_pfnFlashWindowEx )
950 {
951 WinStruct<FLASHWINFO> fwi;
952 fwi.hwnd = GetHwnd();
953 fwi.dwFlags = FLASHW_ALL;
954 if ( flags & wxUSER_ATTENTION_INFO )
955 {
956 // just flash a few times
957 fwi.uCount = 3;
958 }
959 else // wxUSER_ATTENTION_ERROR
960 {
961 // flash until the user notices it
962 fwi.dwFlags |= FLASHW_TIMERNOFG;
963 }
964
965 s_pfnFlashWindowEx(&fwi);
966 }
967 else // FlashWindowEx() not available
4f79eb79 968#endif // FlashWindowEx() defined
dc92adaf
VZ
969 {
970 wxUnusedVar(flags);
068959b9 971#ifndef __WXWINCE__
dc92adaf 972 ::FlashWindow(GetHwnd(), TRUE);
068959b9 973#endif // __WXWINCE__
dc92adaf
VZ
974 }
975}
976
085ad686
VZ
977// ----------------------------------------------------------------------------
978// wxTopLevelWindow event handling
979// ----------------------------------------------------------------------------
980
981// Default activation behaviour - set the focus for the first child
982// subwindow found.
983void wxTopLevelWindowMSW::OnActivate(wxActivateEvent& event)
984{
985 if ( event.GetActive() )
986 {
2736a5de
VZ
987 // restore focus to the child which was last focused unless we already
988 // have it
989 wxLogTrace(_T("focus"), _T("wxTLW %08x activated."), (int) m_hWnd);
085ad686 990
2736a5de
VZ
991 wxWindow *winFocus = FindFocus();
992 if ( !winFocus || wxGetTopLevelParent(winFocus) != this )
085ad686 993 {
2736a5de
VZ
994 wxWindow *parent = m_winLastFocused ? m_winLastFocused->GetParent()
995 : NULL;
996 if ( !parent )
997 {
998 parent = this;
999 }
085ad686 1000
2736a5de
VZ
1001 wxSetFocusToChild(parent, &m_winLastFocused);
1002 }
085ad686
VZ
1003 }
1004 else // deactivating
1005 {
1006 // remember the last focused child if it is our child
1007 m_winLastFocused = FindFocus();
1008
13834828
VZ
1009 if ( m_winLastFocused )
1010 {
1011 // let it know that it doesn't have focus any more
77e00fe9 1012 m_winLastFocused->HandleKillFocus((WXHWND)NULL);
13834828 1013
2736a5de
VZ
1014 // and don't remember it if it's a child from some other frame
1015 if ( wxGetTopLevelParent(m_winLastFocused) != this )
085ad686 1016 {
2736a5de 1017 m_winLastFocused = NULL;
085ad686 1018 }
085ad686
VZ
1019 }
1020
1021 wxLogTrace(_T("focus"),
1022 _T("wxTLW %08x deactivated, last focused: %08x."),
9b601c24
GRG
1023 (int) m_hWnd,
1024 (int) (m_winLastFocused ? GetHwndOf(m_winLastFocused)
1025 : NULL));
085ad686
VZ
1026
1027 event.Skip();
1028 }
1029}
1030
77ffb593 1031// the DialogProc for all wxWidgets dialogs
12447831 1032LONG APIENTRY _EXPORT
0fc58b86 1033wxDlgProc(HWND hDlg,
2eb10e2a
VZ
1034 UINT message,
1035 WPARAM WXUNUSED(wParam),
1036 LPARAM WXUNUSED(lParam))
12447831 1037{
a48e51ce 1038 if ( message == WM_INITDIALOG )
12447831 1039 {
a48e51ce
VZ
1040 // under CE, add a "Ok" button in the dialog title bar and make it full
1041 // screen
1042 //
9ceeecb9
JS
1043 // TODO: find the window for this HWND, and take into account
1044 // wxMAXIMIZE and wxCLOSE_BOX. For now, assume both are present.
1045 //
a48e51ce
VZ
1046 // Standard SDK doesn't have aygshell.dll: see
1047 // include/wx/msw/wince/libraries.h
3d487566 1048#if defined(__WXWINCE__) && !defined(__WINCE_STANDARDSDK__) && !defined(__HANDHELDPC__)
a48e51ce
VZ
1049 SHINITDLGINFO shidi;
1050 shidi.dwMask = SHIDIM_FLAGS;
b554cf63 1051 shidi.dwFlags = SHIDIF_SIZEDLG // take account of the SIP or menubar
ef6d716b
WS
1052#ifndef __SMARTPHONE__
1053 | SHIDIF_DONEBUTTON
1054#endif
1055 ;
a48e51ce
VZ
1056 shidi.hDlg = hDlg;
1057 SHInitDialog( &shidi );
1058#else // no SHInitDialog()
1059 wxUnusedVar(hDlg);
0fc58b86 1060#endif
12447831 1061 }
a48e51ce
VZ
1062
1063 // for almost all messages, returning FALSE means that we didn't process
1064 // the message
1065 //
1066 // for WM_INITDIALOG, returning TRUE tells system to set focus to
1067 // the first control in the dialog box, but as we set the focus
1068 // ourselves, we return FALSE for it as well
1069 return FALSE;
12447831
VZ
1070}
1071
2b5f62a0
VZ
1072// ============================================================================
1073// wxTLWHiddenParentModule implementation
1074// ============================================================================
1075
1076HWND wxTLWHiddenParentModule::ms_hwnd = NULL;
1077
1078const wxChar *wxTLWHiddenParentModule::ms_className = NULL;
1079
1080bool wxTLWHiddenParentModule::OnInit()
1081{
1082 ms_hwnd = NULL;
1083 ms_className = NULL;
1084
bfbb0b4c 1085 return true;
2b5f62a0
VZ
1086}
1087
1088void wxTLWHiddenParentModule::OnExit()
1089{
1090 if ( ms_hwnd )
1091 {
1092 if ( !::DestroyWindow(ms_hwnd) )
1093 {
1094 wxLogLastError(_T("DestroyWindow(hidden TLW parent)"));
1095 }
1096
1097 ms_hwnd = NULL;
1098 }
1099
1100 if ( ms_className )
1101 {
1102 if ( !::UnregisterClass(ms_className, wxGetInstance()) )
1103 {
1104 wxLogLastError(_T("UnregisterClass(\"wxTLWHiddenParent\")"));
1105 }
1106
1107 ms_className = NULL;
1108 }
1109}
1110
1111/* static */
1112HWND wxTLWHiddenParentModule::GetHWND()
1113{
1114 if ( !ms_hwnd )
1115 {
1116 if ( !ms_className )
1117 {
1118 static const wxChar *HIDDEN_PARENT_CLASS = _T("wxTLWHiddenParent");
1119
1120 WNDCLASS wndclass;
1121 wxZeroMemory(wndclass);
1122
1123 wndclass.lpfnWndProc = DefWindowProc;
1124 wndclass.hInstance = wxGetInstance();
1125 wndclass.lpszClassName = HIDDEN_PARENT_CLASS;
1126
1127 if ( !::RegisterClass(&wndclass) )
1128 {
1129 wxLogLastError(_T("RegisterClass(\"wxTLWHiddenParent\")"));
1130 }
1131 else
1132 {
1133 ms_className = HIDDEN_PARENT_CLASS;
1134 }
1135 }
1136
fda7962d 1137 ms_hwnd = ::CreateWindow(ms_className, wxEmptyString, 0, 0, 0, 0, 0, NULL,
2b5f62a0
VZ
1138 (HMENU)NULL, wxGetInstance(), NULL);
1139 if ( !ms_hwnd )
1140 {
1141 wxLogLastError(_T("CreateWindow(hidden TLW parent)"));
1142 }
1143 }
1144
1145 return ms_hwnd;
1146}
1147
1542ea39 1148