]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
Rework the wxCusor ctor taking wx stock number to provide as many cursors as
[wxWidgets.git] / src / msw / window.cpp
index 080310c83cbc7c13d0044690c6264258b4b6a11b..81ee66815febfc2ba445bd3f7efaadcb5fb83941 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
 // ---------------------------------------------------------------------------
@@ -484,7 +492,6 @@ void wxWindowMSW::Init()
     m_mouseInWindow = false;
     m_lastKeydownProcessed = false;
 
-    m_childrenDisabled = NULL;
     m_frozenness = 0;
 
     m_hWnd = 0;
@@ -545,8 +552,6 @@ wxWindowMSW::~wxWindowMSW()
         wxRemoveHandleAssociation(this);
     }
 
-    delete m_childrenDisabled;
-
 }
 
 // real construction (Init() must have been called before!)
@@ -648,110 +653,11 @@ wxWindow *wxWindowBase::DoFindFocus()
     return NULL;
 }
 
-bool wxWindowMSW::Enable(bool enable)
+void wxWindowMSW::DoEnable( bool enable )
 {
-    // we shouldn't really enable the window if our parent is currently
-    // disabled because under MSW this would indeed show the window in enabled
-    // state but it still wouldn't respond to the input (as its parent is
-    // disabled), so just update the internal m_childrenDisabled list in this
-    // case and our state will be really changed when the parent is enabled
-
-    // the logic above doesn't apply to top level windows, of course
-    wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
-    if ( parent && !parent->IsEnabled() && !IsEnabled() )
-    {
-        // it's a reference as we can create it below
-        wxWindowList *& disabledSiblings = parent->m_childrenDisabled;
-
-        bool rc = false;
-        if ( enable )
-        {
-            // shouldn't be disabled when the parent is reenabled
-            if ( disabledSiblings )
-            {
-                wxWindowList::compatibility_iterator
-                    i = disabledSiblings->Find(this);
-                if ( i )
-                {
-                    disabledSiblings->Erase(i);
-                    rc = true;
-                }
-            }
-            //else: nothing to do
-        }
-        else // !enable
-        {
-            // should disable this window when the parent is enabled
-            if ( !disabledSiblings )
-                disabledSiblings = new wxWindowList;
-
-            disabledSiblings->Append(this);
-        }
-
-        return rc;
-    }
-
-    if ( !wxWindowBase::Enable(enable) )
-        return false;
-
     HWND hWnd = GetHwnd();
     if ( hWnd )
         ::EnableWindow(hWnd, (BOOL)enable);
-
-    // the logic below doesn't apply to the top level windows -- otherwise
-    // showing a modal dialog would result in total greying out (and ungreying
-    // out later) of everything which would be really ugly
-    if ( IsTopLevel() )
-        return true;
-
-    // when the parent is disabled, all of its children should be disabled as
-    // well but when it is enabled back, only those of the children which
-    // hadn't been already disabled in the beginning should be enabled again,
-    // so we have to keep the list of those children
-    for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-          node;
-          node = node->GetNext() )
-    {
-        wxWindow *child = node->GetData();
-        if ( child->IsTopLevel() )
-        {
-            // the logic below doesn't apply to top level children
-            continue;
-        }
-
-        if ( enable )
-        {
-            // re-enable the child unless it had been disabled before us
-            if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
-                child->Enable();
-        }
-        else // we're being disabled
-        {
-            if ( child->IsEnabled() )
-            {
-                // disable it as children shouldn't stay enabled while the
-                // parent is not
-                child->Disable();
-            }
-            else // child already disabled, remember it
-            {
-                // have we created the list of disabled children already?
-                if ( !m_childrenDisabled )
-                    m_childrenDisabled = new wxWindowList;
-
-                m_childrenDisabled->Append(child);
-            }
-        }
-    }
-
-    if ( enable && m_childrenDisabled )
-    {
-        // we don't need this list any more, don't keep unused memory
-        delete m_childrenDisabled;
-        m_childrenDisabled = NULL;
-    }
-
-    return true;
 }
 
 bool wxWindowMSW::Show(bool show)
@@ -1020,10 +926,7 @@ void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
     RECT *pr;
     if ( prect )
     {
-        rect.left = prect->x;
-        rect.top = prect->y;
-        rect.right = prect->x + prect->width;
-        rect.bottom = prect->y + prect->height;
+        wxCopyRectToRECT(*prect, rect);
         pr = ▭
     }
     else
