X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9a83f860948059b0273b5cc6d9e43fadad3ebfca..b404a8f3b072129c107c6d9a5e0f6f53cd34807b:/src/msw/toplevel.cpp diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index 274bc888c9..9e068789c8 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -6,7 +6,7 @@ // Created: 24.09.01 // RCS-ID: $Id$ // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com) -// License: wxWindows licence +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -141,6 +141,8 @@ void wxTopLevelWindowMSW::Init() m_activateInfo = (void*) info; #endif + + m_menuSystem = NULL; } WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const @@ -225,7 +227,7 @@ WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const msflags |= WS_MAXIMIZE; // Keep this here because it saves recoding this function in wxTinyFrame - if ( style & (wxTINY_CAPTION_VERT | wxTINY_CAPTION_HORIZ) ) + if ( style & wxTINY_CAPTION ) msflags |= WS_CAPTION; if ( exflags ) @@ -326,9 +328,9 @@ WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WX WXLRESULT rc = 0; bool processed = false; -#if defined(__SMARTPHONE__) || defined(__POCKETPC__) switch ( message ) { +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) case WM_ACTIVATE: { SHACTIVATEINFO* info = (SHACTIVATEINFO*) m_activateInfo; @@ -355,8 +357,32 @@ WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WX } break; } +#endif // __SMARTPHONE__ || __POCKETPC__ + + case WM_SYSCOMMAND: + // We may need to generate events for the items added to the system + // menu if it had been created (and presumably modified). + if ( m_menuSystem ) + { + // From MSDN: + // + // ... the four low-order bits of the wParam parameter are + // used internally by the system. To obtain the correct + // result when testing the value of wParam, an application + // must combine the value 0xFFF0 with the wParam value by + // using the bitwise AND operator. + unsigned id = wParam & 0xfff0; + + // SC_SIZE is the first of the system-defined commands and we + // leave those to DefWindowProc(). + if ( id < SC_SIZE ) + { + if ( m_menuSystem->MSWCommand(0 /* unused anyhow */, id) ) + processed = true; + } + } + break; } -#endif if ( !processed ) rc = wxTopLevelWindowBase::MSWWindowProc(message, wParam, lParam); @@ -375,8 +401,7 @@ bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate, #else // !__WXMICROWIN__ // static cast is valid as we're only ever called for dialogs wxWindow * const - parent = static_cast(this)-> - GetParentForModalDialog(GetParent()); + parent = static_cast(this)->GetParentForModalDialog(); m_hWnd = (WXHWND)::CreateDialogIndirect ( @@ -404,7 +429,7 @@ bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate, if ( winTop ) { wxIcon icon = winTop->GetIcon(); - if ( icon.Ok() ) + if ( icon.IsOk() ) { ::SendMessage(GetHwnd(), WM_SETICON, (WPARAM)TRUE, @@ -414,25 +439,26 @@ bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate, } #endif // !__WXWINCE__ +#if !defined(__WXWINCE__) || defined(__WINCE_STANDARDSDK__) // move the dialog to its initial position without forcing repainting int x, y, w, h; (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h); if ( x == (int)CW_USEDEFAULT ) { - // centre it on the screen - what else can we do? - wxSize sizeDpy = wxGetDisplaySize(); - - x = (sizeDpy.x - w) / 2; - y = (sizeDpy.y - h) / 2; + // Let the system position the window, just set its size. + ::SetWindowPos(GetHwnd(), 0, + 0, 0, w, h, + SWP_NOMOVE | SWP_NOZORDER); } - -#if !defined(__WXWINCE__) || defined(__WINCE_STANDARDSDK__) - if ( !::MoveWindow(GetHwnd(), x, y, w, h, FALSE) ) + else // Move the window to the desired location and set its size too. { - wxLogLastError(wxT("MoveWindow")); + if ( !::MoveWindow(GetHwnd(), x, y, w, h, FALSE) ) + { + wxLogLastError(wxT("MoveWindow")); + } } -#endif +#endif // !__WXWINCE__ if ( !title.empty() ) { @@ -476,30 +502,29 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent, long style, const wxString& name) { - bool ret wxDUMMY_INITIALIZE(false); - wxSize sizeReal = size; if ( !sizeReal.IsFullySpecified() ) { sizeReal.SetDefaults(GetDefaultSize()); } - m_windowStyle = style; - - SetName(name); - - m_windowId = id == wxID_ANY ? NewControlId() : id; - + // notice that we should append this window to wxTopLevelWindows list + // before calling CreateBase() as it behaves differently for TLW and + // non-TLW windows wxTopLevelWindows.Append(this); + bool ret = CreateBase(parent, id, pos, sizeReal, style, name); + if ( !ret ) + return false; + if ( parent ) parent->AddChild(this); if ( GetExtraStyle() & wxTOPLEVEL_EX_DIALOG ) { // we have different dialog templates to allows creation of dialogs - // with & without captions under MSWindows, resizeable or not (but a - // resizeable dialog always has caption - otherwise it would look too + // with & without captions under MSWindows, resizable or not (but a + // resizable dialog always has caption - otherwise it would look too // strange) // we need 3 additional WORDs for dialog menu, class and title (as we @@ -580,6 +605,8 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent, wxTopLevelWindowMSW::~wxTopLevelWindowMSW() { + delete m_menuSystem; + SendDestroyEvent(); #if defined(__SMARTPHONE__) || defined(__POCKETPC__) @@ -610,7 +637,21 @@ void wxTopLevelWindowMSW::DoShowWindow(int nShowCmd) { ::ShowWindow(GetHwnd(), nShowCmd); - m_iconized = nShowCmd == SW_MINIMIZE; + // Hiding the window doesn't change its iconized state. + if ( nShowCmd != SW_HIDE ) + { + // Otherwise restoring, maximizing or showing the window normally also + // makes it not iconized and only minimizing it does make it iconized. + m_iconized = nShowCmd == SW_MINIMIZE; + } +} + +void wxTopLevelWindowMSW::ShowWithoutActivating() +{ + if ( !wxWindowBase::Show(true) ) + return; + + DoShowWindow(SW_SHOWNA); } bool wxTopLevelWindowMSW::Show(bool show) @@ -656,6 +697,18 @@ bool wxTopLevelWindowMSW::Show(bool show) nShowCmd = SW_HIDE; } +#if wxUSE_DEFERRED_SIZING + // we only set pending size if we're maximized before being shown, now that + // we're shown we don't need it any more (it is reset in size event handler + // for child windows but we have to do it ourselves for this parent window) + // + // make sure to reset it before actually showing the window as this will + // generate WM_SIZE events and we want to use the correct client size from + // them, not the size returned by WM_NCCALCSIZE in DoGetClientSize() which + // turns out to be wrong for maximized windows (see #11762) + m_pendingSize = wxDefaultSize; +#endif // wxUSE_DEFERRED_SIZING + DoShowWindow(nShowCmd); #if defined(__WXWINCE__) && (_WIN32_WCE >= 400 && !defined(__POCKETPC__) && !defined(__SMARTPHONE__)) @@ -665,11 +718,6 @@ bool wxTopLevelWindowMSW::Show(bool show) frame->GetMenuBar()->AddAdornments(GetWindowStyleFlag()); #endif - // we only set pending size if we're maximized before being shown, now that - // we're shown we don't need it any more (it is reset in size event handler - // for child windows but we have to do it ourselves for this parent window) - m_pendingSize = wxDefaultSize; - return true; } @@ -690,6 +738,7 @@ void wxTopLevelWindowMSW::Maximize(bool maximize) // so just remember that we should do it later in this case m_maximizeOnShow = maximize; +#if wxUSE_DEFERRED_SIZING // after calling Maximize() the client code expects to get the frame // "real" size and doesn't want to know that, because of implementation // details, the frame isn't really maximized yet but will be only once @@ -707,6 +756,7 @@ void wxTopLevelWindowMSW::Maximize(bool maximize) m_pendingSize = wxGetClientDisplayRect().GetSize(); } //else: can't do anything in this case, we don't have the old size +#endif // wxUSE_DEFERRED_SIZING } } @@ -722,6 +772,13 @@ bool wxTopLevelWindowMSW::IsMaximized() const void wxTopLevelWindowMSW::Iconize(bool iconize) { + if ( iconize == m_iconized ) + { + // Do nothing, in particular don't restore non-iconized windows when + // Iconize(false) is called as this would wrongly un-maximize them. + return; + } + if ( IsShown() ) { // change the window state immediately @@ -838,6 +895,72 @@ void wxTopLevelWindowMSW::DoGetSize(int *width, int *height) const #endif // __WXWINCE__ +void +wxTopLevelWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, + const wxSize& size, + int& x, int& y, + int& w, int& h) const +{ + // let the system position the window if no explicit position was specified + if ( pos.x == wxDefaultCoord ) + { + // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we + // can just as well set it to CW_USEDEFAULT as well + x = + y = CW_USEDEFAULT; + } + else + { + // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it + // neither because it is not handled as a special value by Windows then + // and so we have to choose some default value for it, even if a + // completely arbitrary one + static const int DEFAULT_Y = 200; + + x = pos.x; + y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y; + } + + if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord ) + { + // We don't use CW_USEDEFAULT here for several reasons: + // + // 1. It results in huge frames on modern screens (1000*800 is not + // uncommon on my 1280*1024 screen) which is way too big for a half + // empty frame of most of wxWidgets samples for example) + // + // 2. It is buggy for frames with wxFRAME_TOOL_WINDOW style for which + // the default is for whatever reason 8*8 which breaks client <-> + // window size calculations (it would be nice if it didn't, but it + // does and the simplest way to fix it seemed to change the broken + // default size anyhow) + // + // 3. There is just no advantage in doing it: with x and y it is + // possible that [future versions of] Windows position the new top + // level window in some smart way which we can't do, but we can + // guess a reasonably good size for a new window just as well + // ourselves + // + // The only exception is for the Windows CE platform where the system + // does know better than we how should the windows be sized +#ifdef _WIN32_WCE + w = + h = CW_USEDEFAULT; +#else // !_WIN32_WCE + wxSize sizeReal = size; + sizeReal.SetDefaults(GetDefaultSize()); + + w = sizeReal.x; + h = sizeReal.y; +#endif // _WIN32_WCE/!_WIN32_WCE + } + else + { + w = size.x; + h = size.y; + } +} + // ---------------------------------------------------------------------------- // wxTopLevelWindowMSW fullscreen // ---------------------------------------------------------------------------- @@ -933,6 +1056,7 @@ bool wxTopLevelWindowMSW::ShowFullScreen(bool show, long style) // finally send an event allowing the window to relayout itself &c wxSizeEvent event(rect.GetSize(), GetId()); + event.SetEventObject(this); HandleWindowEvent(event); } else // stop showing full screen @@ -970,14 +1094,24 @@ bool wxTopLevelWindowMSW::DoSelectAndSetIcon(const wxIconBundle& icons, { const wxSize size(::GetSystemMetrics(smX), ::GetSystemMetrics(smY)); - const wxIcon icon = icons.GetIconOfExactSize(size); - if ( icon.Ok() ) + // Try the exact size first. + wxIcon icon = icons.GetIconOfExactSize(size); + + if ( !icon.IsOk() ) { - ::SendMessage(GetHwnd(), WM_SETICON, i, (LPARAM)GetHiconOf(icon)); - return true; + // If we didn't find any, set at least some icon: it will look scaled + // and ugly but in practice it's impossible to prevent this because not + // everyone can provide the icons in all sizes used by all versions of + // Windows in all DPIs (this would include creating them in at least + // 14, 16, 22, 32, 48, 64 and 128 pixel sizes). + icon = icons.GetIcon(size); } - return false; + if ( !icon.IsOk() ) + return false; + + ::SendMessage(GetHwnd(), WM_SETICON, i, (LPARAM)GetHiconOf(icon)); + return true; } void wxTopLevelWindowMSW::SetIcons(const wxIconBundle& icons) @@ -992,15 +1126,8 @@ void wxTopLevelWindowMSW::SetIcons(const wxIconBundle& icons) return; } - bool anySet = - DoSelectAndSetIcon(icons, SM_CXSMICON, SM_CYSMICON, ICON_SMALL); - if ( DoSelectAndSetIcon(icons, SM_CXICON, SM_CYICON, ICON_BIG) ) - anySet = true; - - if ( !anySet ) - { - wxFAIL_MSG( "icon bundle doesn't contain any suitable icon" ); - } + DoSelectAndSetIcon(icons, SM_CXSMICON, SM_CYSMICON, ICON_SMALL); + DoSelectAndSetIcon(icons, SM_CXICON, SM_CYICON, ICON_BIG); } bool wxTopLevelWindowMSW::EnableCloseButton(bool enable) @@ -1134,6 +1261,39 @@ void wxTopLevelWindowMSW::RequestUserAttention(int flags) } } +wxMenu *wxTopLevelWindowMSW::MSWGetSystemMenu() const +{ + if ( !m_menuSystem ) + { + HMENU hmenu = ::GetSystemMenu(GetHwnd(), FALSE); + if ( !hmenu ) + { + wxLogLastError(wxT("GetSystemMenu()")); + return NULL; + } + + wxTopLevelWindowMSW * const + self = const_cast(this); + + self->m_menuSystem = wxMenu::MSWNewFromHMENU(hmenu); + + // We need to somehow associate this menu with this window to ensure + // that we get events from it. A natural idea would be to pretend that + // it's attached to our menu bar but this wouldn't work if we don't + // have any menu bar which is a common case for applications using + // custom items in the system menu (they mostly do it exactly because + // they don't have any other menus). + // + // So reuse the invoking window pointer instead, this is not exactly + // correct but doesn't seem to have any serious drawbacks. + m_menuSystem->SetInvokingWindow(self); + } + + return m_menuSystem; +} + +// ---------------------------------------------------------------------------- +// Transparency support // --------------------------------------------------------------------------- bool wxTopLevelWindowMSW::SetTransparent(wxByte alpha) @@ -1195,6 +1355,17 @@ bool wxTopLevelWindowMSW::CanSetTransparent() return (os_type == wxOS_WINDOWS_NT && ver_major >= 5); } +void wxTopLevelWindowMSW::DoEnable(bool enable) +{ + wxTopLevelWindowBase::DoEnable(enable); + + // Enabling or disabling a window may change its appearance. Unfortunately, + // in at least some situation, toplevel windows don't repaint themselves, + // so we have to issue explicit refresh to avoid rendering artifacts. + // + // TODO: find out just what exactly is wrong here + Refresh(); +} void wxTopLevelWindowMSW::DoFreeze() {