X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a8b2285edf2eb1ef1dd1cb19abf130a871821dbf..69659fd770f615210efac4b4fa741b3ad6223616:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 4dff286ca2..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,69 +653,11 @@ wxWindow *wxWindowBase::DoFindFocus() return NULL; } -bool wxWindowMSW::Enable(bool enable) +void wxWindowMSW::DoEnable( bool enable ) { - 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) @@ -979,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 @@ -1520,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 @@ -2039,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 ) @@ -2104,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 @@ -2380,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) ) { @@ -2512,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); @@ -2790,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(); } } @@ -2864,12 +2816,12 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l #endif // defined(WM_DRAWITEM) case WM_GETDLGCODE: - if ( !IsOfStandardClass() ) + if ( !IsOfStandardClass() || HasFlag(wxWANTS_CHARS) ) { // we always want to get the char events rc.result = DLGC_WANTCHARS; - if ( GetWindowStyleFlag() & wxWANTS_CHARS ) + if ( HasFlag(wxWANTS_CHARS) ) { // in fact, we want everything rc.result |= DLGC_WANTARROWS | @@ -3199,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 ) @@ -3212,6 +3165,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l } } break; +#endif // wxUSE_MENUS #ifndef __WXWINCE__ case WM_POWERBROADCAST: @@ -3222,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 ) @@ -3408,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(), @@ -3529,7 +3492,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code, ( CP_ACP, 0, // no flags - ttip, + ttip.wx_str(), tipLength, buf, WXSIZEOF(buf) - 1 @@ -3847,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() ) @@ -3914,10 +3870,9 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), } } + if ( hcursor ) { -// wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor); - ::SetCursor(hcursor); // cursor set, stop here @@ -5234,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)) { @@ -5268,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('&') ) @@ -5315,6 +5271,7 @@ bool wxWindowMSW::HandleClipboardEvent( WXUINT nMsg ) return GetEventHandler()->ProcessEvent(evt); } +#endif // wxUSE_MENUS // --------------------------------------------------------------------------- // joystick @@ -5488,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 // =========================================================================== @@ -5769,13 +5750,26 @@ WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual) return vk; } +#ifndef SM_SWAPBUTTON + #define SM_SWAPBUTTON 23 +#endif + // small helper for wxGetKeyState() and wxGetMouseState() static inline bool wxIsKeyDown(WXWORD vk) { + switch (vk) + { + case VK_LBUTTON: + if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_RBUTTON; + break; + case VK_RBUTTON: + if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_LBUTTON; + break; + } // the low order bit indicates whether the key was pressed since the last // call and the high order one indicates whether it is down right now and // we only want that one - return (::GetAsyncKeyState(vk) & (1<<15)) != 0; + return (GetAsyncKeyState(vk) & (1<<15)) != 0; } bool wxGetKeyState(wxKeyCode key) @@ -5795,7 +5789,7 @@ bool wxGetKeyState(wxKeyCode key) // low order bit means LED is highlighted and high order one means the // key is down; for compatibility with the other ports return true if // either one is set - return ::GetKeyState(vk) != 0; + return GetKeyState(vk) != 0; } else // normal key @@ -6060,6 +6054,46 @@ const wxChar *wxGetMessageName(int message) case 0x00A7: return wxT("WM_NCMBUTTONDOWN"); case 0x00A8: return wxT("WM_NCMBUTTONUP"); case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK"); + + case 0x00B0: return wxT("EM_GETSEL"); + case 0x00B1: return wxT("EM_SETSEL"); + case 0x00B2: return wxT("EM_GETRECT"); + case 0x00B3: return wxT("EM_SETRECT"); + case 0x00B4: return wxT("EM_SETRECTNP"); + case 0x00B5: return wxT("EM_SCROLL"); + case 0x00B6: return wxT("EM_LINESCROLL"); + case 0x00B7: return wxT("EM_SCROLLCARET"); + case 0x00B8: return wxT("EM_GETMODIFY"); + case 0x00B9: return wxT("EM_SETMODIFY"); + case 0x00BA: return wxT("EM_GETLINECOUNT"); + case 0x00BB: return wxT("EM_LINEINDEX"); + case 0x00BC: return wxT("EM_SETHANDLE"); + case 0x00BD: return wxT("EM_GETHANDLE"); + case 0x00BE: return wxT("EM_GETTHUMB"); + case 0x00C1: return wxT("EM_LINELENGTH"); + case 0x00C2: return wxT("EM_REPLACESEL"); + case 0x00C4: return wxT("EM_GETLINE"); + case 0x00C5: return wxT("EM_LIMITTEXT/EM_SETLIMITTEXT"); /* ;win40 Name change */ + case 0x00C6: return wxT("EM_CANUNDO"); + case 0x00C7: return wxT("EM_UNDO"); + case 0x00C8: return wxT("EM_FMTLINES"); + case 0x00C9: return wxT("EM_LINEFROMCHAR"); + case 0x00CB: return wxT("EM_SETTABSTOPS"); + case 0x00CC: return wxT("EM_SETPASSWORDCHAR"); + case 0x00CD: return wxT("EM_EMPTYUNDOBUFFER"); + case 0x00CE: return wxT("EM_GETFIRSTVISIBLELINE"); + case 0x00CF: return wxT("EM_SETREADONLY"); + case 0x00D0: return wxT("EM_SETWORDBREAKPROC"); + case 0x00D1: return wxT("EM_GETWORDBREAKPROC"); + case 0x00D2: return wxT("EM_GETPASSWORDCHAR"); + case 0x00D3: return wxT("EM_SETMARGINS"); + case 0x00D4: return wxT("EM_GETMARGINS"); + case 0x00D5: return wxT("EM_GETLIMITTEXT"); + case 0x00D6: return wxT("EM_POSFROMCHAR"); + case 0x00D7: return wxT("EM_CHARFROMPOS"); + case 0x00D8: return wxT("EM_SETIMESTATUS"); + case 0x00D9: return wxT("EM_GETIMESTATUS"); + case 0x0100: return wxT("WM_KEYDOWN"); case 0x0101: return wxT("WM_KEYUP"); case 0x0102: return wxT("WM_CHAR"); @@ -6085,6 +6119,16 @@ const wxChar *wxGetMessageName(int message) case 0x011F: return wxT("WM_MENUSELECT"); case 0x0120: return wxT("WM_MENUCHAR"); case 0x0121: return wxT("WM_ENTERIDLE"); + + case 0x0132: return wxT("WM_CTLCOLORMSGBOX"); + case 0x0133: return wxT("WM_CTLCOLOREDIT"); + case 0x0134: return wxT("WM_CTLCOLORLISTBOX"); + case 0x0135: return wxT("WM_CTLCOLORBTN"); + case 0x0136: return wxT("WM_CTLCOLORDLG"); + case 0x0137: return wxT("WM_CTLCOLORSCROLLBAR"); + case 0x0138: return wxT("WM_CTLCOLORSTATIC"); + case 0x01E1: return wxT("MN_GETHMENU"); + case 0x0200: return wxT("WM_MOUSEMOVE"); case 0x0201: return wxT("WM_LBUTTONDOWN"); case 0x0202: return wxT("WM_LBUTTONUP"); @@ -6129,6 +6173,11 @@ const wxChar *wxGetMessageName(int message) case 0x0290: return wxT("WM_IME_KEYDOWN"); case 0x0291: return wxT("WM_IME_KEYUP"); + case 0x02A0: return wxT("WM_NCMOUSEHOVER"); + case 0x02A1: return wxT("WM_MOUSEHOVER"); + case 0x02A2: return wxT("WM_NCMOUSELEAVE"); + case 0x02A3: return wxT("WM_MOUSELEAVE"); + case 0x0300: return wxT("WM_CUT"); case 0x0301: return wxT("WM_COPY"); case 0x0302: return wxT("WM_PASTE"); @@ -6147,9 +6196,10 @@ const wxChar *wxGetMessageName(int message) case 0x030F: return wxT("WM_QUERYNEWPALETTE"); case 0x0310: return wxT("WM_PALETTEISCHANGING"); case 0x0311: return wxT("WM_PALETTECHANGED"); -#if wxUSE_HOTKEY case 0x0312: return wxT("WM_HOTKEY"); -#endif + + case 0x0317: return wxT("WM_PRINT"); + case 0x0318: return wxT("WM_PRINTCLIENT"); // common controls messages - although they're not strictly speaking // standard, it's nice to decode them nevertheless @@ -6580,7 +6630,7 @@ public: } return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam); - }; + } private: static HHOOK ms_hMsgHookProc;