X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7282b0678a879077a109495cb3cd20b28ea9cf45..968c75e36684abc092623e7055e8e1f4d94194c6:/src/msw/toplevel.cpp diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index a61f3336a7..8219f12a43 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 /////////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -33,6 +33,7 @@ #include "wx/log.h" #include "wx/intl.h" #include "wx/frame.h" + #include "wx/menu.h" #include "wx/containr.h" // wxSetFocusToChild() #include "wx/module.h" #endif //WX_PRECOMP @@ -141,6 +142,8 @@ void wxTopLevelWindowMSW::Init() m_activateInfo = (void*) info; #endif + + m_menuSystem = NULL; } WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const @@ -326,9 +329,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 +358,37 @@ WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WX } break; } +#endif // __SMARTPHONE__ || __POCKETPC__ + + case WM_SYSCOMMAND: + // Keep the #ifdef block inside the case to fix a potential MSVC + // warning regarding switch statement containing no case or + // default labels (or a default only). +#ifndef __WXUNIVERSAL__ + // 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; + } + } +#endif // #ifndef __WXUNIVERSAL__ + break; } -#endif if ( !processed ) rc = wxTopLevelWindowBase::MSWWindowProc(message, wParam, lParam); @@ -403,7 +435,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, @@ -413,32 +445,33 @@ bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate, } #endif // !__WXWINCE__ + if ( !title.empty() ) + { + ::SetWindowText(GetHwnd(), title.wx_str()); + } + + SubclassWin(m_hWnd); + +#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; - } - -#if !defined(__WXWINCE__) || defined(__WINCE_STANDARDSDK__) - if ( !::MoveWindow(GetHwnd(), x, y, w, h, FALSE) ) - { - wxLogLastError(wxT("MoveWindow")); + // Let the system position the window, just set its size. + ::SetWindowPos(GetHwnd(), 0, + 0, 0, w, h, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); } -#endif - - if ( !title.empty() ) + else // Move the window to the desired location and set its size too. { - ::SetWindowText(GetHwnd(), title.wx_str()); + if ( !::MoveWindow(GetHwnd(), x, y, w, h, FALSE) ) + { + wxLogLastError(wxT("MoveWindow")); + } } - - SubclassWin(m_hWnd); +#endif // !__WXWINCE__ #ifdef __SMARTPHONE__ // Work around title non-display glitch @@ -496,8 +529,8 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent, 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 @@ -578,6 +611,8 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent, wxTopLevelWindowMSW::~wxTopLevelWindowMSW() { + delete m_menuSystem; + SendDestroyEvent(); #if defined(__SMARTPHONE__) || defined(__POCKETPC__) @@ -608,7 +643,13 @@ 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() @@ -662,6 +703,7 @@ 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) @@ -671,6 +713,7 @@ bool wxTopLevelWindowMSW::Show(bool show) // 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); @@ -701,6 +744,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 @@ -718,6 +762,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 } } @@ -733,6 +778,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 @@ -1010,6 +1062,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 @@ -1047,14 +1100,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) @@ -1069,15 +1132,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) @@ -1114,54 +1170,6 @@ bool wxTopLevelWindowMSW::EnableCloseButton(bool enable) return true; } -#ifndef __WXWINCE__ - -bool wxTopLevelWindowMSW::SetShape(const wxRegion& region) -{ - wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false, - wxT("Shaped windows must be created with the wxFRAME_SHAPED style.")); - - // The empty region signifies that the shape should be removed from the - // window. - if ( region.IsEmpty() ) - { - if (::SetWindowRgn(GetHwnd(), NULL, TRUE) == 0) - { - wxLogLastError(wxT("SetWindowRgn")); - return false; - } - return true; - } - - // Windows takes ownership of the region, so - // we'll have to make a copy of the region to give to it. - DWORD noBytes = ::GetRegionData(GetHrgnOf(region), 0, NULL); - RGNDATA *rgnData = (RGNDATA*) new char[noBytes]; - ::GetRegionData(GetHrgnOf(region), noBytes, rgnData); - HRGN hrgn = ::ExtCreateRegion(NULL, noBytes, rgnData); - delete[] (char*) rgnData; - - // SetWindowRgn expects the region to be in coordinants - // relative to the window, not the client area. Figure - // out the offset, if any. - RECT rect; - DWORD dwStyle = ::GetWindowLong(GetHwnd(), GWL_STYLE); - DWORD dwExStyle = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE); - ::GetClientRect(GetHwnd(), &rect); - ::AdjustWindowRectEx(&rect, dwStyle, ::GetMenu(GetHwnd()) != NULL, dwExStyle); - ::OffsetRgn(hrgn, -rect.left, -rect.top); - - // Now call the shape API with the new region. - if (::SetWindowRgn(GetHwnd(), hrgn, TRUE) == 0) - { - wxLogLastError(wxT("SetWindowRgn")); - return false; - } - return true; -} - -#endif // !__WXWINCE__ - void wxTopLevelWindowMSW::RequestUserAttention(int flags) { // check if we can use FlashWindowEx(): unfortunately a simple test for @@ -1211,6 +1219,41 @@ void wxTopLevelWindowMSW::RequestUserAttention(int flags) } } +wxMenu *wxTopLevelWindowMSW::MSWGetSystemMenu() const +{ +#ifndef __WXUNIVERSAL__ + 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); + } +#endif // #ifndef __WXUNIVERSAL__ + + return m_menuSystem; +} + +// ---------------------------------------------------------------------------- +// Transparency support // --------------------------------------------------------------------------- bool wxTopLevelWindowMSW::SetTransparent(wxByte alpha) @@ -1272,6 +1315,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() {