1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        msw/toplevel.cpp 
   3 // Purpose:     implements wxTopLevelWindow for MSW 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 2001 SciTech Software, Inc. (www.scitechsoft.com) 
   9 // License:     wxWindows license 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  21     #pragma implementation "toplevel.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  33     #include "wx/toplevel.h" 
  34     #include "wx/string.h" 
  40 #include "wx/msw/private.h" 
  50 // ---------------------------------------------------------------------------- 
  51 // stubs for missing functions under MicroWindows 
  52 // ---------------------------------------------------------------------------- 
  56 // static inline bool IsIconic(HWND WXUNUSED(hwnd)) { return FALSE; } 
  57 static inline bool IsZoomed(HWND 
WXUNUSED(hwnd
)) { return FALSE
; } 
  59 #endif // __WXMICROWIN__ 
  61 // ---------------------------------------------------------------------------- 
  63 // ---------------------------------------------------------------------------- 
  65 // list of all frames and modeless dialogs 
  66 wxWindowList wxModelessWindows
; 
  68 // the name of the default wxWindows class 
  69 extern const wxChar 
*wxCanvasClassName
; 
  71 // ============================================================================ 
  72 // wxTopLevelWindowMSW implementation 
  73 // ============================================================================ 
  75 // ---------------------------------------------------------------------------- 
  77 // ---------------------------------------------------------------------------- 
  81 wxDlgProc(HWND hDlg
, UINT message
, WPARAM wParam
, LPARAM lParam
) 
  86             // for this message, returning TRUE tells system to set focus to the 
  87             // first control in the dialog box 
  91             // for all the other ones, FALSE means that we didn't process the 
  97 // ---------------------------------------------------------------------------- 
  98 // wxTopLevelWindowMSW creation 
  99 // ---------------------------------------------------------------------------- 
 101 void wxTopLevelWindowMSW::Init() 
 104     m_maximizeOnShow 
= FALSE
; 
 106     // unlike (almost?) all other windows, frames are created hidden 
 109     // Data to save/restore when calling ShowFullScreen 
 111     m_fsOldWindowStyle 
= 0; 
 112     m_fsIsMaximized 
= FALSE
; 
 113     m_fsIsShowing 
= FALSE
; 
 116 WXDWORD 
wxTopLevelWindowMSW::MSWGetStyle(long style
, WXDWORD 
*exflags
) const 
 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
 
 122                         (style 
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exflags
 
 125     // first select the kind of window being created 
 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 
) 
 133         msflags 
|= WS_OVERLAPPED
; 
 135     // border and caption styles 
 136     if ( style 
& wxRESIZE_BORDER 
) 
 137         msflags 
|= WS_THICKFRAME
; 
 138     else if ( !(style 
& wxBORDER_NONE
) ) 
 139         msflags 
|= WS_BORDER
; 
 143     if ( style 
& wxCAPTION 
) 
 144         msflags 
|= WS_CAPTION
; 
 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
; 
 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
; 
 167     if ( style 
& (wxTINY_CAPTION_VERT 
| wxTINY_CAPTION_HORIZ
) ) 
 168         msflags 
|= WS_CAPTION
; 
 173 #if !defined(__WIN16__) && !defined(__SC__) 
 174         if ( !(GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
) ) 
 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
; 
 187         if ( style 
& wxSTAY_ON_TOP 
) 
 188             *exflags 
|= WS_EX_TOPMOST
; 
 191         if ( GetExtraStyle() & wxFRAME_EX_CONTEXTHELP 
) 
 192             *exflags 
|= WS_EX_CONTEXTHELP
; 
 199 bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate
, 
 200                                        const wxString
& title
, 
 204 #ifdef __WXMICROWIN__ 
 205     // no dialogs support under MicroWin yet 
 206     return CreateFrame(title
, pos
, size
); 
 207 #else // !__WXMICROWIN__ 
 208     wxWindow 
*parent 
= GetParent(); 
 210     // for the dialogs without wxDIALOG_NO_PARENT style, use the top level 
 211     // app window as parent - this avoids creating modal dialogs without 
 213     if ( !parent 
&& !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT
) ) 
 215         parent 
= wxTheApp
->GetTopWindow(); 
 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 
 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
) || 
 232     m_hWnd 
= (WXHWND
)::CreateDialogIndirect
 
 235                         (DLGTEMPLATE
*)dlgTemplate
, 
 236                         parent 
? GetHwndOf(parent
) : NULL
, 
 242         wxFAIL_MSG(_("Failed to create dialog. Incorrect DLGTEMPLATE?")); 
 244         wxLogSysError(_("Can't create dialog using memory template")); 
 250     (void)MSWGetCreateWindowFlags(&exflags
); 
 254         ::SetWindowLong(GetHwnd(), GWL_EXSTYLE
, exflags
); 
 255         ::SetWindowPos(GetHwnd(), NULL
, 0, 0, 0, 0, 
 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 
) 
 267         wxFrame 
