From: Vadim Zeitlin Date: Mon, 8 Aug 2011 09:32:42 +0000 (+0000) Subject: Added wxTopLevelWindow::MSWGetSystemMenu() method. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/ddae52629c7114da46bc6ac53874593d8eb965bd Added wxTopLevelWindow::MSWGetSystemMenu() method. Also generate events corresponding to WM_SYSCOMMAND messages for the custom items of the system menu. Add a small snippet to test the new functionality to the dialogs sample. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68596 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/changes.txt b/docs/changes.txt index 92f145027f..d467990b48 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -467,6 +467,7 @@ GTK: MSW: - Added wxGCDC(wxEnhMetaFileDC) ctor (Marcin Wojdyr). +- Added wxTopLevelWindow::MSWGetSystemMenu(). 2.9.2: (released 2011-07-05) diff --git a/include/wx/msw/toplevel.h b/include/wx/msw/toplevel.h index 52905cc32a..39756b355b 100644 --- a/include/wx/msw/toplevel.h +++ b/include/wx/msw/toplevel.h @@ -77,6 +77,19 @@ public: virtual bool CanSetTransparent(); + // MSW-specific methods + // -------------------- + + // Return the menu representing the "system" menu of the window. You can + // call wxMenu::AppendWhatever() methods on it but removing items from it + // is in general not a good idea. + // + // The pointer returned by this method belongs to the window and will be + // deleted when the window itself is, do not delete it yourself. May return + // NULL if getting the system menu failed. + wxMenu *MSWGetSystemMenu() const; + + // implementation from now on // -------------------------- @@ -214,6 +227,10 @@ private: void* m_activateInfo; #endif + // The system menu: initially NULL but can be set (once) by + // MSWGetSystemMenu(). Owned by this window. + wxMenu *m_menuSystem; + DECLARE_EVENT_TABLE() wxDECLARE_NO_COPY_CLASS(wxTopLevelWindowMSW); }; diff --git a/interface/wx/toplevel.h b/interface/wx/toplevel.h index 55be716a7d..32e09f7e6f 100644 --- a/interface/wx/toplevel.h +++ b/interface/wx/toplevel.h @@ -262,6 +262,33 @@ public: */ virtual void Maximize(bool maximize = true); + /** + MSW-specific function for accessing the system menu. + + Returns a wxMenu pointer representing the system menu of the window + under MSW. The returned wxMenu may be used, if non-@c NULL, to add + extra items to the system menu. The usual @c wxEVT_COMMAND_MENU_SELECTED + events (that can be processed using @c EVT_MENU event table macro) will + then be generated for them. All the other wxMenu methods may be used as + well but notice that they won't allow you to access any standard system + menu items (e.g. they can't be deleted or modified in any way + currently). + + Notice that because of the native system limitations the identifiers of + the items added to the system menu must be multiples of 16, otherwise + no events will be generated for them. + + The returned pointer must @em not be deleted, it is owned by the window + and will be only deleted when the window itself is destroyed. + + This function is not available in the other ports by design, any + occurrences of it in the portable code must be guarded by @code #ifdef + __WXMSW__ @endcode preprocessor guards. + + @since 2.9.3 + */ + wxMenu *MSWGetSystemMenu() const; + /** Use a system-dependent way to attract users attention to the window when it is in background. diff --git a/samples/dialogs/dialogs.cpp b/samples/dialogs/dialogs.cpp index 14f1a80318..eeeecdac1f 100644 --- a/samples/dialogs/dialogs.cpp +++ b/samples/dialogs/dialogs.cpp @@ -648,6 +648,24 @@ MyFrame::MyFrame(const wxString& title) // covers our entire client area to avoid jarring colour jumps SetOwnBackgroundColour(m_canvas->GetBackgroundColour()); #endif // wxUSE_INFOBAR + +#ifdef __WXMSW__ + // Test MSW-specific function allowing to access the "system" menu. + wxMenu * const menu = MSWGetSystemMenu(); + if ( menu ) + { + menu->AppendSeparator(); + + // The ids of the menu commands in MSW system menu must be multiple of + // 16 so we can't use DIALOGS_ABOUTDLG_SIMPLE here because it might not + // satisfy this condition and need to define and connect a separate id. + static const int DIALOGS_SYSTEM_ABOUT = 0x4010; + + menu->Append(DIALOGS_SYSTEM_ABOUT, "&About..."); + Connect(DIALOGS_SYSTEM_ABOUT, wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler(MyFrame::ShowSimpleAboutDialog)); + } +#endif // __WXMSW__ } MyFrame::~MyFrame() diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index 45ef33843b..856e761b39 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -141,6 +141,8 @@ void wxTopLevelWindowMSW::Init() m_activateInfo = (void*) info; #endif + + m_menuSystem = NULL; } WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const @@ -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); @@ -578,6 +604,8 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent, wxTopLevelWindowMSW::~wxTopLevelWindowMSW() { + delete m_menuSystem; + SendDestroyEvent(); #if defined(__SMARTPHONE__) || defined(__POCKETPC__) @@ -1226,6 +1254,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)