From 5acec1124566f6e3c16e29f1c29c4ff5e1b88d3a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 1 Apr 2007 12:07:00 +0000 Subject: [PATCH] added a generic mechanism for registering global handlers for custom windows messages and use it in wxFindReplaceDialog instead of subclassing the parent window, this solves the problem with having 2 find dialogs with the same parent (replaces patch 1447739) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45196 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/window.h | 23 +++++ src/msw/fdrepdlg.cpp | 201 +++++++++++++++++----------------------- src/msw/window.cpp | 41 ++++++++ 3 files changed, 147 insertions(+), 118 deletions(-) diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h index 8f846c2c9f..4e758ba9cd 100644 --- a/include/wx/msw/window.h +++ b/include/wx/msw/window.h @@ -148,6 +148,29 @@ public: // does this window have deferred position and/or size? bool IsSizeDeferred() const; + // these functions allow to register a global handler for the given Windows + // message: it will be called from MSWWindowProc() of any window which gets + // this event if it's not processed before (i.e. unlike a hook procedure it + // does not override the normal processing) + // + // notice that if you want to process a message for a given window only you + // should override its MSWWindowProc() instead + + // type of the handler: it is called with the message parameters (except + // that the window object is passed instead of window handle) and should + // return true if it handled the message or false if it should be passed to + // DefWindowProc() + typedef bool (*MSWMessageHandler)(wxWindow *win, + WXUINT nMsg, + WXWPARAM wParam, + WXLPARAM lParam); + + // install a handler, shouldn't be called more than one for the same message + static bool MSWRegisterMessageHandler(int msg, MSWMessageHandler handler); + + // unregister a previously registered handler + static void MSWUnregisterMessageHandler(int msg, MSWMessageHandler handler); + // implementation from now on // ========================== diff --git a/src/msw/fdrepdlg.cpp b/src/msw/fdrepdlg.cpp index 1c2006f35d..c1f7176452 100644 --- a/src/msw/fdrepdlg.cpp +++ b/src/msw/fdrepdlg.cpp @@ -40,9 +40,6 @@ // functions prototypes // ---------------------------------------------------------------------------- -LRESULT CALLBACK wxFindReplaceWindowProc(HWND hwnd, WXUINT nMsg, - WPARAM wParam, LPARAM lParam); - UINT_PTR CALLBACK wxFindReplaceDialogHookProc(HWND hwnd, UINT uiMsg, WPARAM wParam, @@ -67,10 +64,6 @@ public: void InitFindWhat(const wxString& str); void InitReplaceWith(const wxString& str); - void SubclassDialog(HWND hwnd); - - static UINT GetFindDialogMessage() { return ms_msgFindDialog; } - // only for passing to ::FindText or ::ReplaceText FINDREPLACE *GetPtrFindReplace() { return &m_findReplace; } @@ -79,13 +72,15 @@ public: bool WasClosedByUser() const { return m_wasClosedByUser; } private: - void InitString(const wxString& str, LPTSTR *ppStr, WORD *pLen); + // called from window procedure for ms_msgFindDialog + static bool FindMessageHandler(wxWindow *win, + WXUINT nMsg, + WPARAM wParam, + LPARAM lParam); - // the owner of the dialog - HWND m_hwndOwner; + // copy string str contents to ppStr and fill pLen with its length + void InitString(const wxString& str, LPTSTR *ppStr, WORD *pLen); - // the previous window proc of our owner - WNDPROC m_oldParentWndProc; // the find replace data used by the dialog FINDREPLACE m_findReplace; @@ -121,10 +116,13 @@ wxFindReplaceDialogImpl::wxFindReplaceDialogImpl(wxFindReplaceDialog *dialog, { wxLogLastError(_T("RegisterWindowMessage(FINDMSGSTRING)")); } - } - m_hwndOwner = NULL; - m_oldParentWndProc = NULL; + wxWindow::MSWRegisterMessageHandler + ( + ms_msgFindDialog, + &wxFindReplaceDialogImpl::FindMessageHandler + ); + } m_wasClosedByUser = false; @@ -186,40 +184,21 @@ void wxFindReplaceDialogImpl::InitReplaceWith(const wxString& str) &m_findReplace.wReplaceWithLen); } -void wxFindReplaceDialogImpl::SubclassDialog(HWND hwnd) -{ - m_hwndOwner = hwnd; - - // check that we don't subclass the parent twice: this would be a bad idea - // as then we'd have infinite recursion in wxFindReplaceWindowProc - wxCHECK_RET( wxGetWindowProc(hwnd) != &wxFindReplaceWindowProc, - _T("can't have more than one find dialog currently") ); - - // set the new one and save the old as user data to allow access to it - // from wxFindReplaceWindowProc - m_oldParentWndProc = wxSetWindowProc(hwnd, wxFindReplaceWindowProc); - - wxSetWindowUserData(hwnd, (void *)m_oldParentWndProc); -} - wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl() { delete [] m_findReplace.lpstrFindWhat; delete [] m_findReplace.lpstrReplaceWith; - - if ( m_hwndOwner ) - { - // undo subclassing - wxSetWindowProc(m_hwndOwner, m_oldParentWndProc); - } } // ---------------------------------------------------------------------------- -// Window Proc for handling RegisterWindowMessage(FINDMSGSTRING) +// handler for FINDMSGSTRING message // ---------------------------------------------------------------------------- -LRESULT CALLBACK wxFindReplaceWindowProc(HWND hwnd, WXUINT nMsg, - WPARAM wParam, LPARAM lParam) +bool +wxFindReplaceDialogImpl::FindMessageHandler(wxWindow * WXUNUSED(win), + WXUINT WXUNUSED_UNLESS_DEBUG(nMsg), + WPARAM WXUNUSED(wParam), + LPARAM lParam) { #if wxUSE_UNICODE_MSLU static unsigned long s_lastMsgFlags = 0; @@ -231,100 +210,89 @@ LRESULT CALLBACK wxFindReplaceWindowProc(HWND hwnd, WXUINT nMsg, static bool s_blockMsg = false; #endif // wxUSE_UNICODE_MSLU - if ( nMsg == wxFindReplaceDialogImpl::GetFindDialogMessage() ) - { - FINDREPLACE *pFR = (FINDREPLACE *)lParam; + wxASSERT_MSG( nMsg == ms_msgFindDialog, _T("unexpected message received") ); + + FINDREPLACE *pFR = (FINDREPLACE *)lParam; #if wxUSE_UNICODE_MSLU - // This is a hack for a MSLU problem: Versions up to 1.0.4011 - // of UNICOWS.DLL send the correct UNICODE item after button press - // and a bogus ANSI mode item right after this, so lets ignore - // the second bogus message - if ( wxUsingUnicowsDll() && s_lastMsgFlags == pFR->Flags ) - { - s_lastMsgFlags = 0; - return 0; - } - s_lastMsgFlags = pFR->Flags; + // This is a hack for a MSLU problem: Versions up to 1.0.4011 + // of UNICOWS.DLL send the correct UNICODE item after button press + // and a bogus ANSI mode item right after this, so lets ignore + // the second bogus message + if ( wxUsingUnicowsDll() && s_lastMsgFlags == pFR->Flags ) + { + s_lastMsgFlags = 0; + return 0; + } + s_lastMsgFlags = pFR->Flags; #endif // wxUSE_UNICODE_MSLU - wxFindReplaceDialog *dialog = (wxFindReplaceDialog *)pFR->lCustData; + wxFindReplaceDialog *dialog = (wxFindReplaceDialog *)pFR->lCustData; - // map flags from Windows - wxEventType evtType; + // map flags from Windows + wxEventType evtType; - bool replace = false; - if ( pFR->Flags & FR_DIALOGTERM ) - { - // we have to notify the dialog that it's being closed by user and - // not deleted programmatically as it behaves differently in these - // 2 cases - dialog->GetImpl()->SetClosedByUser(); + bool replace = false; + if ( pFR->Flags & FR_DIALOGTERM ) + { + // we have to notify the dialog that it's being closed by user and + // not deleted programmatically as it behaves differently in these + // 2 cases + dialog->GetImpl()->SetClosedByUser(); - evtType = wxEVT_COMMAND_FIND_CLOSE; - } - else if ( pFR->Flags & FR_FINDNEXT ) - { - evtType = wxEVT_COMMAND_FIND_NEXT; - } - else if ( pFR->Flags & FR_REPLACE ) - { - evtType = wxEVT_COMMAND_FIND_REPLACE; + evtType = wxEVT_COMMAND_FIND_CLOSE; + } + else if ( pFR->Flags & FR_FINDNEXT ) + { + evtType = wxEVT_COMMAND_FIND_NEXT; + } + else if ( pFR->Flags & FR_REPLACE ) + { + evtType = wxEVT_COMMAND_FIND_REPLACE; - replace = true; - } - else if ( pFR->Flags & FR_REPLACEALL ) - { - evtType = wxEVT_COMMAND_FIND_REPLACE_ALL; + replace = true; + } + else if ( pFR->Flags & FR_REPLACEALL ) + { + evtType = wxEVT_COMMAND_FIND_REPLACE_ALL; - replace = true; - } - else - { - wxFAIL_MSG( _T("unknown find dialog event") ); + replace = true; + } + else + { + wxFAIL_MSG( _T("unknown find dialog event") ); - return 0; - } + return 0; + } - wxUint32 flags = 0; - if ( pFR->Flags & FR_DOWN ) - flags |= wxFR_DOWN; - if ( pFR->Flags & FR_WHOLEWORD ) - flags |= wxFR_WHOLEWORD; - if ( pFR->Flags & FR_MATCHCASE ) - flags |= wxFR_MATCHCASE; - - wxFindDialogEvent event(evtType, dialog->GetId()); - event.SetEventObject(dialog); - event.SetFlags(flags); - event.SetFindString(pFR->lpstrFindWhat); - if ( replace ) - { - event.SetReplaceString(pFR->lpstrReplaceWith); - } + wxUint32 flags = 0; + if ( pFR->Flags & FR_DOWN ) + flags |= wxFR_DOWN; + if ( pFR->Flags & FR_WHOLEWORD ) + flags |= wxFR_WHOLEWORD; + if ( pFR->Flags & FR_MATCHCASE ) + flags |= wxFR_MATCHCASE; + + wxFindDialogEvent event(evtType, dialog->GetId()); + event.SetEventObject(dialog); + event.SetFlags(flags); + event.SetFindString(pFR->lpstrFindWhat); + if ( replace ) + { + event.SetReplaceString(pFR->lpstrReplaceWith); + } #if wxUSE_UNICODE_MSLU - s_blockMsg = true; + s_blockMsg = true; #endif // wxUSE_UNICODE_MSLU - dialog->Send(event); + dialog->Send(event); #if wxUSE_UNICODE_MSLU - s_blockMsg = false; -#endif // wxUSE_UNICODE_MSLU - } -#if wxUSE_UNICODE_MSLU - else if ( !s_blockMsg ) - s_lastMsgFlags = 0; + s_blockMsg = false; #endif // wxUSE_UNICODE_MSLU - WNDPROC wndProc = (WNDPROC)wxGetWindowUserData(hwnd); - - // sanity check - wxASSERT_MSG( wndProc != wxFindReplaceWindowProc, - _T("infinite recursion detected") ); - - return ::CallWindowProc(wndProc, hwnd, nMsg, wParam, lParam); + return true; } // ---------------------------------------------------------------------------- @@ -478,9 +446,6 @@ bool wxFindReplaceDialog::Show(bool show) return false; } - // subclass parent window in order to get FINDMSGSTRING message - m_impl->SubclassDialog(GetHwndOf(m_parent)); - if ( !::ShowWindow(hwnd, SW_SHOW) ) { wxLogLastError(_T("ShowWindow(find dialog)")); diff --git a/src/msw/window.cpp b/src/msw/window.cpp index a7ea67d2bb..0d5c841090 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -57,6 +57,7 @@ #include "wx/ownerdrw.h" #endif +#include "wx/hashmap.h" #include "wx/evtloop.h" #include "wx/power.h" #include "wx/sysopt.h" @@ -172,6 +173,13 @@ static struct MouseEventInfoDummy } gs_lastMouseEvent; #endif // wxUSE_MOUSEEVENT_HACK +// hash containing the registered handlers for the custom messages +WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler, + wxIntegerHash, wxIntegerEqual, + MSWMessageHandlers); + +static MSWMessageHandlers gs_messageHandlers; + // --------------------------------------------------------------------------- // private functions // --------------------------------------------------------------------------- @@ -3173,6 +3181,15 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l } break; #endif // __WXWINCE__ + + default: + // try a custom message handler + const MSWMessageHandlers::const_iterator + i = gs_messageHandlers.find(message); + if ( i != gs_messageHandlers.end() ) + { + processed = (*i->second)(this, message, wParam, lParam); + } } if ( !processed ) @@ -5439,6 +5456,30 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, return GetEventHandler()->ProcessEvent(event); } +// ---------------------------------------------------------------------------- +// custom message handlers +// ---------------------------------------------------------------------------- + +/* static */ bool +wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler) +{ + wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(), + false, _T("registering handler for the same message twice") ); + + gs_messageHandlers[msg] = handler; + return true; +} + +/* static */ void +wxWindowMSW::MSWUnregisterMessageHandler(int msg, MSWMessageHandler handler) +{ + const MSWMessageHandlers::iterator i = gs_messageHandlers.find(msg); + wxCHECK_RET( i != gs_messageHandlers.end() && i->second == handler, + _T("unregistering non-registered handler?") ); + + gs_messageHandlers.erase(i); +} + // =========================================================================== // global functions // =========================================================================== -- 2.45.2