*winTop 
= wxDynamicCast(wxTheApp
->GetTopWindow(), wxFrame
); 
 270             wxIcon icon 
= winTop
->GetIcon(); 
 273                 ::SendMessage(GetHwnd(), WM_SETICON
, 
 275                               (LPARAM
)GetHiconOf(icon
)); 
 281     // move the dialog to its initial position without forcing repainting 
 283     if ( !MSWGetCreateWindowCoords(pos
, size
, x
, y
, w
, h
) ) 
 286         w 
= (int)CW_USEDEFAULT
; 
 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 
) 
 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 
 303     if ( x 
== (int)CW_USEDEFAULT 
) 
 305         // centre it on the screen - what else can we do? 
 306         wxSize sizeDpy 
= wxGetDisplaySize(); 
 308         x 
= (sizeDpy
.x 
- w
) / 2; 
 309         y 
= (sizeDpy
.y 
- h
) / 2; 
 312     if ( !::MoveWindow(GetHwnd(), x
, y
, w
, h
, FALSE
) ) 
 314         wxLogLastError(wxT("MoveWindow")); 
 317     if ( !title
.empty() ) 
 319         ::SetWindowText(GetHwnd(), title
); 
 325 #endif // __WXMICROWIN__/!__WXMICROWIN__ 
 328 bool wxTopLevelWindowMSW::CreateFrame(const wxString
& title
, 
 333     WXDWORD flags 
= MSWGetCreateWindowFlags(&exflags
); 
 335     return MSWCreate(wxCanvasClassName
, title
, pos
, size
, flags
, exflags
); 
 338 bool wxTopLevelWindowMSW::Create(wxWindow 
*parent
, 
 340                                  const wxString
& title
, 
 344                                  const wxString
& name
) 
 349     m_windowStyle 
= style
; 
 353     m_windowId 
= id 
== -1 ? NewControlId() : id
; 
 355     wxTopLevelWindows
.Append(this); 
 358         parent
->AddChild(this); 
 360     if ( GetExtraStyle() & wxTOPLEVEL_EX_DIALOG 
) 
 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 
 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
); 
 373         // these values are arbitrary, they won't be used normally anyhow 
 376         dlgTemplate
->cx 
= 144; 
 377         dlgTemplate
->cy 
= 75; 
 379         // reuse the code in MSWGetStyle() but correct the results slightly for 
 381         dlgTemplate
->style 
= MSWGetStyle(style
, NULL
); 
 383         // all dialogs are popups 
 384         dlgTemplate
->style 
|= WS_POPUP
; 
 386         // force 3D-look if necessary, it looks impossibly ugly otherwise 
 387         if ( style 
& (wxRESIZE_BORDER 
| wxCAPTION
) ) 
 388             dlgTemplate
->style 
|= DS_MODALFRAME
; 
 390         bool ret 
= CreateDialog(dlgTemplate
, title
, pos
, size
); 
 397         return CreateFrame(title
, pos
, size
); 
 401 wxTopLevelWindowMSW::~wxTopLevelWindowMSW() 
 403     wxTopLevelWindows
.DeleteObject(this); 
 405     if ( wxModelessWindows
.Find(this) ) 
 406         wxModelessWindows
.DeleteObject(this); 
 408     // If this is the last top-level window, exit. 
 409     if ( wxTheApp 
&& (wxTopLevelWindows
.Number() == 0) ) 
 411         wxTheApp
->SetTopWindow(NULL
); 
 413         if ( wxTheApp
->GetExitOnFrameDelete() ) 
 415             ::PostQuitMessage(0); 
 420 // ---------------------------------------------------------------------------- 
 421 // wxTopLevelWindowMSW showing 
 422 // ---------------------------------------------------------------------------- 
 424 void wxTopLevelWindowMSW::DoShowWindow(int nShowCmd
) 
 426     ::ShowWindow(GetHwnd(), nShowCmd
); 
 428     m_iconized 
= nShowCmd 
== SW_MINIMIZE
; 
 431 bool wxTopLevelWindowMSW::Show(bool show
) 
 433     // don't use wxWindow version as we want to call DoShowWindow() ourselves 
 434     if ( !wxWindowBase::Show(show
) ) 
 440         if ( m_maximizeOnShow 
) 
 443             nShowCmd 
= SW_MAXIMIZE
; 
 445             m_maximizeOnShow 
= FALSE
; 
 457     DoShowWindow(nShowCmd
); 
 461         ::BringWindowToTop(GetHwnd()); 
 463         wxActivateEvent 
event(wxEVT_ACTIVATE
, TRUE
, m_windowId
); 
 464         event
.SetEventObject( this ); 
 465         GetEventHandler()->ProcessEvent(event
); 
 469         // Try to highlight the correct window (the parent) 
 472             HWND hWndParent 
= GetHwndOf(GetParent()); 
 474                 ::BringWindowToTop(hWndParent
); 
 481 // ---------------------------------------------------------------------------- 
 482 // wxTopLevelWindowMSW maximize/minimize 
 483 // ---------------------------------------------------------------------------- 
 485 void wxTopLevelWindowMSW::Maximize(bool maximize
) 
 489         // just maximize it directly 
 490         DoShowWindow(maximize 
? SW_MAXIMIZE 
: SW_RESTORE
); 
 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
