]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/toplevel.cpp
Committing in .
[wxWidgets.git] / src / msw / toplevel.cpp
... / ...
CommitLineData
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
32 #include "wx/app.h"
33 #include "wx/toplevel.h"
34 #include "wx/string.h"
35 #include "wx/log.h"
36 #include "wx/intl.h"
37 #include "wx/frame.h"
38#endif //WX_PRECOMP
39
40#include "wx/msw/private.h"
41
42#ifndef ICON_BIG
43 #define ICON_BIG 1
44#endif
45
46#ifndef ICON_SMALL
47 #define ICON_SMALL 0
48#endif
49
50// ----------------------------------------------------------------------------
51// stubs for missing functions under MicroWindows
52// ----------------------------------------------------------------------------
53
54#ifdef __WXMICROWIN__
55
56// static inline bool IsIconic(HWND WXUNUSED(hwnd)) { return FALSE; }
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
68// the name of the default wxWindows class
69extern const wxChar *wxCanvasClassName;
70
71// ============================================================================
72// wxTopLevelWindowMSW implementation
73// ============================================================================
74
75// ----------------------------------------------------------------------------
76// wxDialog helpers
77// ----------------------------------------------------------------------------
78
79// Dialog window proc
80LONG APIENTRY _EXPORT
81wxDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
82{
83 switch ( message )
84 {
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;
94 }
95}
96
97// ----------------------------------------------------------------------------
98// wxTopLevelWindowMSW creation
99// ----------------------------------------------------------------------------
100
101void wxTopLevelWindowMSW::Init()
102{
103 m_iconized =
104 m_maximizeOnShow = FALSE;
105
106 // unlike (almost?) all other windows, frames are created hidden
107 m_isShown = FALSE;
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;
114}
115
116WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const
117{
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;
124
125 // first select the kind of window being created
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
130 if ( style & wxFRAME_TOOL_WINDOW )
131 msflags |= WS_POPUP;
132 else
133 msflags |= WS_OVERLAPPED;
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;
140 else
141 msflags |= WS_POPUP;
142
143 if ( style & wxCAPTION )
144 msflags |= WS_CAPTION;
145 else
146 msflags |= WS_POPUP;
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;
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;
159
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 {
173#if !defined(__WIN16__) && !defined(__SC__)
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
186
187 if ( style & wxSTAY_ON_TOP )
188 *exflags |= WS_EX_TOPMOST;
189
190#ifdef __WIN32__
191 if ( GetExtraStyle() & wxFRAME_EX_CONTEXTHELP )
192 *exflags |= WS_EX_CONTEXTHELP;
193#endif // __WIN32__
194 }
195
196 return msflags;
197}
198
199bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate,
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();
216
217 if ( parent )
218 {
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 }
229 }
230 }
231
232 m_hWnd = (WXHWND)::CreateDialogIndirect
233 (
234 wxGetInstance(),
235 (DLGTEMPLATE*)dlgTemplate,
236 parent ? GetHwndOf(parent) : NULL,
237 (DLGPROC)wxDlgProc
238 );
239
240 if ( !m_hWnd )
241 {
242 wxFAIL_MSG(_("Failed to create dialog. Incorrect DLGTEMPLATE?"));
243
244 wxLogSysError(_("Can't create dialog using memory template"));
245
246 return FALSE;
247 }
248
249 WXDWORD exflags;
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;
283 if ( !MSWGetCreateWindowCoords(pos, size, x, y, w, h) )
284 {
285 x =
286 w = (int)CW_USEDEFAULT;
287 }
288
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 }
302
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"));
315 }
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{
332 WXDWORD exflags;
333 WXDWORD flags = MSWGetCreateWindowFlags(&exflags);
334
335 return MSWCreate(wxCanvasClassName, title, pos, size, flags, exflags);
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
360 if ( GetExtraStyle() & wxTOPLEVEL_EX_DIALOG )
361 {
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)
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
374 dlgTemplate->x = 34;
375 dlgTemplate->y = 22;
376 dlgTemplate->cx = 144;
377 dlgTemplate->cy = 75;
378
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;
389
390 bool ret = CreateDialog(dlgTemplate, title, pos, size);
391 free(dlgTemplate);
392
393 return ret;
394 }
395 else // !dialog
396 {
397 return CreateFrame(title, pos, size);
398 }
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
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
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
593// ----------------------------------------------------------------------------
594// wxTopLevelWindowMSW misc
595// ----------------------------------------------------------------------------
596
597void wxTopLevelWindowMSW::SetIcon(const wxIcon& icon)
598{
599 SetIcons( wxIconBundle( icon ) );
600}
601
602void wxTopLevelWindowMSW::SetIcons(const wxIconBundle& icons)
603{
604 wxTopLevelWindowBase::SetIcons(icons);
605
606#if defined(__WIN95__) && !defined(__WXMICROWIN__)
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 )
616 {
617 ::SendMessage( GetHwndOf( this ), WM_SETICON, ICON_BIG,
618 (LPARAM)GetHiconOf(big) );
619 }
620#endif // __WIN95__
621}
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
637 if ( ::EnableMenuItem(hmenu, SC_CLOSE,
638 MF_BYCOMMAND |
639 (enable ? MF_ENABLED : MF_GRAYED)) == -1 )
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