X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/609da8bbad84f858f98c78fb1f87b8172f292497..69659fd770f615210efac4b4fa741b3ad6223616:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 84509a8182..81ee66815f 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 // --------------------------------------------------------------------------- @@ -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 : 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;