X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/90c6edd706882b8fd06b6d5359d9682ac0ee858c..3f4a2351e4c677c88c18ea812b609477adee7380:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 2c7a71a8a3..bd7a853adf 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -28,6 +28,8 @@ #ifndef WX_PRECOMP #include "wx/msw/wrapwin.h" + #include "wx/msw/wrapcctl.h" // include "properly" + #include "wx/msw/missing.h" #include "wx/accel.h" #include "wx/menu.h" #include "wx/dc.h" @@ -48,6 +50,7 @@ #include "wx/log.h" #include "wx/textctrl.h" #include "wx/menuitem.h" + #include "wx/module.h" #endif #if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__) @@ -55,7 +58,6 @@ #endif #include "wx/evtloop.h" -#include "wx/module.h" #include "wx/power.h" #include "wx/sysopt.h" @@ -103,15 +105,10 @@ #include #endif -// include "properly" -#include "wx/msw/wrapcctl.h" - -#ifndef __WXWINCE__ +#if !defined __WXWINCE__ && !defined NEED_PBT_H #include #endif -#include "wx/msw/missing.h" - #if defined(__WXWINCE__) #include "wx/msw/wince/missing.h" #ifdef __POCKETPC__ @@ -829,7 +826,7 @@ void wxWindowMSW::MSWUpdateUIState(int action, int state) if ( s_needToUpdate == -1 ) { int verMaj, verMin; - s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxWINDOWS_NT && + s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxOS_WINDOWS_NT && verMaj >= 5; } @@ -1018,6 +1015,67 @@ bool wxWindowMSW::ScrollPages(int pages) down ? pages : -pages); } +// ---------------------------------------------------------------------------- +// RTL support +// ---------------------------------------------------------------------------- + +void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir) +{ +#ifdef __WXWINCE__ + wxUnusedVar(dir); +#else + const HWND hwnd = GetHwnd(); + wxCHECK_RET( hwnd, _T("layout direction must be set after window creation") ); + + LONG styleOld = ::GetWindowLong(hwnd, GWL_EXSTYLE); + + LONG styleNew = styleOld; + switch ( dir ) + { + case wxLayout_LeftToRight: + styleNew &= ~WS_EX_LAYOUTRTL; + break; + + case wxLayout_RightToLeft: + styleNew |= WS_EX_LAYOUTRTL; + break; + + default: + wxFAIL_MSG(_T("unsupported layout direction")); + break; + } + + if ( styleNew != styleOld ) + { + ::SetWindowLong(hwnd, GWL_EXSTYLE, styleNew); + } +#endif +} + +wxLayoutDirection wxWindowMSW::GetLayoutDirection() const +{ +#ifdef __WXWINCE__ + return wxLayout_Default; +#else + const HWND hwnd = GetHwnd(); + wxCHECK_MSG( hwnd, wxLayout_Default, _T("invalid window") ); + + return ::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL + ? wxLayout_RightToLeft + : wxLayout_LeftToRight; +#endif +} + +wxCoord +wxWindowMSW::AdjustForLayoutDirection(wxCoord x, + wxCoord WXUNUSED(width), + wxCoord WXUNUSED(widthTotal)) const +{ + // Win32 mirrors the coordinates of RTL windows automatically, so don't + // redo it ourselves + return x; +} + // --------------------------------------------------------------------------- // subclassing // --------------------------------------------------------------------------- @@ -1643,6 +1701,13 @@ void wxWindowMSW::DoGetPosition(int *x, int *y) const // children, not for the dialogs/frames if ( !IsTopLevel() ) { + if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) + { + // In RTL mode, we want the logical left x-coordinate, + // which would be the physical right x-coordinate. + point.x = rect.right; + } + // Since we now have the absolute screen coords, if there's a // parent we must subtract its top left corner if ( parent ) @@ -2196,90 +2261,10 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) } } - // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the - // message even when there is no cancel button and when the message is - // needed by the control itself: in particular, it prevents the tree in - // place edit control from being closed with Escape in a dialog - if ( msg->message != WM_KEYDOWN || msg->wParam != VK_ESCAPE ) + if ( ::IsDialogMessage(GetHwnd(), msg) ) { - // ::IsDialogMessage() is broken and may sometimes hang the - // application by going into an infinite loop, so we try to detect - // [some of] the situations when this may happen and not call it - // then - - // assume we can call it by default - bool canSafelyCallIsDlgMsg = true; - - HWND hwndFocus = ::GetFocus(); - - // if the currently focused window itself has WS_EX_CONTROLPARENT style, ::IsDialogMessage() will also enter - // an infinite loop, because it will recursively check the child - // windows but not the window itself and so if none of the children - // accepts focus it loops forever (as it only stops when it gets - // back to the window it started from) - // - // while it is very unusual that a window with WS_EX_CONTROLPARENT - // style has the focus, it can happen. One such possibility is if - // all windows are either toplevel, wxDialog, wxPanel or static - // controls and no window can actually accept keyboard input. -#if !defined(__WXWINCE__) - if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT ) - { - // pessimistic by default - canSafelyCallIsDlgMsg = false; - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindow * const win = node->GetData(); - if ( win->AcceptsFocus() && - !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) & - WS_EX_CONTROLPARENT) ) - { - // it shouldn't hang... - canSafelyCallIsDlgMsg = true; - - break; - } - } - } -#endif // !__WXWINCE__ - - if ( canSafelyCallIsDlgMsg ) - { - // ::IsDialogMessage() can enter in an infinite loop when the - // currently focused window is disabled or hidden and its - // parent has WS_EX_CONTROLPARENT style, so don't call it in - // this case - while ( hwndFocus ) - { - if ( !::IsWindowEnabled(hwndFocus) || - !::IsWindowVisible(hwndFocus) ) - { - // it would enter an infinite loop if we do this! - canSafelyCallIsDlgMsg = false; - - break; - } - - if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) ) - { - // it's a top level window, don't go further -- e.g. even - // if the parent of a dialog is disabled, this doesn't - // break navigation inside the dialog - break; - } - - hwndFocus = ::GetParent(hwndFocus); - } - } - - // let IsDialogMessage() have the message if it's safe to call it - if ( canSafelyCallIsDlgMsg && ::IsDialogMessage(GetHwnd(), msg) ) - { - // IsDialogMessage() did something... - return true; - } + // IsDialogMessage() did something... + return true; } } #endif // __WXUNIVERSAL__ @@ -2307,10 +2292,96 @@ bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg) #endif // wxUSE_ACCEL } -bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(pMsg)) +bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg) { - // preprocess all messages by default - return true; + // all tests below have to deal with various bugs/misfeatures of + // IsDialogMessage(): we have to prevent it from being called from our + // MSWProcessMessage() in some situations + + // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the + // message even when there is no cancel button and when the message is + // needed by the control itself: in particular, it prevents the tree in + // place edit control from being closed with Escape in a dialog + if ( msg->message == WM_KEYDOWN && msg->wParam == VK_ESCAPE ) + { + return false; + } + + // ::IsDialogMessage() is broken and may sometimes hang the application by + // going into an infinite loop when it tries to find the control to give + // focus to when Alt- is pressed, so we try to detect [some of] the + // situations when this may happen and not call it then + if ( msg->message != WM_SYSCHAR ) + return true; + + // assume we can call it by default + bool canSafelyCallIsDlgMsg = true; + + HWND hwndFocus = ::GetFocus(); + + // if the currently focused window itself has WS_EX_CONTROLPARENT style, + // ::IsDialogMessage() will also enter an infinite loop, because it will + // recursively check the child windows but not the window itself and so if + // none of the children accepts focus it loops forever (as it only stops + // when it gets back to the window it started from) + // + // while it is very unusual that a window with WS_EX_CONTROLPARENT + // style has the focus, it can happen. One such possibility is if + // all windows are either toplevel, wxDialog, wxPanel or static + // controls and no window can actually accept keyboard input. +#if !defined(__WXWINCE__) + if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT ) + { + // pessimistic by default + canSafelyCallIsDlgMsg = false; + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow * const win = node->GetData(); + if ( win->AcceptsFocus() && + !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) & + WS_EX_CONTROLPARENT) ) + { + // it shouldn't hang... + canSafelyCallIsDlgMsg = true; + + break; + } + } + } +#endif // !__WXWINCE__ + + if ( canSafelyCallIsDlgMsg ) + { + // ::IsDialogMessage() can enter in an infinite loop when the + // currently focused window is disabled or hidden and its + // parent has WS_EX_CONTROLPARENT style, so don't call it in + // this case + while ( hwndFocus ) + { + if ( !::IsWindowEnabled(hwndFocus) || + !::IsWindowVisible(hwndFocus) ) + { + // it would enter an infinite loop if we do this! + canSafelyCallIsDlgMsg = false; + + break; + } + + if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) ) + { + // it's a top level window, don't go further -- e.g. even + // if the parent of a dialog is disabled, this doesn't + // break navigation inside the dialog + break; + } + + hwndFocus = ::GetParent(hwndFocus); + } + } + + return canSafelyCallIsDlgMsg; } // --------------------------------------------------------------------------- @@ -3879,6 +3950,19 @@ bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam), #endif } +bool wxWindowMSW::IsDoubleBuffered() const +{ + for ( const wxWindow *wnd = this; + wnd && !wnd->IsTopLevel(); wnd = + wnd->GetParent() ) + { + if ( ::GetWindowLong(GetHwndOf(wnd), GWL_EXSTYLE) & WS_EX_COMPOSITED ) + return true; + } + + return false; +} + // --------------------------------------------------------------------------- // owner drawn stuff // --------------------------------------------------------------------------- @@ -4294,7 +4378,7 @@ void wxWindowMSW::OnPaint(wxPaintEvent& event) bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) { - wxDCTemp dc(hdc); + wxDCTemp dc(hdc, GetClientSize()); dc.SetHDC(hdc); dc.SetWindow((wxWindow *)this); @@ -4397,11 +4481,37 @@ WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, WXHWND hWndToPaint) return 0; } -bool wxWindowMSW::HandlePrintClient(WXHDC WXUNUSED(hDC)) +bool wxWindowMSW::HandlePrintClient(WXHDC hDC) { - // TODO: handle wxBG_STYLE_CUSTOM and/or wxBG_STYLE_COLOUR here so when - // DrawParentThemeBackground() from uxtheme.dll is called we don't get - // the default background e.g. the border when custom drawing buttons + // we receive this message when DrawThemeParentBackground() is + // called from def window proc of several controls under XP and we + // must draw properly themed background here + // + // note that naively I'd expect filling the client rect with the + // brush returned by MSWGetBgBrush() work -- but for some reason it + // doesn't and we have to call parents MSWPrintChild() which is + // supposed to call DrawThemeBackground() with appropriate params + // + // also note that in this case lParam == PRF_CLIENT but we're + // clearly expected to paint the background and nothing else! + + if ( IsTopLevel() || InheritsBackgroundColour() ) + return false; + + // sometimes we don't want the parent to handle it at all, instead + // return whatever value this window wants + if ( !MSWShouldPropagatePrintChild() ) + return MSWPrintChild(hDC, (wxWindow *)this); + + for ( wxWindow *win = GetParent(); win; win = win->GetParent() ) + { + if ( win->MSWPrintChild(hDC, (wxWindow *)this) ) + return true; + + if ( win->IsTopLevel() || win->InheritsBackgroundColour() ) + break; + } + return false; }