@@ -1561,11 +1464,7 @@ void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
         const RECT *pRect;
         if ( rect )
         {
-            mswRect.left = rect->x;
-            mswRect.top = rect->y;
-            mswRect.right = rect->x + rect->width;
-            mswRect.bottom = rect->y + rect->height;
-
+            wxCopyRectToRECT(*rect, mswRect);
             pRect = &mswRect;
         }
         else
@@ -2080,7 +1979,7 @@ void wxWindowMSW::GetTextExtent(const wxString& string,
 
     SIZE sizeRect;
     TEXTMETRIC tm;
-    ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
+    ::GetTextExtentPoint32(hdc, string.wx_str(), string.length(), &sizeRect);
     GetTextMetrics(hdc, &tm);
 
     if ( x )
@@ -2145,10 +2044,22 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
     ::ClientToScreen(hWnd, &point);
     wxCurrentPopupMenu = menu;
 #if defined(__WXWINCE__)
-    UINT flags = 0;
-#else
-    UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE;
-#endif
+    static const UINT flags = 0;
+#else // !__WXWINCE__
+    UINT flags = TPM_RIGHTBUTTON;
+    // NT4 doesn't support TPM_RECURSE and simply doesn't show the menu at all
+    // when it's use, I'm not sure about Win95/98 but prefer to err on the safe
+    // side and not to use it there neither -- modify the test if it does work
+    // on these systems
+    if ( wxGetWinVersion() >= wxWinVersion_5 )
+    {
+        // using TPM_RECURSE allows us to show a popup menu while another menu
+        // is opened which can be useful and is supported by the other
+        // platforms, so allow it under Windows too
+        flags |= TPM_RECURSE;
+    }
+#endif // __WXWINCE__/!__WXWINCE__
+
     ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
 
     // we need to do it right now as otherwise the events are never going to be
@@ -2421,7 +2332,7 @@ bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
               node = node->GetNext() )
         {
             wxWindow * const win = node->GetData();
-            if ( win->AcceptsFocus() &&
+            if ( win->CanAcceptFocus() &&
                     !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) &
                         WS_EX_CONTROLPARENT) )
             {
@@ -2553,7 +2464,7 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w
 
     LRESULT rc;
 
-    if ( wnd && wxEventLoop::AllowProcessing(wnd) )
+    if ( wnd && wxGUIEventLoop::AllowProcessing(wnd) )
         rc = wnd->MSWWindowProc(message, wParam, lParam);
     else
         rc = ::DefWindowProc(hWnd, message, wParam, lParam);
@@ -2831,7 +2742,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                     // problems, so don't do it for them (unnecessary anyhow)
                     if ( !win->IsOfStandardClass() )
                     {
-                        if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
+                        if ( message == WM_LBUTTONDOWN && win->IsFocusable() )
                             win->SetFocus();
                     }
                 }
@@ -3240,6 +3151,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
             break;
 #endif
 
+#if wxUSE_MENUS
         case WM_MENUCHAR:
             // we're only interested in our own menus, not MF_SYSMENU
             if ( HIWORD(wParam) == MF_POPUP )
@@ -3253,6 +3165,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                 }
             }
             break;
+#endif // wxUSE_MENUS
 
 #ifndef __WXWINCE__
         case WM_POWERBROADCAST:
@@ -3263,6 +3176,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 )
@@ -3449,8 +3371,8 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
     m_hWnd = (WXHWND)::CreateWindowEx
                        (
                         extendedStyle,
-                        className,
-                        title ? title : (const wxChar*)m_windowName.c_str(),
+                        className.wx_str(),
+                        title ? title : m_windowName.wx_str(),
                         style,
                         x, y, w, h,
                         (HWND)MSWGetParent(),
@@ -3570,7 +3492,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
                     (
                         CP_ACP,
                         0,                      // no flags
-                        ttip,
+                        ttip.wx_str(),
                         tipLength,
                         buf,
                         WXSIZEOF(buf) - 1
@@ -3888,63 +3810,56 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
 {
 #ifndef __WXMICROWIN__
     // the logic is as follows:
-    // -1. don't set cursor for non client area, including but not limited to
-    //     the title bar, scrollbars, &c
-    //  0. allow the user to override default behaviour by using EVT_SET_CURSOR
-    //  1. if we have the cursor set it unless wxIsBusy()
-    //  2. if we're a top level window, set some cursor anyhow
-    //  3. if wxIsBusy(), set the busy cursor, otherwise the global one
+    //  0. if we're busy, set the busy cursor (even for non client elements)
+    //  1. don't set custom cursor for non client area of enabled windows
+    //  2. ask user EVT_SET_CURSOR handler for the cursor
+    //  3. if still no cursor but we're in a TLW, set the global cursor
 
-    if ( nHitTest != HTCLIENT )
+    HCURSOR hcursor = 0;
+    if ( wxIsBusy() )
     {
-        return false;
+        hcursor = wxGetCurrentBusyCursor();
     }
+    else // not busy
+    {
+        if ( nHitTest != HTCLIENT )
+            return false;
 
-    HCURSOR hcursor = 0;
-
-    // first ask the user code - it may wish to set the cursor in some very
-    // specific way (for example, depending on the current position)
-    POINT pt;
+        // first ask the user code - it may wish to set the cursor in some very
+        // specific way (for example, depending on the current position)
+        POINT pt;
 #ifdef __WXWINCE__
-    if ( !::GetCursorPosWinCE(&pt))
+        if ( !::GetCursorPosWinCE(&pt))
 #else
-    if ( !::GetCursorPos(&pt) )
+        if ( !::GetCursorPos(&pt) )
 #endif
-    {
-        wxLogLastError(wxT("GetCursorPos"));
-    }
-
-    int x = pt.x,
-        y = pt.y;
-    ScreenToClient(&x, &y);
-    wxSetCursorEvent event(x, y);
-
-    bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
-    if ( processedEvtSetCursor && event.HasCursor() )
-    {
-        hcursor = GetHcursorOf(event.GetCursor());
-    }
+        {
+            wxLogLastError(wxT("GetCursorPos"));
+        }
 
-    if ( !hcursor )
-    {
-        bool isBusy = wxIsBusy();
+        int x = pt.x,
+            y = pt.y;
+        ScreenToClient(&x, &y);
+        wxSetCursorEvent event(x, y);
 
-        // the test for processedEvtSetCursor is here to prevent using m_cursor
-        // if the user code caught EVT_SET_CURSOR() and returned nothing from
-        // it - this is a way to say that our cursor shouldn't be used for this
-        // point
-        if ( !processedEvtSetCursor && m_cursor.Ok() )
+        bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
+        if ( processedEvtSetCursor && event.HasCursor() )
         {
-            hcursor = GetHcursorOf(m_cursor);
+            hcursor = GetHcursorOf(event.GetCursor());
         }
 
-        if ( !GetParent() )
+        if ( !hcursor )
         {
-            if ( isBusy )
+            // the test for processedEvtSetCursor is here to prevent using
+            // m_cursor if the user code caught EVT_SET_CURSOR() and returned
+            // nothing from it - this is a way to say that our cursor shouldn't
+            // be used for this point
+            if ( !processedEvtSetCursor && m_cursor.Ok() )
             {
-                hcursor = wxGetCurrentBusyCursor();
+                hcursor = GetHcursorOf(m_cursor);
             }
-            else if ( !hcursor )
+
+            if ( !hcursor && !GetParent() )
             {
                 const wxCursor *cursor = wxGetGlobalCursor();
                 if ( cursor && cursor->Ok() )
@@ -3955,10 +3870,9 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
         }
     }
 
+
     if ( hcursor )
     {
-//        wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor);
-
         ::SetCursor(hcursor);
 
         // cursor set, stop here
@@ -5275,6 +5189,7 @@ bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
     return GetEventHandler()->ProcessEvent(event);
 }
 
+#if wxUSE_MENUS
 int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
                                 WXLPARAM WXUNUSED_IN_WINCE(lParam))
 {
@@ -5309,7 +5224,7 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
                 //  menu creation code
                 wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
 
-                const wxChar *p = wxStrchr(item->GetText(), _T('&'));
+                const wxChar *p = wxStrchr(item->GetText().wx_str(), _T('&'));
                 while ( p++ )
                 {
                     if ( *p == _T('&') )
@@ -5356,6 +5271,7 @@ bool wxWindowMSW::HandleClipboardEvent( WXUINT nMsg )
 
     return GetEventHandler()->ProcessEvent(evt);
 }
+#endif // wxUSE_MENUS
 
 // ---------------------------------------------------------------------------
 // joystick
@@ -5529,6 +5445,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
 // ===========================================================================
@@ -6690,7 +6630,7 @@ public:
         }
 
         return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
-    };
+    }
 
 private:
     static HHOOK ms_hMsgHookProc;