; 
 500 bool wxTopLevelWindowMSW::IsMaximized() const 
 502     return ::IsZoomed(GetHwnd()) != 0; 
 505 void wxTopLevelWindowMSW::Iconize(bool iconize
) 
 507     DoShowWindow(iconize 
? SW_MINIMIZE 
: SW_RESTORE
); 
 510 bool wxTopLevelWindowMSW::IsIconized() const 
 512     // also update the current state 
 513     ((wxTopLevelWindowMSW 
*)this)->m_iconized 
= ::IsIconic(GetHwnd()) != 0; 
 518 void wxTopLevelWindowMSW::Restore() 
 520     DoShowWindow(SW_RESTORE
); 
 523 // ---------------------------------------------------------------------------- 
 524 // wxTopLevelWindowMSW fullscreen 
 525 // ---------------------------------------------------------------------------- 
 527 bool wxTopLevelWindowMSW::ShowFullScreen(bool show
, long style
) 
 534         m_fsIsShowing 
= TRUE
; 
 537         // zap the frame borders 
 539         // save the 'normal' window style 
 540         m_fsOldWindowStyle 
= GetWindowLong((HWND
)GetHWND(), GWL_STYLE
); 
 542         // save the old position, width & height, maximize state 
 543         m_fsOldSize 
= GetRect(); 
 544         m_fsIsMaximized 
= IsMaximized(); 
 546         // decide which window style flags to turn off 
 547         LONG newStyle 
= m_fsOldWindowStyle
; 
 550         if (style 
& wxFULLSCREEN_NOBORDER
) 
 551             offFlags 
|= WS_BORDER 
| WS_THICKFRAME
; 
 552         if (style 
& wxFULLSCREEN_NOCAPTION
) 
 553             offFlags 
|= (WS_CAPTION 
| WS_SYSMENU
); 
 555         newStyle 
&= (~offFlags
); 
 557         // change our window style to be compatible with full-screen mode 
 558         ::SetWindowLong((HWND
)GetHWND(), GWL_STYLE
, newStyle
); 
 560         // resize to the size of the desktop 
 563         RECT rect 
= wxGetWindowRect(::GetDesktopWindow()); 
 564         width 
= rect
.right 
- rect
.left
; 
 565         height 
= rect
.bottom 
- rect
.top
; 
 567         SetSize(width
, height
); 
 569         // now flush the window style cache and actually go full-screen 
 570         SetWindowPos((HWND
)GetHWND(), HWND_TOP
, 0, 0, width
, height
, SWP_FRAMECHANGED
); 
 572         wxSizeEvent 
event(wxSize(width
, height
), GetId()); 
 573         GetEventHandler()->ProcessEvent(event
); 
 582         m_fsIsShowing 
= FALSE
; 
 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
); 
 593 // ---------------------------------------------------------------------------- 
 594 // wxTopLevelWindowMSW misc 
 595 // ---------------------------------------------------------------------------- 
 597 void wxTopLevelWindowMSW::SetIcon(const wxIcon
& icon
) 
 599     SetIcons( wxIconBundle( icon 
) ); 
 602 void wxTopLevelWindowMSW::SetIcons(const wxIconBundle
& icons
) 
 604     wxTopLevelWindowBase::SetIcons(icons
); 
 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 ) 
 610         ::SendMessage( GetHwndOf( this ), WM_SETICON
, ICON_SMALL
, 
 611                        (LPARAM
)GetHiconOf(sml
) ); 
 614     const wxIcon
& big 
= icons
.GetIcon( wxSize( 32, 32 ) ); 
 615     if( big
.Ok() && big
.GetWidth() == 32 && big
.GetHeight() == 32 ) 
 617         ::SendMessage( GetHwndOf( this ), WM_SETICON
, ICON_BIG
, 
 618                        (LPARAM
)GetHiconOf(big
) ); 
 623 bool wxTopLevelWindowMSW::EnableCloseButton(bool enable
) 
 625 #ifndef __WXMICROWIN__ 
 626     // get system (a.k.a. window) menu 
 627     HMENU hmenu 
= ::GetSystemMenu(GetHwnd(), FALSE 
/* get it */); 
 630         wxLogLastError(_T("GetSystemMenu")); 
 635     // enabling/disabling the close item from it also automatically 
 636     // disables/enables the close title bar button 
 637     if ( ::EnableMenuItem(hmenu
, SC_CLOSE
, 
 639                           (enable 
? MF_ENABLED 
: MF_GRAYED
)) == -1 ) 
 641         wxLogLastError(_T("EnableMenuItem(SC_CLOSE)")); 
 646     // update appearance immediately 
 647     if ( !::DrawMenuBar(GetHwnd()) ) 
 649         wxLogLastError(_T("DrawMenuBar")); 
 651 #endif // !__WXMICROWIN__