]> git.saurik.com Git - wxWidgets.git/commitdiff
added a generic mechanism for registering global handlers for custom windows messages...
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 1 Apr 2007 12:07:00 +0000 (12:07 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 1 Apr 2007 12:07:00 +0000 (12:07 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45196 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/msw/window.h
src/msw/fdrepdlg.cpp
src/msw/window.cpp

index 8f846c2c9f363f5e12c5ebc6a2be6f3d0e440b51..4e758ba9cdcbd0bab7c12577b0437f606ab43b5d 100644 (file)
@@ -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
     // ==========================
index 1c2006f35d934f86a4ee01efe55cd04bee0d18ac..c1f71764521e01ad189c9d7ba56a41af3f67b1eb 100644 (file)
@@ -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)"));
index a7ea67d2bb89c7e837df73f071df07296b858cee..0d5c841090a0e40908211d6237c6e6a714526c68 100644 (file)
@@ -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
 // ===========================================================================