]> git.saurik.com Git - wxWidgets.git/blame - src/msw/toplevel.cpp
reformatted to fit in the page width
[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)
9// License: wxWindows license
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
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"
82c9f85c
VZ
34 #include "wx/string.h"
35 #include "wx/log.h"
36 #include "wx/intl.h"
14dd645e 37 #include "wx/frame.h"
82c9f85c
VZ
38#endif //WX_PRECOMP
39
40#include "wx/msw/private.h"
41
e121a72a
MB
42#ifndef ICON_BIG
43 #define ICON_BIG 1
44#endif
45
46#ifndef ICON_SMALL
47 #define ICON_SMALL 0
48#endif
49
82c9f85c
VZ
50// ----------------------------------------------------------------------------
51// stubs for missing functions under MicroWindows
52// ----------------------------------------------------------------------------
53
54#ifdef __WXMICROWIN__
55
c67d6888 56// static inline bool IsIconic(HWND WXUNUSED(hwnd)) { return FALSE; }
82c9f85c
VZ
57static inline bool IsZoomed(HWND WXUNUSED(hwnd)) { return FALSE; }
58
59#endif // __WXMICROWIN__
60
61// ----------------------------------------------------------------------------
62// globals
63// ----------------------------------------------------------------------------
64
65// list of all frames and modeless dialogs
66wxWindowList wxModelessWindows;
67
b225f659
VZ
68// the name of the default wxWindows class
69extern const wxChar *wxCanvasClassName;
70
82c9f85c
VZ
71// ============================================================================
72// wxTopLevelWindowMSW implementation
73// ============================================================================
74
7fe1a8b5
VZ
75// ----------------------------------------------------------------------------
76// wxDialog helpers
77// ----------------------------------------------------------------------------
78
b225f659
VZ
79// Dialog window proc
80LONG APIENTRY _EXPORT
7fe1a8b5 81wxDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
b225f659 82{
7fe1a8b5 83 switch ( message )
b225f659 84 {
7fe1a8b5
VZ
85 case WM_INITDIALOG:
86 // for this message, returning TRUE tells system to set focus to the
87 // first control in the dialog box
88 return TRUE;
89
90 default:
91 // for all the other ones, FALSE means that we didn't process the
92 // message
93 return FALSE;
b225f659
VZ
94 }
95}
96
82c9f85c
VZ
97// ----------------------------------------------------------------------------
98// wxTopLevelWindowMSW creation
99// ----------------------------------------------------------------------------
100
101void wxTopLevelWindowMSW::Init()
102{
103 m_iconized =
104 m_maximizeOnShow = FALSE;
b225f659
VZ
105
106 // unlike (almost?) all other windows, frames are created hidden
107 m_isShown = FALSE;
c641b1d2
VS
108
109 // Data to save/restore when calling ShowFullScreen
110 m_fsStyle = 0;
111 m_fsOldWindowStyle = 0;
112 m_fsIsMaximized = FALSE;
113 m_fsIsShowing = FALSE;
b225f659
VZ
114}
115
b2d5a7ee 116WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const
b225f659 117{
b2d5a7ee
VZ
118 // let the base class deal with the common styles but fix the ones which
119 // don't make sense for us (we also deal with the borders ourselves)
120 WXDWORD msflags = wxWindow::MSWGetStyle
121 (
122 (style & ~wxBORDER_MASK) | wxBORDER_NONE, exflags
123 ) & ~WS_CHILD;
b225f659
VZ
124
125 // first select the kind of window being created
dfb06c62
VZ
126 //
127 // note that if we don't set WS_POPUP, Windows assumes WS_OVERLAPPED and
128 // creates a window with both caption and border, hence we also test it
129 // below in some other cases
0e082993 130 if ( style & wxFRAME_TOOL_WINDOW )
b2d5a7ee 131 msflags |= WS_POPUP;
b225f659 132 else
b2d5a7ee 133 msflags |= WS_OVERLAPPED;
0e082993
VZ
134
135 // border and caption styles
136 if ( style & wxRESIZE_BORDER )
137 msflags |= WS_THICKFRAME;
138 else if ( !(style & wxBORDER_NONE) )
139 msflags |= WS_BORDER;
dfb06c62
VZ
140 else
141 msflags |= WS_POPUP;
0e082993
VZ
142
143 if ( style & wxCAPTION )
144 msflags |= WS_CAPTION;
dfb06c62 145 else
b225f659 146 msflags |= WS_POPUP;
b225f659
VZ
147
148 // next translate the individual flags
149 if ( style & wxMINIMIZE_BOX )
150 msflags |= WS_MINIMIZEBOX;
151 if ( style & wxMAXIMIZE_BOX )
152 msflags |= WS_MAXIMIZEBOX;
b225f659
VZ
153 if ( style & wxSYSTEM_MENU )
154 msflags |= WS_SYSMENU;
155 if ( style & wxMINIMIZE )
156 msflags |= WS_MINIMIZE;
157 if ( style & wxMAXIMIZE )
158 msflags |= WS_MAXIMIZE;
0e082993 159
b225f659
VZ
160 // Keep this here because it saves recoding this function in wxTinyFrame
161#if wxUSE_ITSY_BITSY && !defined(__WIN32__)
162 if ( style & wxTINY_CAPTION_VERT )
163 msflags |= IBS_VERTCAPTION;
164 if ( style & wxTINY_CAPTION_HORIZ )
165 msflags |= IBS_HORZCAPTION;
166#else
167 if ( style & (wxTINY_CAPTION_VERT | wxTINY_CAPTION_HORIZ) )
168 msflags |= WS_CAPTION;
169#endif
170
171 if ( exflags )
172 {
b225f659 173#if !defined(__WIN16__) && !defined(__SC__)
35bf863b
VZ
174 if ( !(GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) )
175 {
176 // make all frames appear in the win9x shell taskbar unless
177 // wxFRAME_TOOL_WINDOW or wxFRAME_NO_TASKBAR is given - without
178 // giving them WS_EX_APPWINDOW style, the child (i.e. owned) frames
179 // wouldn't appear in it
180 if ( (style & wxFRAME_TOOL_WINDOW) || (style & wxFRAME_NO_TASKBAR) )
181 *exflags |= WS_EX_TOOLWINDOW;
182 else if ( !(style & wxFRAME_NO_TASKBAR) )
183 *exflags |= WS_EX_APPWINDOW;
184 }
185#endif // !Win16
b225f659
VZ
186
187 if ( style & wxSTAY_ON_TOP )
188 *exflags |= WS_EX_TOPMOST;
189
190#ifdef __WIN32__
b2d5a7ee 191 if ( GetExtraStyle() & wxFRAME_EX_CONTEXTHELP )
68d02db3 192 *exflags |= WS_EX_CONTEXTHELP;
b225f659
VZ
193#endif // __WIN32__
194 }
195
196 return msflags;
197}
198
6e8515a3 199bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate,
b225f659
VZ
200 const wxString& title,
201 const wxPoint& pos,
202 const wxSize& size)
203{
204#ifdef __WXMICROWIN__
205 // no dialogs support under MicroWin yet
206 return CreateFrame(title, pos, size);
207#else // !__WXMICROWIN__
208 wxWindow *parent = GetParent();
209
210 // for the dialogs without wxDIALOG_NO_PARENT style, use the top level
211 // app window as parent - this avoids creating modal dialogs without
212 // parent
213 if ( !parent && !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT) )
214 {
215 parent = wxTheApp->GetTopWindow();
e058b98d 216
39cc7a0b 217 if ( parent )
e058b98d 218 {
39cc7a0b
VZ
219 // don't use transient windows as parents, this is dangerous as it
220 // can lead to a crash if the parent is destroyed before the child
221 //
222 // also don't use the window which is currently hidden as then the
223 // dialog would be hidden as well
224 if ( (parent->GetExtraStyle() & wxWS_EX_TRANSIENT) ||
225 !parent->IsShown() )
226 {
227 parent = NULL;
228 }
e058b98d 229 }
b225f659
VZ
230 }
231
434005ca
VZ
232 m_hWnd = (WXHWND)::CreateDialogIndirect
233 (
234 wxGetInstance(),
235 (DLGTEMPLATE*)dlgTemplate,
236 parent ? GetHwndOf(parent) : NULL,
237 (DLGPROC)wxDlgProc
238 );
b225f659
VZ
239
240 if ( !m_hWnd )
241 {
6e8515a3 242 wxFAIL_MSG(_("Failed to create dialog. Incorrect DLGTEMPLATE?"));
b225f659 243
6e8515a3 244 wxLogSysError(_("Can't create dialog using memory template"));
b225f659
VZ
245
246 return FALSE;
247 }
248
b2d5a7ee 249 WXDWORD exflags;
b225f659
VZ
250 (void)MSWGetCreateWindowFlags(&exflags);
251
252 if ( exflags )
253 {
254 ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exflags);
255 ::SetWindowPos(GetHwnd(), NULL, 0, 0, 0, 0,
256 SWP_NOSIZE |
257 SWP_NOMOVE |
258 SWP_NOZORDER |
259 SWP_NOACTIVATE);
260 }
261
262#if defined(__WIN95__)
263 // For some reason, the system menu is activated when we use the
264 // WS_EX_CONTEXTHELP style, so let's set a reasonable icon
265 if ( exflags & WS_EX_CONTEXTHELP )
266 {
267 wxFrame *winTop = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame);
268 if ( winTop )
269 {
270 wxIcon icon = winTop->GetIcon();
271 if ( icon.Ok() )
272 {
273 ::SendMessage(GetHwnd(), WM_SETICON,
274 (WPARAM)TRUE,
275 (LPARAM)GetHiconOf(icon));
276 }
277 }
278 }
279#endif // __WIN95__
280
281 // move the dialog to its initial position without forcing repainting
282 int x, y, w, h;
4c53c743 283 if ( !MSWGetCreateWindowCoords(pos, size, x, y, w, h) )
b225f659 284 {
4c53c743
VZ
285 x =
286 w = (int)CW_USEDEFAULT;
287 }
f04a0744 288
4c53c743
VZ
289 // we can't use CW_USEDEFAULT here as we're not calling CreateWindow()
290 // and passing CW_USEDEFAULT to MoveWindow() results in resizing the
291 // window to (0, 0) size which breaks quite a lot of things, e.g. the
292 // sizer calculation in wxSizer::Fit()
293 if ( w == (int)CW_USEDEFAULT )
294 {
295 // the exact number doesn't matter, the dialog will be resized
296 // again soon anyhow but it should be big enough to allow
297 // calculation relying on "totalSize - clientSize > 0" work, i.e.
298 // at least greater than the title bar height
299 w =
300 h = 100;
301 }
f0adbe0f 302
4c53c743
VZ
303 if ( x == (int)CW_USEDEFAULT )
304 {
305 // centre it on the screen - what else can we do?
306 wxSize sizeDpy = wxGetDisplaySize();
307
308 x = (sizeDpy.x - w) / 2;
309 y = (sizeDpy.y - h) / 2;
310 }
311
312 if ( !::MoveWindow(GetHwnd(), x, y, w, h, FALSE) )
313 {
314 wxLogLastError(wxT("MoveWindow"));
b225f659 315 }
b225f659
VZ
316
317 if ( !title.empty() )
318 {
319 ::SetWindowText(GetHwnd(), title);
320 }
321
322 SubclassWin(m_hWnd);
323
324 return TRUE;
325#endif // __WXMICROWIN__/!__WXMICROWIN__
326}
327
328bool wxTopLevelWindowMSW::CreateFrame(const wxString& title,
329 const wxPoint& pos,
330 const wxSize& size)
331{
b2d5a7ee
VZ
332 WXDWORD exflags;
333 WXDWORD flags = MSWGetCreateWindowFlags(&exflags);
b225f659
VZ
334
335 return MSWCreate(wxCanvasClassName, title, pos, size, flags, exflags);
82c9f85c
VZ
336}
337
338bool wxTopLevelWindowMSW::Create(wxWindow *parent,
339 wxWindowID id,
340 const wxString& title,
341 const wxPoint& pos,
342 const wxSize& size,
343 long style,
344 const wxString& name)
345{
346 // init our fields
347 Init();
348
349 m_windowStyle = style;
350
351 SetName(name);
352
353 m_windowId = id == -1 ? NewControlId() : id;
354
355 wxTopLevelWindows.Append(this);
356
357 if ( parent )
358 parent->AddChild(this);
359
b225f659
VZ
360 if ( GetExtraStyle() & wxTOPLEVEL_EX_DIALOG )
361 {
b225f659
VZ
362 // we have different dialog templates to allows creation of dialogs
363 // with & without captions under MSWindows, resizeable or not (but a
364 // resizeable dialog always has caption - otherwise it would look too
365 // strange)
434005ca
VZ
366
367 // we need 3 additional WORDs for dialog menu, class and title (as we
368 // don't use DS_SETFONT we don't need the fourth WORD for the font)
369 static const int dlgsize = sizeof(DLGTEMPLATE) + (sizeof(WORD) * 3);
370 DLGTEMPLATE *dlgTemplate = (DLGTEMPLATE *)malloc(dlgsize);
371 memset(dlgTemplate, 0, dlgsize);
372
373 // these values are arbitrary, they won't be used normally anyhow
6e8515a3
JS
374 dlgTemplate->x = 34;
375 dlgTemplate->y = 22;
376 dlgTemplate->cx = 144;
377 dlgTemplate->cy = 75;
378
434005ca
VZ
379 // reuse the code in MSWGetStyle() but correct the results slightly for
380 // the dialog
381 dlgTemplate->style = MSWGetStyle(style, NULL);
382
383 // all dialogs are popups
384 dlgTemplate->style |= WS_POPUP;
385
386 // force 3D-look if necessary, it looks impossibly ugly otherwise
387 if ( style & (wxRESIZE_BORDER | wxCAPTION) )
388 dlgTemplate->style |= DS_MODALFRAME;
b225f659 389
6e8515a3
JS
390 bool ret = CreateDialog(dlgTemplate, title, pos, size);
391 free(dlgTemplate);
434005ca 392
6e8515a3 393 return ret;
b225f659
VZ
394 }
395 else // !dialog
396 {
397 return CreateFrame(title, pos, size);
398 }
82c9f85c
VZ
399}
400
401wxTopLevelWindowMSW::~wxTopLevelWindowMSW()
402{
403 wxTopLevelWindows.DeleteObject(this);
404
405 if ( wxModelessWindows.Find(this) )
406 wxModelessWindows.DeleteObject(this);
407
408 // If this is the last top-level window, exit.
409 if ( wxTheApp && (wxTopLevelWindows.Number() == 0) )
410 {
411 wxTheApp->SetTopWindow(NULL);
412
413 if ( wxTheApp->GetExitOnFrameDelete() )
414 {
415 ::PostQuitMessage(0);
416 }
417 }
418}
419
82c9f85c
VZ
420// ----------------------------------------------------------------------------
421// wxTopLevelWindowMSW showing
422// ----------------------------------------------------------------------------
423
424void wxTopLevelWindowMSW::DoShowWindow(int nShowCmd)
425{
426 ::ShowWindow(GetHwnd(), nShowCmd);
427
428 m_iconized = nShowCmd == SW_MINIMIZE;
429}
430
431bool wxTopLevelWindowMSW::Show(bool show)
432{
433 // don't use wxWindow version as we want to call DoShowWindow() ourselves
434 if ( !wxWindowBase::Show(show) )
435 return FALSE;
436
437 int nShowCmd;
438 if ( show )
439 {
440 if ( m_maximizeOnShow )
441 {
442 // show and maximize
443 nShowCmd = SW_MAXIMIZE;
444
445 m_maximizeOnShow = FALSE;
446 }
447 else // just show
448 {
449 nShowCmd = SW_SHOW;
450 }
451 }
452 else // hide
453 {
454 nShowCmd = SW_HIDE;
455 }
456
457 DoShowWindow(nShowCmd);
458
459 if ( show )
460 {
461 ::BringWindowToTop(GetHwnd());
462
463 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_windowId);
464 event.SetEventObject( this );
465 GetEventHandler()->ProcessEvent(event);
466 }
467 else // hide
468 {
469 // Try to highlight the correct window (the parent)
470 if ( GetParent() )
471 {
472 HWND hWndParent = GetHwndOf(GetParent());
473 if (hWndParent)
474 ::BringWindowToTop(hWndParent);
475 }
476 }
477
478 return TRUE;
479}
480
481// ----------------------------------------------------------------------------
482// wxTopLevelWindowMSW maximize/minimize
483// ----------------------------------------------------------------------------
484
485void wxTopLevelWindowMSW::Maximize(bool maximize)
486{
487 if ( IsShown() )
488 {
489 // just maximize it directly
490 DoShowWindow(maximize ? SW_MAXIMIZE : SW_RESTORE);
491 }
492 else // hidden
493 {
494 // we can't maximize the hidden frame because it shows it as well, so
495 // just remember that we should do it later in this case
496 m_maximizeOnShow = TRUE;
497 }
498}
499
500bool wxTopLevelWindowMSW::IsMaximized() const
501{
502 return ::IsZoomed(GetHwnd()) != 0;
503}
504
505void wxTopLevelWindowMSW::Iconize(bool iconize)
506{
507 DoShowWindow(iconize ? SW_MINIMIZE : SW_RESTORE);
508}
509
510bool wxTopLevelWindowMSW::IsIconized() const
511{
512 // also update the current state
513 ((wxTopLevelWindowMSW *)this)->m_iconized = ::IsIconic(GetHwnd()) != 0;
514
515 return m_iconized;
516}
517
518void wxTopLevelWindowMSW::Restore()
519{
520 DoShowWindow(SW_RESTORE);
521}
522
c641b1d2
VS
523// ----------------------------------------------------------------------------
524// wxTopLevelWindowMSW fullscreen
525// ----------------------------------------------------------------------------
526
527bool wxTopLevelWindowMSW::ShowFullScreen(bool show, long style)
528{
529 if (show)
530 {
531 if (IsFullScreen())
532 return FALSE;
533
534 m_fsIsShowing = TRUE;
535 m_fsStyle = style;
536
537 // zap the frame borders
538
539 // save the 'normal' window style
540 m_fsOldWindowStyle = GetWindowLong((HWND)GetHWND(), GWL_STYLE);
541
542 // save the old position, width & height, maximize state
543 m_fsOldSize = GetRect();
544 m_fsIsMaximized = IsMaximized();
545
546 // decide which window style flags to turn off
547 LONG newStyle = m_fsOldWindowStyle;
548 LONG offFlags = 0;
549
550 if (style & wxFULLSCREEN_NOBORDER)
551 offFlags |= WS_BORDER | WS_THICKFRAME;
552 if (style & wxFULLSCREEN_NOCAPTION)
553 offFlags |= (WS_CAPTION | WS_SYSMENU);
554
555 newStyle &= (~offFlags);
556
557 // change our window style to be compatible with full-screen mode
558 ::SetWindowLong((HWND)GetHWND(), GWL_STYLE, newStyle);
559
560 // resize to the size of the desktop
561 int width, height;
562
563 RECT rect = wxGetWindowRect(::GetDesktopWindow());
564 width = rect.right - rect.left;
565 height = rect.bottom - rect.top;
566
567 SetSize(width, height);
568
569 // now flush the window style cache and actually go full-screen
570 SetWindowPos((HWND)GetHWND(), HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED);
571
572 wxSizeEvent event(wxSize(width, height), GetId());
573 GetEventHandler()->ProcessEvent(event);
574
575 return TRUE;
576 }
577 else
578 {
579 if (!IsFullScreen())
580 return FALSE;
581
582 m_fsIsShowing = FALSE;
583
584 Maximize(m_fsIsMaximized);
585 SetWindowLong((HWND)GetHWND(),GWL_STYLE, m_fsOldWindowStyle);
586 SetWindowPos((HWND)GetHWND(),HWND_TOP,m_fsOldSize.x, m_fsOldSize.y,
587 m_fsOldSize.width, m_fsOldSize.height, SWP_FRAMECHANGED);
588
589 return TRUE;
590 }
591}
592
82c9f85c
VZ
593// ----------------------------------------------------------------------------
594// wxTopLevelWindowMSW misc
595// ----------------------------------------------------------------------------
596
597void wxTopLevelWindowMSW::SetIcon(const wxIcon& icon)
598{
f618020a
MB
599 SetIcons( wxIconBundle( icon ) );
600}
601
602void wxTopLevelWindowMSW::SetIcons(const wxIconBundle& icons)
603{
604 wxTopLevelWindowBase::SetIcons(icons);
82c9f85c
VZ
605
606#if defined(__WIN95__) && !defined(__WXMICROWIN__)
f618020a
MB
607 const wxIcon& sml = icons.GetIcon( wxSize( 16, 16 ) );
608 if( sml.Ok() && sml.GetWidth() == 16 && sml.GetHeight() == 16 )
609 {
610 ::SendMessage( GetHwndOf( this ), WM_SETICON, ICON_SMALL,
611 (LPARAM)GetHiconOf(sml) );
612 }
613
614 const wxIcon& big = icons.GetIcon( wxSize( 32, 32 ) );
615 if( big.Ok() && big.GetWidth() == 32 && big.GetHeight() == 32 )
82c9f85c 616 {
f618020a
MB
617 ::SendMessage( GetHwndOf( this ), WM_SETICON, ICON_BIG,
618 (LPARAM)GetHiconOf(big) );
82c9f85c
VZ
619 }
620#endif // __WIN95__
621}
a91cf80c
VZ
622
623bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
624{
625#ifndef __WXMICROWIN__
626 // get system (a.k.a. window) menu
627 HMENU hmenu = ::GetSystemMenu(GetHwnd(), FALSE /* get it */);
628 if ( !hmenu )
629 {
630 wxLogLastError(_T("GetSystemMenu"));
631
632 return FALSE;
633 }
634
635 // enabling/disabling the close item from it also automatically
636 // disables/enables the close title bar button
aaf765a5
VZ
637 if ( ::EnableMenuItem(hmenu, SC_CLOSE,
638 MF_BYCOMMAND |
639 (enable ? MF_ENABLED : MF_GRAYED)) == -1 )
a91cf80c
VZ
640 {
641 wxLogLastError(_T("EnableMenuItem(SC_CLOSE)"));
642
643 return FALSE;
644 }
645
646 // update appearance immediately
647 if ( !::DrawMenuBar(GetHwnd()) )
648 {
649 wxLogLastError(_T("DrawMenuBar"));
650 }
651#endif // !__WXMICROWIN__
652
653 return TRUE;
654}
655