X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/47b378bd88260611387af8604a1c8f62355350ab..107defe36a68091303be9a11c8abb83432acee8c:/src/msw/window.cpp?ds=sidebyside diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 929beded15..1aab7e12dd 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -79,6 +79,7 @@ #endif #include "wx/msw/private.h" +#include "wx/msw/dcclient.h" #if wxUSE_TOOLTIPS #include "wx/tooltip.h" @@ -121,20 +122,35 @@ #endif #endif +#if wxUSE_UXTHEME + #include "wx/msw/uxtheme.h" + #define EP_EDITTEXT 1 + #define ETS_NORMAL 1 + #define ETS_HOT 2 + #define ETS_SELECTED 3 + #define ETS_DISABLED 4 + #define ETS_FOCUSED 5 + #define ETS_READONLY 6 + #define ETS_ASSIST 7 +#endif + +// define the constants used by AnimateWindow() if our SDK doesn't have them +#ifndef AW_CENTER + #define AW_HOR_POSITIVE 0x00000001 + #define AW_HOR_NEGATIVE 0x00000002 + #define AW_VER_POSITIVE 0x00000004 + #define AW_VER_NEGATIVE 0x00000008 + #define AW_CENTER 0x00000010 + #define AW_HIDE 0x00010000 + #define AW_ACTIVATE 0x00020000 + #define AW_SLIDE 0x00040000 + #define AW_BLEND 0x00080000 +#endif + #if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS #define HAVE_TRACKMOUSEEVENT #endif // everything needed for TrackMouseEvent() -// if this is set to 1, we use deferred window sizing to reduce flicker when -// resizing complicated window hierarchies, but this can in theory result in -// different behaviour than the old code so we keep the possibility to use it -// by setting this to 0 (in the future this should be removed completely) -#ifdef __WXWINCE__ -#define USE_DEFERRED_SIZING 0 -#else -#define USE_DEFERRED_SIZING 1 -#endif - // set this to 1 to filter out duplicate mouse events, e.g. mouse move events // when mouse position didnd't change #ifdef __WXWINCE__ @@ -143,27 +159,30 @@ #define wxUSE_MOUSEEVENT_HACK 1 #endif +// not all compilers/platforms have X button related declarations (notably +// Windows CE doesn't, and probably some old SDKs don't neither) +#ifdef WM_XBUTTONDOWN + #define wxHAS_XBUTTON +#endif + // --------------------------------------------------------------------------- // global variables // --------------------------------------------------------------------------- #if wxUSE_MENUS_NATIVE -wxMenu *wxCurrentPopupMenu = NULL; -#endif // wxUSE_MENUS_NATIVE - -#ifdef __WXWINCE__ -extern wxChar *wxCanvasClassName; -#else -extern const wxChar *wxCanvasClassName; +extern wxMenu *wxCurrentPopupMenu; #endif +namespace +{ + // true if we had already created the std colour map, used by // wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT) -static bool gs_hasStdCmap = false; +bool gs_hasStdCmap = false; // last mouse event information we need to filter out the duplicates #if wxUSE_MOUSEEVENT_HACK -static struct MouseEventInfoDummy +struct MouseEventInfoDummy { // mouse position (in screen coordinates) wxPoint pos; @@ -178,7 +197,29 @@ WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler, wxIntegerHash, wxIntegerEqual, MSWMessageHandlers); -static MSWMessageHandlers gs_messageHandlers; +MSWMessageHandlers gs_messageHandlers; + +// hash containing all our windows, it uses HWND keys and wxWindow* values +WX_DECLARE_HASH_MAP(HWND, wxWindow *, + wxPointerHash, wxPointerEqual, + WindowHandles); + +WindowHandles gs_windowHandles; + +#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK + +// temporary override for WM_ERASEBKGND processing: we don't store this in +// wxWindow itself as we don't need it during most of the time so don't +// increase the size of all window objects unnecessarily +WX_DECLARE_HASH_MAP(wxWindow *, wxWindow *, + wxPointerHash, wxPointerEqual, + EraseBgHooks); + +EraseBgHooks gs_eraseBgHooks; + +#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK + +} // anonymous namespace // --------------------------------------------------------------------------- // private functions @@ -189,13 +230,12 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); -#ifdef __WXDEBUG__ +#if wxDEBUG_LEVEL >= 2 const wxChar *wxGetMessageName(int message); -#endif //__WXDEBUG__ +#endif // wxDEBUG_LEVEL >= 2 void wxRemoveHandleAssociation(wxWindowMSW *win); extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win); -wxWindow *wxFindWinFromHandle(WXHWND hWnd); // get the text metrics for the current font static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win); @@ -219,7 +259,7 @@ static inline void wxBringWindowToTop(HWND hwnd) // raise top level parent to top of z order if (!::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)) { - wxLogLastError(_T("SetWindowPos")); + wxLogLastError(wxT("SetWindowPos")); } } @@ -243,12 +283,11 @@ static void EnsureParentHasControlParentStyle(wxWindow *parent) */ while ( parent && !parent->IsTopLevel() ) { - LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE); + LONG exStyle = wxGetWindowExStyle(parent); if ( !(exStyle & WS_EX_CONTROLPARENT) ) { // force the parent to have this style - ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE, - exStyle | WS_EX_CONTROLPARENT); + wxSetWindowExStyle(parent, exStyle | WS_EX_CONTROLPARENT); } parent = parent->GetParent(); @@ -392,7 +431,6 @@ wxCONSTRUCTOR_DUMMY(wxWindow) BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase) EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged) - EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground) #ifdef __WXWINCE__ EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog) #endif @@ -487,21 +525,20 @@ bool wxWindowMSW::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id)) void wxWindowMSW::Init() { // MSW specific - m_isBeingDeleted = false; m_oldWndProc = NULL; m_mouseInWindow = false; m_lastKeydownProcessed = false; - m_frozenness = 0; - m_hWnd = 0; - m_hDWP = 0; m_xThumbSize = 0; m_yThumbSize = 0; +#if wxUSE_DEFERRED_SIZING + m_hDWP = 0; m_pendingPosition = wxDefaultPosition; m_pendingSize = wxDefaultSize; +#endif // wxUSE_DEFERRED_SIZING #ifdef __POCKETPC__ m_contextMenuEnabled = false; @@ -511,7 +548,7 @@ void wxWindowMSW::Init() // Destructor wxWindowMSW::~wxWindowMSW() { - m_isBeingDeleted = true; + SendDestroyEvent(); #ifndef __WXUNIVERSAL__ // VS: make sure there's no wxFrame with last focus set to us: @@ -545,7 +582,9 @@ wxWindowMSW::~wxWindowMSW() //if (::IsWindow(GetHwnd())) { if ( !::DestroyWindow(GetHwnd()) ) + { wxLogLastError(wxT("DestroyWindow")); + } } // remove hWnd <-> wxWindow association @@ -554,6 +593,12 @@ wxWindowMSW::~wxWindowMSW() } +/* static */ +const wxChar *wxWindowMSW::MSWGetRegisteredClassName() +{ + return wxApp::GetRegisteredClassName(wxT("wxWindow"), COLOR_BTNFACE); +} + // real construction (Init() must have been called before!) bool wxWindowMSW::Create(wxWindow *parent, wxWindowID id, @@ -586,7 +631,8 @@ bool wxWindowMSW::Create(wxWindow *parent, msflags |= WS_VISIBLE; } - if ( !MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle) ) + if ( !MSWCreate(MSWGetRegisteredClassName(), + NULL, pos, size, msflags, exstyle) ) return false; InheritAttributes(); @@ -601,15 +647,14 @@ bool wxWindowMSW::Create(wxWindow *parent, void wxWindowMSW::SetFocus() { HWND hWnd = GetHwnd(); - wxCHECK_RET( hWnd, _T("can't set focus to invalid window") ); + wxCHECK_RET( hWnd, wxT("can't set focus to invalid window") ); -#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) +#if !defined(__WXWINCE__) ::SetLastError(0); #endif if ( !::SetFocus(hWnd) ) { -#if defined(__WXDEBUG__) && !defined(__WXMICROWIN__) // was there really an error? DWORD dwRes = ::GetLastError(); if ( dwRes ) @@ -617,10 +662,9 @@ void wxWindowMSW::SetFocus() HWND hwndFocus = ::GetFocus(); if ( hwndFocus != hWnd ) { - wxLogApiError(_T("SetFocus"), dwRes); + wxLogApiError(wxT("SetFocus"), dwRes); } } -#endif // Debug } } @@ -680,6 +724,119 @@ bool wxWindowMSW::Show(bool show) ::ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE); } + if ( IsFrozen() ) + { + // DoFreeze/DoThaw don't do anything if the window is not shown, so + // we have to call them from here now + if ( show ) + DoFreeze(); + else + DoThaw(); + } + + return true; +} + +bool +wxWindowMSW::MSWShowWithEffect(bool show, + wxShowEffect effect, + unsigned timeout) +{ + if ( effect == wxSHOW_EFFECT_NONE ) + return Show(show); + + if ( !wxWindowBase::Show(show) ) + return false; + + typedef BOOL (WINAPI *AnimateWindow_t)(HWND, DWORD, DWORD); + + static AnimateWindow_t s_pfnAnimateWindow = NULL; + static bool s_initDone = false; + if ( !s_initDone ) + { + wxDynamicLibrary dllUser32(wxT("user32.dll"), wxDL_VERBATIM | wxDL_QUIET); + wxDL_INIT_FUNC(s_pfn, AnimateWindow, dllUser32); + + s_initDone = true; + + // notice that it's ok to unload user32.dll here as it won't be really + // unloaded, being still in use because we link to it statically too + } + + if ( !s_pfnAnimateWindow ) + return Show(show); + + // Show() has a side effect of sending a WM_SIZE to the window, which helps + // ensuring that it's laid out correctly, but AnimateWindow() doesn't do + // this so send the event ourselves + SendSizeEvent(); + + // prepare to use AnimateWindow() + + if ( !timeout ) + timeout = 200; // this is the default animation timeout, per MSDN + + DWORD dwFlags = show ? 0 : AW_HIDE; + + switch ( effect ) + { + case wxSHOW_EFFECT_ROLL_TO_LEFT: + dwFlags |= AW_HOR_NEGATIVE; + break; + + case wxSHOW_EFFECT_ROLL_TO_RIGHT: + dwFlags |= AW_HOR_POSITIVE; + break; + + case wxSHOW_EFFECT_ROLL_TO_TOP: + dwFlags |= AW_VER_NEGATIVE; + break; + + case wxSHOW_EFFECT_ROLL_TO_BOTTOM: + dwFlags |= AW_VER_POSITIVE; + break; + + case wxSHOW_EFFECT_SLIDE_TO_LEFT: + dwFlags |= AW_SLIDE | AW_HOR_NEGATIVE; + break; + + case wxSHOW_EFFECT_SLIDE_TO_RIGHT: + dwFlags |= AW_SLIDE | AW_HOR_POSITIVE; + break; + + case wxSHOW_EFFECT_SLIDE_TO_TOP: + dwFlags |= AW_SLIDE | AW_VER_NEGATIVE; + break; + + case wxSHOW_EFFECT_SLIDE_TO_BOTTOM: + dwFlags |= AW_SLIDE | AW_VER_POSITIVE; + break; + + case wxSHOW_EFFECT_BLEND: + dwFlags |= AW_BLEND; + break; + + case wxSHOW_EFFECT_EXPAND: + dwFlags |= AW_CENTER; + break; + + + case wxSHOW_EFFECT_MAX: + wxFAIL_MSG( wxT("invalid window show effect") ); + return false; + + default: + wxFAIL_MSG( wxT("unknown window show effect") ); + return false; + } + + if ( !(*s_pfnAnimateWindow)(GetHwnd(), timeout, dwFlags) ) + { + wxLogLastError(wxT("AnimateWindow")); + + return false; + } + return true; } @@ -709,14 +866,14 @@ void wxWindowMSW::DoReleaseMouse() { if ( !::ReleaseCapture() ) { - wxLogLastError(_T("ReleaseCapture")); + wxLogLastError(wxT("ReleaseCapture")); } } /* static */ wxWindow *wxWindowBase::GetCapture() { HWND hwnd = ::GetCapture(); - return hwnd ? wxFindWinFromHandle((WXHWND)hwnd) : (wxWindow *)NULL; + return hwnd ? wxFindWinFromHandle(hwnd) : NULL; } bool wxWindowMSW::SetFont(const wxFont& font) @@ -730,7 +887,11 @@ bool wxWindowMSW::SetFont(const wxFont& font) HWND hWnd = GetHwnd(); if ( hWnd != 0 ) { - WXHANDLE hFont = m_font.GetResourceHandle(); + // note the use of GetFont() instead of m_font: our own font could have + // just been reset and in this case we need to change the font used by + // the native window to the default for this class, i.e. exactly what + // GetFont() returns + WXHANDLE hFont = GetFont().GetResourceHandle(); wxASSERT_MSG( hFont, wxT("should have valid font") ); @@ -785,7 +946,7 @@ void wxWindowMSW::WarpPointer(int x, int y) if ( !::SetCursorPos(x, y) ) { - wxLogLastError(_T("SetCursorPos")); + wxLogLastError(wxT("SetCursorPos")); } } @@ -813,6 +974,9 @@ void wxWindowMSW::MSWUpdateUIState(int action, int state) // scrolling stuff // --------------------------------------------------------------------------- +namespace +{ + inline int GetScrollPosition(HWND hWnd, int wOrient) { #ifdef __WXMICROWIN__ @@ -828,12 +992,19 @@ inline int GetScrollPosition(HWND hWnd, int wOrient) #endif } +inline UINT WXOrientToSB(int orient) +{ + return orient == wxHORIZONTAL ? SB_HORZ : SB_VERT; +} + +} // anonymous namespace + int wxWindowMSW::GetScrollPos(int orient) const { HWND hWnd = GetHwnd(); - wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") ); + wxCHECK_MSG( hWnd, 0, wxT("no HWND in GetScrollPos") ); - return GetScrollPosition(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT); + return GetScrollPosition(hWnd, WXOrientToSB(orient)); } // This now returns the whole range, not just the number @@ -844,19 +1015,13 @@ int wxWindowMSW::GetScrollRange(int orient) const HWND hWnd = GetHwnd(); if ( !hWnd ) return 0; -#if 0 - ::GetScrollRange(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, - &minPos, &maxPos); -#endif WinStruct scrollInfo; scrollInfo.fMask = SIF_RANGE; - if ( !::GetScrollInfo(hWnd, - orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, - &scrollInfo) ) + if ( !::GetScrollInfo(hWnd, WXOrientToSB(orient), &scrollInfo) ) { // Most of the time this is not really an error, since the return // value can also be zero when there is no scrollbar yet. - // wxLogLastError(_T("GetScrollInfo")); + // wxLogLastError(wxT("GetScrollInfo")); } maxPos = scrollInfo.nMax; @@ -872,7 +1037,7 @@ int wxWindowMSW::GetScrollThumb(int orient) const void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh) { HWND hWnd = GetHwnd(); - wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") ); + wxCHECK_RET( hWnd, wxT("SetScrollPos: no HWND") ); WinStruct info; info.nPage = 0; @@ -885,8 +1050,7 @@ void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh) info.fMask |= SIF_DISABLENOSCROLL; } - ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, - &info, refresh); + ::SetScrollInfo(hWnd, WXOrientToSB(orient), &info, refresh); } // New function that will replace some of the above. @@ -896,28 +1060,37 @@ void wxWindowMSW::SetScrollbar(int orient, int range, bool refresh) { + // We have to set the variables here to make them valid in events + // triggered by ::SetScrollInfo() + *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize; + + HWND hwnd = GetHwnd(); + if ( !hwnd ) + return; + WinStruct info; - info.nPage = pageSize; - info.nMin = 0; // range is nMax - nMin + 1 - info.nMax = range - 1; // as both nMax and nMax are inclusive - info.nPos = pos; + if ( range != -1 ) + { + info.nPage = pageSize; + info.nMin = 0; // range is nMax - nMin + 1 + info.nMax = range - 1; // as both nMax and nMax are inclusive + info.nPos = pos; + + // enable the scrollbar if it had been disabled before by specifying + // SIF_DISABLENOSCROLL below: as we can't know whether this had been + // done or not just do it always + ::EnableScrollBar(hwnd, WXOrientToSB(orient), ESB_ENABLE_BOTH); + } + //else: leave all the fields to be 0 + info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; - if ( HasFlag(wxALWAYS_SHOW_SB) ) + if ( HasFlag(wxALWAYS_SHOW_SB) || range == -1 ) { // disable scrollbar instead of removing it then info.fMask |= SIF_DISABLENOSCROLL; } - HWND hWnd = GetHwnd(); - if ( hWnd ) - { - // We have to set the variables here to make them valid in events - // triggered by ::SetScrollInfo() - *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize; - - ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, - &info, refresh); - } + ::SetScrollInfo(hwnd, WXOrientToSB(orient), &info, refresh); } void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect) @@ -926,10 +1099,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 @@ -995,10 +1165,10 @@ 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") ); + wxCHECK_RET( GetHwnd(), + wxT("layout direction must be set after window creation") ); - LONG styleOld = ::GetWindowLong(hwnd, GWL_EXSTYLE); + LONG styleOld = wxGetWindowExStyle(this); LONG styleNew = styleOld; switch ( dir ) @@ -1012,13 +1182,13 @@ void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir) break; default: - wxFAIL_MSG(_T("unsupported layout direction")); + wxFAIL_MSG(wxT("unsupported layout direction")); break; } if ( styleNew != styleOld ) { - ::SetWindowLong(hwnd, GWL_EXSTYLE, styleNew); + wxSetWindowExStyle(this, styleNew); } #endif } @@ -1028,12 +1198,10 @@ wxLayoutDirection wxWindowMSW::GetLayoutDirection() const #ifdef __WXWINCE__ return wxLayout_Default; #else - const HWND hwnd = GetHwnd(); - wxCHECK_MSG( hwnd, wxLayout_Default, _T("invalid window") ); + wxCHECK_MSG( GetHwnd(), wxLayout_Default, wxT("invalid window") ); - return ::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL - ? wxLayout_RightToLeft - : wxLayout_LeftToRight; + return wxHasWindowExStyle(this, WS_EX_LAYOUTRTL) ? wxLayout_RightToLeft + : wxLayout_LeftToRight; #endif } @@ -1058,6 +1226,8 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) HWND hwnd = (HWND)hWnd; wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") ); + SetHWND(hWnd); + wxAssociateWinWithHandle(hwnd, this); m_oldWndProc = (WXFARPROC)wxGetWindowProc((HWND)hWnd); @@ -1079,7 +1249,7 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) // we're officially created now, send the event wxWindowCreateEvent event((wxWindow *)this); - (void)GetEventHandler()->ProcessEvent(event); + (void)HandleWindowEvent(event); } void wxWindowMSW::UnsubclassWin() @@ -1111,12 +1281,14 @@ void wxWindowMSW::AssociateHandle(WXWidget handle) if ( m_hWnd ) { if ( !::DestroyWindow(GetHwnd()) ) + { wxLogLastError(wxT("DestroyWindow")); + } } WXHWND wxhwnd = (WXHWND)handle; - SetHWND(wxhwnd); + // this also calls SetHWND(wxhwnd) SubclassWin(wxhwnd); } @@ -1130,36 +1302,12 @@ void wxWindowMSW::DissociateHandle() bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC WXUNUSED(wndProc)) { -// TODO: This list of window class names should be factored out so they can be -// managed in one place and then accessed from here and other places, such as -// wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses() + const wxString str(wxGetWindowClass(hWnd)); -#ifdef __WXWINCE__ - extern wxChar *wxCanvasClassName; - extern wxChar *wxCanvasClassNameNR; -#else - extern const wxChar *wxCanvasClassName; - extern const wxChar *wxCanvasClassNameNR; -#endif - extern const wxChar *wxMDIFrameClassName; - extern const wxChar *wxMDIFrameClassNameNoRedraw; - extern const wxChar *wxMDIChildFrameClassName; - extern const wxChar *wxMDIChildFrameClassNameNoRedraw; - wxString str(wxGetWindowClass(hWnd)); - if (str == wxCanvasClassName || - str == wxCanvasClassNameNR || -#if wxUSE_GLCANVAS - str == _T("wxGLCanvasClass") || - str == _T("wxGLCanvasClassNR") || -#endif // wxUSE_GLCANVAS - str == wxMDIFrameClassName || - str == wxMDIFrameClassNameNoRedraw || - str == wxMDIChildFrameClassName || - str == wxMDIChildFrameClassNameNoRedraw || - str == _T("wxTLWHiddenParent")) - return true; // Effectively means don't subclass - else - return false; + // TODO: get rid of wxTLWHiddenParent special case (currently it's not + // registered by wxApp but using ad hoc code in msw/toplevel.cpp); + // there is also a hidden window class used by sockets &c + return wxApp::IsRegisteredClassName(str) || str == wxT("wxTLWHiddenParent"); } // ---------------------------------------------------------------------------- @@ -1242,14 +1390,14 @@ void wxWindowMSW::MSWUpdateStyle(long flagsOld, long exflagsOld) } // and the extended style - long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE); + long exstyleReal = wxGetWindowExStyle(this); if ( exstyle != exstyleOld ) { exstyleReal &= ~exstyleOld; exstyleReal |= exstyle; - ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal); + wxSetWindowExStyle(this, exstyleReal); // ex style changes don't take effect without calling SetWindowPos callSWP = true; @@ -1266,11 +1414,48 @@ void wxWindowMSW::MSWUpdateStyle(long flagsOld, long exflagsOld) 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED) ) { - wxLogLastError(_T("SetWindowPos")); + wxLogLastError(wxT("SetWindowPos")); } } } +wxBorder wxWindowMSW::GetDefaultBorderForControl() const +{ + return wxBORDER_THEME; +} + +wxBorder wxWindowMSW::GetDefaultBorder() const +{ + return wxWindowBase::GetDefaultBorder(); +} + +// Translate wxBORDER_THEME (and other border styles if necessary) to the value +// that makes most sense for this Windows environment +wxBorder wxWindowMSW::TranslateBorder(wxBorder border) const +{ +#if defined(__POCKETPC__) || defined(__SMARTPHONE__) + if (border == wxBORDER_THEME || border == wxBORDER_SUNKEN || border == wxBORDER_SIMPLE) + return wxBORDER_SIMPLE; + else + return wxBORDER_NONE; +#else +#if wxUSE_UXTHEME + if (border == wxBORDER_THEME) + { + if (CanApplyThemeBorder()) + { + wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive(); + if (theme) + return wxBORDER_THEME; + } + return wxBORDER_SUNKEN; + } +#endif + return border; +#endif +} + + WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const { // translate common wxWidgets styles to Windows ones @@ -1300,7 +1485,10 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const if ( flags & wxHSCROLL ) style |= WS_HSCROLL; - const wxBorder border = GetBorder(flags); + const wxBorder border = TranslateBorder(GetBorder(flags)); + + // After translation, border is now optimized for the specific version of Windows + // and theme engine presence. // WS_BORDER is only required for wxBORDER_SIMPLE if ( border == wxBORDER_SIMPLE ) @@ -1320,11 +1508,12 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const { default: case wxBORDER_DEFAULT: - wxFAIL_MSG( _T("unknown border style") ); + wxFAIL_MSG( wxT("unknown border style") ); // fall through case wxBORDER_NONE: case wxBORDER_SIMPLE: + case wxBORDER_THEME: break; case wxBORDER_STATIC: @@ -1340,9 +1529,9 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const style &= ~WS_BORDER; break; - case wxBORDER_DOUBLE: - *exstyle |= WS_EX_DLGMODALFRAME; - break; +// case wxBORDER_DOUBLE: +// *exstyle |= WS_EX_DLGMODALFRAME; +// break; } // wxUniv doesn't use Windows dialog navigation functions at all @@ -1400,7 +1589,7 @@ void wxWindowMSW::OnInternalIdle() } #endif // !HAVE_TRACKMOUSEEVENT - if (wxUpdateUIEvent::CanUpdate(this)) + if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen()) UpdateWindowUI(wxUPDATE_UI_FROMIDLE); } @@ -1416,7 +1605,7 @@ bool wxWindowMSW::Reparent(wxWindowBase *parent) ::SetParent(hWndChild, hWndParent); #ifndef __WXWINCE__ - if ( ::GetWindowLong(hWndChild, GWL_EXSTYLE) & WS_EX_CONTROLPARENT ) + if ( wxHasWindowExStyle(this, WS_EX_CONTROLPARENT) ) { EnsureParentHasControlParentStyle(GetParent()); } @@ -1432,30 +1621,24 @@ static inline void SendSetRedraw(HWND hwnd, bool on) #endif } -void wxWindowMSW::Freeze() +void wxWindowMSW::DoFreeze() { - if ( !m_frozenness++ ) - { - if ( IsShown() ) - SendSetRedraw(GetHwnd(), false); - } + if ( !IsShown() ) + return; // no point in freezing hidden window + + SendSetRedraw(GetHwnd(), false); } -void wxWindowMSW::Thaw() +void wxWindowMSW::DoThaw() { - wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") ); + if ( !IsShown() ) + return; // hidden windows aren't frozen by DoFreeze - if ( --m_frozenness == 0 ) - { - if ( IsShown() ) - { - SendSetRedraw(GetHwnd(), true); + SendSetRedraw(GetHwnd(), true); - // we need to refresh everything or otherwise the invalidated area - // is not going to be repainted - Refresh(); - } - } + // we need to refresh everything or otherwise the invalidated area + // is not going to be repainted + Refresh(); } void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect) @@ -1467,11 +1650,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 @@ -1496,7 +1675,7 @@ void wxWindowMSW::Update() { if ( !::UpdateWindow(GetHwnd()) ) { - wxLogLastError(_T("UpdateWindow")); + wxLogLastError(wxT("UpdateWindow")); } #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) @@ -1598,11 +1777,11 @@ void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip) bool wxWindowMSW::IsSizeDeferred() const { -#if USE_DEFERRED_SIZING +#if wxUSE_DEFERRED_SIZING if ( m_pendingPosition != wxDefaultPosition || m_pendingSize != wxDefaultSize ) return true; -#endif // USE_DEFERRED_SIZING +#endif // wxUSE_DEFERRED_SIZING return false; } @@ -1610,7 +1789,7 @@ bool wxWindowMSW::IsSizeDeferred() const // Get total size void wxWindowMSW::DoGetSize(int *x, int *y) const { -#if USE_DEFERRED_SIZING +#if wxUSE_DEFERRED_SIZING // if SetSize() had been called at wx level but not realized at Windows // level yet (i.e. EndDeferWindowPos() not called), we still should return // the new and not the old position to the other wx code @@ -1622,7 +1801,7 @@ void wxWindowMSW::DoGetSize(int *x, int *y) const *y = m_pendingSize.y; } else // use current size -#endif // USE_DEFERRED_SIZING +#endif // wxUSE_DEFERRED_SIZING { RECT rect = wxGetWindowRect(GetHwnd()); @@ -1636,7 +1815,7 @@ void wxWindowMSW::DoGetSize(int *x, int *y) const // Get size *available for subwindows* i.e. excluding menu bar etc. void wxWindowMSW::DoGetClientSize(int *x, int *y) const { -#if USE_DEFERRED_SIZING +#if wxUSE_DEFERRED_SIZING if ( m_pendingSize != wxDefaultSize ) { // we need to calculate the client size corresponding to pending size @@ -1654,7 +1833,7 @@ void wxWindowMSW::DoGetClientSize(int *x, int *y) const *y = rect.bottom - rect.top; } else -#endif // USE_DEFERRED_SIZING +#endif // wxUSE_DEFERRED_SIZING { RECT rect = wxGetClientRect(GetHwnd()); @@ -1755,7 +1934,7 @@ void wxWindowMSW::DoClientToScreen(int *x, int *y) const bool wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height) { -#if USE_DEFERRED_SIZING +#if wxUSE_DEFERRED_SIZING // if our parent had prepared a defer window handle for us, use it (unless // we are a top level window) wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent(); @@ -1767,7 +1946,7 @@ wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height) SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE); if ( !hdwp ) { - wxLogLastError(_T("DeferWindowPos")); + wxLogLastError(wxT("DeferWindowPos")); } } @@ -1785,13 +1964,13 @@ wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height) } // otherwise (or if deferring failed) move the window in place immediately -#endif // USE_DEFERRED_SIZING +#endif // wxUSE_DEFERRED_SIZING if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) ) { wxLogLastError(wxT("MoveWindow")); } - // if USE_DEFERRED_SIZING, indicates that we didn't use deferred move, + // if wxUSE_DEFERRED_SIZING, indicates that we didn't use deferred move, // ignored otherwise return false; } @@ -1807,10 +1986,15 @@ void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height) if ( DoMoveSibling(m_hWnd, x, y, width, height) ) { -#if USE_DEFERRED_SIZING +#if wxUSE_DEFERRED_SIZING m_pendingPosition = wxPoint(x, y); m_pendingSize = wxSize(width, height); -#endif // USE_DEFERRED_SIZING + } + else // window was moved immediately, without deferring it + { + m_pendingPosition = wxDefaultPosition; + m_pendingSize = wxDefaultSize; +#endif // wxUSE_DEFERRED_SIZING } } @@ -1837,6 +2021,12 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) width == currentW && height == currentH && !(sizeFlags & wxSIZE_FORCE) ) { + if (sizeFlags & wxSIZE_FORCE_EVENT) + { + wxSizeEvent event( wxSize(width,height), GetId() ); + event.SetEventObject( this ); + HandleWindowEvent( event ); + } return; } @@ -1852,7 +2042,7 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) { if ( sizeFlags & wxSIZE_AUTO_WIDTH ) { - size = DoGetBestSize(); + size = GetBestSize(); width = size.x; } else @@ -1868,9 +2058,9 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) { if ( size.x == wxDefaultCoord ) { - size = DoGetBestSize(); + size = GetBestSize(); } - //else: already called DoGetBestSize() above + //else: already called GetBestSize() above height = size.y; } @@ -1942,11 +2132,41 @@ void wxWindowMSW::DoSetClientSize(int width, int height) height + heightWin - rectClient.bottom, TRUE) ) { - wxLogLastError(_T("MoveWindow")); + wxLogLastError(wxT("MoveWindow")); } } } +wxSize wxWindowMSW::DoGetBorderSize() const +{ + wxCoord border; + switch ( GetBorder() ) + { + case wxBORDER_STATIC: + case wxBORDER_SIMPLE: + border = 1; + break; + + case wxBORDER_SUNKEN: + border = 2; + break; + + case wxBORDER_RAISED: + case wxBORDER_DOUBLE: + border = 3; + break; + + default: + wxFAIL_MSG( wxT("unknown border style") ); + // fall through + + case wxBORDER_NONE: + border = 0; + } + + return 2*wxSize(border, border); +} + // --------------------------------------------------------------------------- // text metrics // --------------------------------------------------------------------------- @@ -1967,26 +2187,27 @@ int wxWindowMSW::GetCharWidth() const #endif } -void wxWindowMSW::GetTextExtent(const wxString& string, - int *x, int *y, - int *descent, int *externalLeading, - const wxFont *theFont) const +void wxWindowMSW::DoGetTextExtent(const wxString& string, + int *x, int *y, + int *descent, + int *externalLeading, + const wxFont *fontToUse) const { - wxASSERT_MSG( !theFont || theFont->Ok(), - _T("invalid font in GetTextExtent()") ); + wxASSERT_MSG( !fontToUse || fontToUse->Ok(), + wxT("invalid font in GetTextExtent()") ); - wxFont fontToUse; - if (theFont) - fontToUse = *theFont; + HFONT hfontToUse; + if ( fontToUse ) + hfontToUse = GetHfontOf(*fontToUse); else - fontToUse = GetFont(); + hfontToUse = GetHfontOf(GetFont()); WindowHDC hdc(GetHwnd()); - SelectInHDC selectFont(hdc, GetHfontOf(fontToUse)); + SelectInHDC selectFont(hdc, hfontToUse); SIZE sizeRect; TEXTMETRIC tm; - ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect); + ::GetTextExtentPoint32(hdc, string.wx_str(), string.length(), &sizeRect); GetTextMetrics(hdc, &tm); if ( x ) @@ -2049,7 +2270,6 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) point.x = x; point.y = y; ::ClientToScreen(hWnd, &point); - wxCurrentPopupMenu = menu; #if defined(__WXWINCE__) static const UINT flags = 0; #else // !__WXWINCE__ @@ -2078,8 +2298,6 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) // for example) and so we do need to process the event immediately wxYieldForCommandsOnly(); - wxCurrentPopupMenu = NULL; - menu->SetInvokingWindow(NULL); return true; @@ -2181,13 +2399,6 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) case VK_RETURN: { - if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown ) - { - // control wants to process Enter itself, don't - // call IsDialogMessage() which would consume it - return false; - } - #if wxUSE_BUTTON // currently active button should get enter press even // if there is a default button elsewhere so check if @@ -2202,16 +2413,56 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW ) { // emulate the button click - btn = wxFindWinFromHandle((WXHWND)msg->hwnd); + btn = wxFindWinFromHandle(msg->hwnd); } bProcess = false; } else // not a button itself, do we have default button? { - wxTopLevelWindow * - tlw = wxDynamicCast(wxGetTopLevelParent(this), - wxTopLevelWindow); + // check if this window or any of its ancestors + // wants the message for itself (we always reserve + // Ctrl-Enter for dialog navigation though) + wxWindow *win = this; + if ( !bCtrlDown ) + { + // this will contain the dialog code of this + // window and all of its parent windows in turn + LONG lDlgCode2 = lDlgCode; + + while ( win ) + { + if ( lDlgCode2 & DLGC_WANTMESSAGE ) + { + // as it wants to process Enter itself, + // don't call IsDialogMessage() which + // would consume it + return false; + } + + // don't propagate keyboard messages beyond + // the first top level window parent + if ( win->IsTopLevel() ) + break; + + win = win->GetParent(); + + lDlgCode2 = ::SendMessage + ( + GetHwndOf(win), + WM_GETDLGCODE, + 0, + 0 + ); + } + } + else // bCtrlDown + { + win = wxGetTopLevelParent(win); + } + + wxTopLevelWindow * const + tlw = wxDynamicCast(win, wxTopLevelWindow); if ( tlw ) { btn = wxDynamicCast(tlw->GetDefaultItem(), @@ -2231,7 +2482,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) // map Enter presses into button presses on PDAs wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN); event.SetEventObject(this); - if ( GetEventHandler()->ProcessEvent(event) ) + if ( HandleWindowEvent(event) ) return true; #endif // __WXWINCE__ } @@ -2249,7 +2500,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) event.SetFromTab(bFromTab); event.SetEventObject(this); - if ( GetEventHandler()->ProcessEvent(event) ) + if ( HandleWindowEvent(event) ) { // as we don't call IsDialogMessage(), which would take of // this by default, we need to manually send this message @@ -2340,8 +2591,7 @@ bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg) { wxWindow * const win = node->GetData(); if ( win->CanAcceptFocus() && - !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) & - WS_EX_CONTROLPARENT) ) + !wxHasWindowExStyle(win, WS_EX_CONTROLPARENT) ) { // it shouldn't hang... canSafelyCallIsDlgMsg = true; @@ -2450,14 +2700,15 @@ wxWindowCreationHook::~wxWindowCreationHook() // Main window proc LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - // trace all messages - useful for the debugging -#ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, - wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"), - wxGetMessageName(message), (long)hWnd, (long)wParam, lParam); -#endif // __WXDEBUG__ + // trace all messages: useful for the debugging but noticeably slows down + // the code so don't do it by default +#if wxDEBUG_LEVEL >= 2 + wxLogTrace("winmsg", + wxT("Processing %s(hWnd=%p, wParam=%08lx, lParam=%08lx)"), + wxGetMessageName(message), hWnd, (long)wParam, lParam); +#endif // wxDEBUG_LEVEL >= 2 - wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd); + wxWindowMSW *wnd = wxFindWinFromHandle(hWnd); // when we get the first message for the HWND we just created, we associate // it with wxWindow stored in gs_winBeingCreated @@ -2471,7 +2722,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); @@ -2543,7 +2794,19 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l } } break; +#if 0 + case WM_ENTERSIZEMOVE: + { + processed = HandleEnterSizeMove(); + } + break; + case WM_EXITSIZEMOVE: + { + processed = HandleExitSizeMove(); + } + break; +#endif case WM_SIZING: { LPRECT pRect = (LPRECT)lParam; @@ -2581,11 +2844,11 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l break; case WM_SETFOCUS: - processed = HandleSetFocus((WXHWND)(HWND)wParam); + processed = HandleSetFocus((WXHWND)wParam); break; case WM_KILLFOCUS: - processed = HandleKillFocus((WXHWND)(HWND)wParam); + processed = HandleKillFocus((WXHWND)wParam); break; case WM_PRINTCLIENT: @@ -2659,6 +2922,11 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDBLCLK: +#ifdef wxHAS_XBUTTON + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: + case WM_XBUTTONDBLCLK: +#endif // wxHAS_XBUTTON { #ifdef __WXMICROWIN__ // MicroWindows seems to ignore the fact that a window is @@ -2702,7 +2970,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l // this should never happen wxCHECK_MSG( win, 0, - _T("FindWindowForMouseEvent() returned NULL") ); + wxT("FindWindowForMouseEvent() returned NULL") ); } #ifdef __POCKETPC__ if (IsContextMenuEnabled() && message == WM_LBUTTONDOWN) @@ -2725,7 +2993,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); evtCtx.SetEventObject(this); - if (GetEventHandler()->ProcessEvent(evtCtx)) + if (HandleWindowEvent(evtCtx)) { processed = true; return true; @@ -2749,7 +3017,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->CanAcceptFocus() ) + if ( message == WM_LBUTTONDOWN && win->IsFocusable() ) win->SetFocus(); } } @@ -2802,23 +3070,15 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l // for these messages we must return true if process the message #ifdef WM_DRAWITEM case WM_DRAWITEM: - case WM_MEASUREITEM: - { - int idCtrl = (UINT)wParam; - if ( message == WM_DRAWITEM ) - { - processed = MSWOnDrawItem(idCtrl, - (WXDRAWITEMSTRUCT *)lParam); - } - else - { - processed = MSWOnMeasureItem(idCtrl, - (WXMEASUREITEMSTRUCT *)lParam); - } + processed = MSWOnDrawItem(wParam, (WXDRAWITEMSTRUCT *)lParam); + if ( processed ) + rc.result = TRUE; + break; - if ( processed ) - rc.result = TRUE; - } + case WM_MEASUREITEM: + processed = MSWOnMeasureItem(wParam, (WXMEASUREITEMSTRUCT *)lParam); + if ( processed ) + rc.result = TRUE; break; #endif // defined(WM_DRAWITEM) @@ -2878,6 +3138,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l case VK_SUBTRACT: case VK_MULTIPLY: case VK_DIVIDE: + case VK_DECIMAL: case VK_NUMPAD0: case VK_NUMPAD1: case VK_NUMPAD2: @@ -2959,6 +3220,12 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l break; #endif // wxUSE_HOTKEY + case WM_CUT: + case WM_COPY: + case WM_PASTE: + processed = HandleClipboardEvent(message); + break; + case WM_HSCROLL: case WM_VSCROLL: { @@ -3004,11 +3271,11 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l #endif case WM_PALETTECHANGED: - processed = HandlePaletteChanged((WXHWND) (HWND) wParam); + processed = HandlePaletteChanged((WXHWND)wParam); break; case WM_CAPTURECHANGED: - processed = HandleCaptureChanged((WXHWND) (HWND) lParam); + processed = HandleCaptureChanged((WXHWND)lParam); break; case WM_SETTINGCHANGE: @@ -3020,7 +3287,17 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l break; case WM_ERASEBKGND: - processed = HandleEraseBkgnd((WXHDC)(HDC)wParam); + { +#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK + // check if an override was configured for this window + EraseBgHooks::const_iterator it = gs_eraseBgHooks.find(this); + if ( it != gs_eraseBgHooks.end() ) + processed = it->second->MSWEraseBgHook((WXHDC)wParam); + else +#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK + processed = HandleEraseBkgnd((WXHDC)wParam); + } + if ( processed ) { // we processed the message, i.e. erased the background @@ -3035,7 +3312,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l #endif case WM_INITDIALOG: - processed = HandleInitDialog((WXHWND)(HWND)wParam); + processed = HandleInitDialog((WXHWND)wParam); if ( processed ) { @@ -3059,7 +3336,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l #endif case WM_SETCURSOR: - processed = HandleSetCursor((WXHWND)(HWND)wParam, + processed = HandleSetCursor((WXHWND)wParam, LOWORD(lParam), // hit test HIWORD(lParam)); // mouse msg @@ -3113,14 +3390,14 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l ); helpEvent.SetEventObject(this); - GetEventHandler()->ProcessEvent(helpEvent); + HandleWindowEvent(helpEvent); #ifndef __WXWINCE__ } else if ( info->iContextType == HELPINFO_MENUITEM ) { wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId); helpEvent.SetEventObject(this); - GetEventHandler()->ProcessEvent(helpEvent); + HandleWindowEvent(helpEvent); } else // unknown help event? @@ -3144,20 +3421,22 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l // we could have got an event from our child, reflect it back // to it if this is the case wxWindowMSW *win = NULL; - if ( (WXHWND)wParam != m_hWnd ) + WXHWND hWnd = (WXHWND)wParam; + if ( hWnd != m_hWnd ) { - win = FindItemByHWND((WXHWND)wParam); + win = FindItemByHWND(hWnd); } if ( !win ) win = this; evtCtx.SetEventObject(win); - processed = win->GetEventHandler()->ProcessEvent(evtCtx); + processed = win->HandleWindowEvent(evtCtx); } break; #endif +#if wxUSE_MENUS case WM_MENUCHAR: // we're only interested in our own menus, not MF_SYSMENU if ( HIWORD(wParam) == MF_POPUP ) @@ -3171,6 +3450,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l } } break; +#endif // wxUSE_MENUS #ifndef __WXWINCE__ case WM_POWERBROADCAST: @@ -3182,6 +3462,108 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l break; #endif // __WXWINCE__ +#if wxUSE_UXTHEME + // If we want the default themed border then we need to draw it ourselves + case WM_NCCALCSIZE: + { + wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive(); + const wxBorder border = TranslateBorder(GetBorder()); + if (theme && border == wxBORDER_THEME) + { + // first ask the widget to calculate the border size + rc.result = MSWDefWindowProc(message, wParam, lParam); + processed = true; + + // now alter the client size making room for drawing a + // themed border + RECT *rect; + NCCALCSIZE_PARAMS *csparam = NULL; + if ( wParam ) + { + csparam = (NCCALCSIZE_PARAMS *)lParam; + rect = &csparam->rgrc[0]; + } + else + { + rect = (RECT *)lParam; + } + + wxUxThemeHandle hTheme((const wxWindow *)this, L"EDIT"); + RECT rcClient = { 0, 0, 0, 0 }; + wxClientDC dc((wxWindow *)this); + wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); + + if ( theme->GetThemeBackgroundContentRect + ( + hTheme, + GetHdcOf(*impl), + EP_EDITTEXT, + ETS_NORMAL, + rect, + &rcClient) == S_OK ) + { + InflateRect(&rcClient, -1, -1); + if (wParam) + csparam->rgrc[0] = rcClient; + else + *((RECT*)lParam) = rcClient; + + // WVR_REDRAW triggers a bug whereby child windows are moved up and left, + // so don't use. + // rc.result = WVR_REDRAW; + } + } + } + break; + + case WM_NCPAINT: + { + wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive(); + const wxBorder border = TranslateBorder(GetBorder()); + if (theme && border == wxBORDER_THEME) + { + // first ask the widget to paint its non-client area, such as scrollbars, etc. + rc.result = MSWDefWindowProc(message, wParam, lParam); + processed = true; + + wxUxThemeHandle hTheme((const wxWindow *)this, L"EDIT"); + wxWindowDC dc((wxWindow *)this); + wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); + + // Clip the DC so that you only draw on the non-client area + RECT rcBorder; + wxCopyRectToRECT(GetSize(), rcBorder); + + RECT rcClient; + theme->GetThemeBackgroundContentRect( + hTheme, GetHdcOf(*impl), EP_EDITTEXT, ETS_NORMAL, &rcBorder, &rcClient); + InflateRect(&rcClient, -1, -1); + + ::ExcludeClipRect(GetHdcOf(*impl), rcClient.left, rcClient.top, + rcClient.right, rcClient.bottom); + + // Make sure the background is in a proper state + if (theme->IsThemeBackgroundPartiallyTransparent(hTheme, EP_EDITTEXT, ETS_NORMAL)) + { + theme->DrawThemeParentBackground(GetHwnd(), GetHdcOf(*impl), &rcBorder); + } + + // Draw the border + int nState; + if ( !IsEnabled() ) + nState = ETS_DISABLED; + // should we check this? + //else if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & ES_READONLY) + // nState = ETS_READONLY; + else + nState = ETS_NORMAL; + theme->DrawThemeBackground(hTheme, GetHdcOf(*impl), EP_EDITTEXT, nState, &rcBorder, NULL); + } + } + break; + +#endif // wxUSE_UXTHEME + default: // try a custom message handler const MSWMessageHandlers::const_iterator @@ -3194,10 +3576,10 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l if ( !processed ) { -#ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."), +#if wxDEBUG_LEVEL >= 2 + wxLogTrace("winmsg", wxT("Forwarding %s to DefWindowProc."), wxGetMessageName(message)); -#endif // __WXDEBUG__ +#endif // wxDEBUG_LEVEL >= 2 rc.result = MSWDefWindowProc(message, wParam, lParam); } @@ -3208,38 +3590,44 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l // wxWindow <-> HWND map // ---------------------------------------------------------------------------- -wxWinHashTable *wxWinHandleHash = NULL; - -wxWindow *wxFindWinFromHandle(WXHWND hWnd) +wxWindow *wxFindWinFromHandle(HWND hwnd) { - return (wxWindow*)wxWinHandleHash->Get((long)hWnd); + WindowHandles::const_iterator i = gs_windowHandles.find(hwnd); + return i == gs_windowHandles.end() ? NULL : i->second; } -void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) +void wxAssociateWinWithHandle(HWND hwnd, wxWindowMSW *win) { - // adding NULL hWnd is (first) surely a result of an error and + // adding NULL hwnd is (first) surely a result of an error and // (secondly) breaks menu command processing - wxCHECK_RET( hWnd != (HWND)NULL, - wxT("attempt to add a NULL hWnd to window list ignored") ); + wxCHECK_RET( hwnd != (HWND)NULL, + wxT("attempt to add a NULL hwnd to window list ignored") ); - wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd); -#ifdef __WXDEBUG__ - if ( oldWin && (oldWin != win) ) - { - wxLogDebug(wxT("HWND %X already associated with another window (%s)"), - (int) hWnd, win->GetClassInfo()->GetClassName()); - } - else -#endif // __WXDEBUG__ - if (!oldWin) +#if wxDEBUG_LEVEL + WindowHandles::const_iterator i = gs_windowHandles.find(hwnd); + if ( i != gs_windowHandles.end() ) { - wxWinHandleHash->Put((long)hWnd, (wxWindow *)win); + if ( i->second != win ) + { + wxFAIL_MSG( + wxString::Format( + wxT("HWND %p already associated with another window (%s)"), + hwnd, win->GetClassInfo()->GetClassName() + ) + ); + } + //else: this actually happens currently because we associate the window + // with its HWND during creation (if we create it) and also when + // SubclassWin() is called later, this is ok } +#endif // wxDEBUG_LEVEL + + gs_windowHandles[hwnd] = (wxWindow *)win; } void wxRemoveHandleAssociation(wxWindowMSW *win) { - wxWinHandleHash->Delete((long)win->GetHWND()); + gs_windowHandles.erase(GetHwndOf(win)); } // ---------------------------------------------------------------------------- @@ -3353,6 +3741,17 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, WXDWORD style, WXDWORD extendedStyle) { + // check a common bug in the user code: if the window is created with a + // non-default ctor and Create() is called too, we'd create 2 HWND for a + // single wxWindow object and this results in all sorts of trouble, + // especially for wxTLWs + wxCHECK_MSG( !m_hWnd, true, "window can't be recreated" ); + + // this can happen if this function is called using the return value of + // wxApp::GetRegisteredClassName() which failed + wxCHECK_MSG( wclass, false, "failed to register window class?" ); + + // choose the position/size for the new window int x, y, w, h; (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h); @@ -3367,7 +3766,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, wxString className(wclass); if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) ) { - className += wxT("NR"); + className += wxApp::GetNoRedrawClassSuffix(); } // do create the window @@ -3376,12 +3775,12 @@ 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(), - (HMENU)controlId, + (HMENU)wxUIntToPtr(controlId), wxGetInstance(), NULL // no extra data ); @@ -3411,7 +3810,7 @@ bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) #ifndef __WXMICROWIN__ LPNMHDR hdr = (LPNMHDR)lParam; HWND hWnd = hdr->hwndFrom; - wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd); + wxWindow *win = wxFindWinFromHandle(hWnd); // if the control is one of our windows, let it handle the message itself if ( win ) @@ -3497,7 +3896,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code, ( CP_ACP, 0, // no flags - ttip, + ttip.wx_str(), tipLength, buf, WXSIZEOF(buf) - 1 @@ -3505,7 +3904,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code, if ( !len ) { - wxLogLastError(_T("MultiByteToWideChar()")); + wxLogLastError(wxT("MultiByteToWideChar()")); } buf[len] = L'\0'; @@ -3518,8 +3917,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code, // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have // to copy the string we have into the buffer static wxChar buf[513]; - wxStrncpy(buf, ttip.c_str(), WXSIZEOF(buf) - 1); - buf[WXSIZEOF(buf) - 1] = _T('\0'); + wxStrlcpy(buf, ttip.c_str(), WXSIZEOF(buf)); ttText->lpszText = buf; } @@ -3592,7 +3990,7 @@ bool wxWindowMSW::HandleEndSession(bool endSession, long logOff) wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY); event.SetEventObject(wxTheApp); event.SetCanVeto(false); - event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) ); + event.SetLoggingOff((logOff & ENDSESSION_LOGOFF) != 0); return wxTheApp->ProcessEvent(event); #else @@ -3624,8 +4022,6 @@ bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED_IN_WINCE(cs), bool wxWindowMSW::HandleDestroy() { - SendDestroyEvent(); - // delete our drop target if we've got one #if wxUSE_DRAG_AND_DROP if ( m_dropTarget != NULL ) @@ -3654,7 +4050,7 @@ bool wxWindowMSW::HandleActivate(int state, m_windowId); event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleSetFocus(WXHWND hwnd) @@ -3669,7 +4065,7 @@ bool wxWindowMSW::HandleSetFocus(WXHWND hwnd) // notify the parent keeping track of focus for the kbd navigation // purposes that we got it wxChildFocusEvent eventFocus((wxWindow *)this); - (void)GetEventHandler()->ProcessEvent(eventFocus); + (void)HandleWindowEvent(eventFocus); #if wxUSE_CARET // Deal with caret @@ -3679,22 +4075,13 @@ bool wxWindowMSW::HandleSetFocus(WXHWND hwnd) } #endif // wxUSE_CARET -#if wxUSE_TEXTCTRL - // If it's a wxTextCtrl don't send the event as it will be done - // after the control gets to process it from EN_FOCUS handler - if ( wxDynamicCastThis(wxTextCtrl) ) - { - return false; - } -#endif // wxUSE_TEXTCTRL - wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId); event.SetEventObject(this); // wxFindWinFromHandle() may return NULL, it is ok event.SetWindow(wxFindWinFromHandle(hwnd)); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) @@ -3707,16 +4094,6 @@ bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) } #endif // wxUSE_CARET -#if wxUSE_TEXTCTRL - // If it's a wxTextCtrl don't send the event as it will be done - // after the control gets to process it. - wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl); - if ( ctrl ) - { - return false; - } -#endif - // Don't send the event when in the process of being deleted. This can // only cause problems if the event handler tries to access the object. if ( m_isBeingDeleted ) @@ -3730,7 +4107,7 @@ bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) // wxFindWinFromHandle() may return NULL, it is ok event.SetWindow(wxFindWinFromHandle(hwnd)); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } // --------------------------------------------------------------------------- @@ -3756,7 +4133,7 @@ bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status)) wxShowEvent event(GetId(), show); event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) @@ -3764,7 +4141,7 @@ bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) wxInitDialogEvent event(GetId()); event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) @@ -3794,7 +4171,6 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) ::DragQueryFile(hFilesInfo, wIndex, wxStringBuffer(files[wIndex], len), len); } - DragFinish (hFilesInfo); wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files); event.SetEventObject(this); @@ -3804,7 +4180,9 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) event.m_pos.x = dropPoint.x; event.m_pos.y = dropPoint.y; - return GetEventHandler()->ProcessEvent(event); + DragFinish(hFilesInfo); + + return HandleWindowEvent(event); #endif } @@ -3815,63 +4193,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 = HandleWindowEvent(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() ) @@ -3882,10 +4253,9 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), } } + if ( hcursor ) { -// wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor); - ::SetCursor(hcursor); // cursor set, stop here @@ -3921,14 +4291,11 @@ bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam), break; case PBT_APMRESUMESUSPEND: -#ifdef PBT_APMRESUMEAUTOMATIC - case PBT_APMRESUMEAUTOMATIC: -#endif evtType = wxEVT_POWER_RESUME; break; default: - wxLogDebug(_T("Unknown WM_POWERBROADCAST(%d) event"), wParam); + wxLogDebug(wxT("Unknown WM_POWERBROADCAST(%d) event"), wParam); // fall through // these messages are currently not mapped to wx events @@ -3940,6 +4307,9 @@ bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam), case PBT_APMPOWERSTATUSCHANGE: case PBT_APMOEMEVENT: case PBT_APMRESUMECRITICAL: +#ifdef PBT_APMRESUMEAUTOMATIC + case PBT_APMRESUMEAUTOMATIC: +#endif evtType = wxEVT_NULL; break; } @@ -3951,7 +4321,7 @@ bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam), // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events? wxPowerEvent event(evtType); - if ( !GetEventHandler()->ProcessEvent(event) ) + if ( !HandleWindowEvent(event) ) return false; *vetoed = event.IsVetoed(); @@ -3962,17 +4332,33 @@ bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam), bool wxWindowMSW::IsDoubleBuffered() const { - for ( const wxWindowMSW *wnd = this; - wnd && !wnd->IsTopLevel(); wnd = - wnd->GetParent() ) + for ( const wxWindowMSW *win = this; win; win = win->GetParent() ) { - if ( ::GetWindowLong(GetHwndOf(wnd), GWL_EXSTYLE) & WS_EX_COMPOSITED ) + if ( wxHasWindowExStyle(win, WS_EX_COMPOSITED) ) return true; + + if ( win->IsTopLevel() ) + break; } return false; } +void wxWindowMSW::SetDoubleBuffered(bool on) +{ + // Get the current extended style bits + long exstyle = wxGetWindowExStyle(this); + + // Twiddle the bit as needed + if ( on ) + exstyle |= WS_EX_COMPOSITED; + else + exstyle &= ~WS_EX_COMPOSITED; + + // put it back + wxSetWindowExStyle(this, exstyle); +} + // --------------------------------------------------------------------------- // owner drawn stuff // --------------------------------------------------------------------------- @@ -4002,7 +4388,7 @@ wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id), return false; wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem), - false, _T("MSWOnDrawItem: bad wxMenuItem pointer") ); + false, wxT("MSWOnDrawItem: bad wxMenuItem pointer") ); // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent // the DC from being released @@ -4068,7 +4454,7 @@ wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) return false; wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem), - false, _T("MSWOnMeasureItem: bad wxMenuItem pointer") ); + false, wxT("MSWOnMeasureItem: bad wxMenuItem pointer") ); size_t w, h; bool rc = pMenuItem->OnMeasureItem(&w, &h); @@ -4101,7 +4487,7 @@ bool wxWindowMSW::HandleSysColorChange() wxSysColourChangedEvent event; event.SetEventObject(this); - (void)GetEventHandler()->ProcessEvent(event); + (void)HandleWindowEvent(event); // always let the system carry on the default processing to allow the // native controls to react to the colours update @@ -4113,7 +4499,7 @@ bool wxWindowMSW::HandleDisplayChange() wxDisplayChangedEvent event; event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } #ifndef __WXMICROWIN__ @@ -4177,7 +4563,7 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange) event.SetEventObject(this); event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange)); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture) @@ -4189,7 +4575,7 @@ bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture) wxWindow *win = wxFindWinFromHandle(hWndGainedCapture); wxMouseCaptureChangedEvent event(GetId(), win); event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam) @@ -4244,7 +4630,7 @@ bool wxWindowMSW::HandleQueryNewPalette() wxQueryNewPaletteEvent event(GetId()); event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event) && event.GetPaletteRealized(); + return HandleWindowEvent(event) && event.GetPaletteRealized(); } // Responds to colour changes: passes event on to children. @@ -4295,12 +4681,12 @@ extern wxCOLORMAP *wxGetStdColourMap() // reference bitmap which can tell us what the RGB values change // to. wxLogNull logNo; // suppress error if we couldn't load the bitmap - wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS")); + wxBitmap stdColourBitmap(wxT("wxBITMAP_STD_COLOURS")); if ( stdColourBitmap.Ok() ) { // the pixels in the bitmap must correspond to wxSTD_COL_XXX! wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX, - _T("forgot to update wxBITMAP_STD_COLOURS!") ); + wxT("forgot to update wxBITMAP_STD_COLOURS!") ); wxMemoryDC memDC; memDC.SelectObject(stdColourBitmap); @@ -4343,6 +4729,69 @@ extern wxCOLORMAP *wxGetStdColourMap() return s_cmap; } +#if wxUSE_UXTHEME && !defined(TMT_FILLCOLOR) + #define TMT_FILLCOLOR 3802 + #define TMT_TEXTCOLOR 3803 + #define TMT_BORDERCOLOR 3801 +#endif + +wxColour wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName, + int themePart, + int themeState, + MSWThemeColour themeColour, + wxSystemColour fallback) +{ +#if wxUSE_UXTHEME + const wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive(); + if ( theme ) + { + int themeProperty = 0; + + // TODO: Convert this into a table? Sure would be faster. + switch ( themeColour ) + { + case ThemeColourBackground: + themeProperty = TMT_FILLCOLOR; + break; + case ThemeColourText: + themeProperty = TMT_TEXTCOLOR; + break; + case ThemeColourBorder: + themeProperty = TMT_BORDERCOLOR; + break; + default: + wxFAIL_MSG(wxT("unsupported theme colour")); + }; + + wxUxThemeHandle hTheme(this, themeName); + COLORREF col; + HRESULT hr = theme->GetThemeColor + ( + hTheme, + themePart, + themeState, + themeProperty, + &col + ); + + if ( SUCCEEDED(hr) ) + return wxRGBToColour(col); + + wxLogApiError( + wxString::Format( + "GetThemeColor(%s, %i, %i, %i)", + themeName, themePart, themeState, themeProperty), + hr); + } +#else + wxUnusedVar(themeName); + wxUnusedVar(themePart); + wxUnusedVar(themeState); + wxUnusedVar(themeColour); +#endif + return wxSystemSettings::GetColour(fallback); +} + // --------------------------------------------------------------------------- // painting // --------------------------------------------------------------------------- @@ -4351,23 +4800,31 @@ bool wxWindowMSW::HandlePaint() { HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle if ( !hRegion ) + { wxLogLastError(wxT("CreateRectRgn")); + } if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR ) + { wxLogLastError(wxT("GetUpdateRgn")); + } m_updateRegion = wxRegion((WXHRGN) hRegion); wxPaintEvent event(m_windowId); event.SetEventObject(this); - bool processed = GetEventHandler()->ProcessEvent(event); + bool processed = HandleWindowEvent(event); // note that we must generate NC event after the normal one as otherwise // BeginPaint() will happily overwrite our decorations with the background // colour wxNcPaintEvent eventNc(m_windowId); eventNc.SetEventObject(this); - GetEventHandler()->ProcessEvent(eventNc); + HandleWindowEvent(eventNc); + + // don't keep an HRGN we don't need any longer (GetUpdateRegion() can only + // be called from inside the event handlers called above) + m_updateRegion.Clear(); return processed; } @@ -4378,7 +4835,7 @@ void wxWindowMSW::OnPaint(wxPaintEvent& event) #ifdef __WXUNIVERSAL__ event.Skip(); #else - HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject()); + HDC hDC = (HDC) wxPaintDCImpl::FindDCInCache((wxWindow*) event.GetEventObject()); if (hDC != 0) { MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0); @@ -4388,62 +4845,103 @@ void wxWindowMSW::OnPaint(wxPaintEvent& event) bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) { - wxDCTemp dc(hdc, GetClientSize()); + switch ( GetBackgroundStyle() ) + { + case wxBG_STYLE_ERASE: + case wxBG_STYLE_COLOUR: + // we need to generate an erase background event + { + wxDCTemp dc(hdc, GetClientSize()); + wxDCTempImpl *impl = (wxDCTempImpl*) dc.GetImpl(); - dc.SetHDC(hdc); - dc.SetWindow((wxWindow *)this); + impl->SetHDC(hdc); + impl->SetWindow((wxWindow *)this); - wxEraseEvent event(m_windowId, &dc); - event.SetEventObject(this); - bool rc = GetEventHandler()->ProcessEvent(event); + wxEraseEvent event(m_windowId, &dc); + event.SetEventObject(this); + bool rc = HandleWindowEvent(event); - // must be called manually as ~wxDC doesn't do anything for wxDCTemp - dc.SelectOldObjects(hdc); + // must be called manually as ~wxDC doesn't do anything for + // wxDCTemp + impl->SelectOldObjects(hdc); - return rc; + if ( rc ) + { + // background erased by the user-defined handler + return true; + } + } + // fall through + + case wxBG_STYLE_SYSTEM: + if ( !DoEraseBackground(hdc) ) + { + // let the default processing to take place if we didn't erase + // the background ourselves + return false; + } + break; + + case wxBG_STYLE_PAINT: + case wxBG_STYLE_TRANSPARENT: + // no need to do anything here at all, background will be entirely + // redrawn in WM_PAINT handler + break; + + default: + wxFAIL_MSG( "unknown background style" ); + } + + return true; } -void wxWindowMSW::OnEraseBackground(wxEraseEvent& event) +#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK + +bool wxWindowMSW::MSWHasEraseBgHook() const { - // standard non top level controls (i.e. except the dialogs) always erase - // their background themselves in HandleCtlColor() or have some control- - // specific ways to set the colours (common controls) - if ( IsOfStandardClass() && !IsTopLevel() ) - { - event.Skip(); - return; - } + return gs_eraseBgHooks.find(this) != gs_eraseBgHooks.end(); +} - if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM ) +void wxWindowMSW::MSWSetEraseBgHook(wxWindow *child) +{ + if ( child ) { - // don't skip the event here, custom background means that the app - // is drawing it itself in its OnPaint(), so don't draw it at all - // now to avoid flicker - return; + if ( !gs_eraseBgHooks.insert( + EraseBgHooks::value_type(this, child)).second ) + { + wxFAIL_MSG( wxT("Setting erase background hook twice?") ); + } } - - - // do default background painting - if ( !DoEraseBackground(GetHdcOf(*event.GetDC())) ) + else // reset the hook { - // let the system paint the background - event.Skip(); + if ( gs_eraseBgHooks.erase(this) != 1 ) + { + wxFAIL_MSG( wxT("Resetting erase background which was not set?") ); + } } } +#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK + bool wxWindowMSW::DoEraseBackground(WXHDC hDC) { HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC); if ( !hbr ) return false; - wxFillRect(GetHwnd(), (HDC)hDC, hbr); + // erase just the client area of the window, this is important for the + // frames to avoid drawing over the toolbar part of the window (you might + // think using WS_CLIPCHILDREN would prevent this from happening, but it + // clearly doesn't) + RECT rc; + wxCopyRectToRECT(GetClientRect(), rc); + ::FillRect((HDC)hDC, &rc, hbr); return true; } WXHBRUSH -wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd) +wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), wxWindowMSW *child) { if ( m_hasBgCol ) { @@ -4455,11 +4953,10 @@ wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd) // children because it would look wrong if a child of non // transparent child would show our bg colour when the child itself // does not - wxWindow *win = wxFindWinFromHandle(hWnd); - if ( win == this || + if ( child == this || m_inheritBgCol || - (win && win->HasTransparentBackground() && - win->GetParent() == this) ) + (child->HasTransparentBackground() && + child->GetParent() == this) ) { // draw children with the same colour as the parent wxBrush * @@ -4472,14 +4969,11 @@ wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd) return 0; } -WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, WXHWND hWndToPaint) +WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, wxWindowMSW *child) { - if ( !hWndToPaint ) - hWndToPaint = GetHWND(); - for ( wxWindowMSW *win = this; win; win = win->GetParent() ) { - WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, hWndToPaint); + WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, child); if ( hBrush ) return hBrush; @@ -4534,7 +5028,7 @@ bool wxWindowMSW::HandleMinimize() wxIconizeEvent event(m_windowId); event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleMaximize() @@ -4542,7 +5036,7 @@ bool wxWindowMSW::HandleMaximize() wxMaximizeEvent event(m_windowId); event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleMove(int x, int y) @@ -4551,7 +5045,7 @@ bool wxWindowMSW::HandleMove(int x, int y) wxMoveEvent event(point, m_windowId); event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleMoving(wxRect& rect) @@ -4559,15 +5053,33 @@ bool wxWindowMSW::HandleMoving(wxRect& rect) wxMoveEvent event(rect, m_windowId); event.SetEventObject(this); - bool rc = GetEventHandler()->ProcessEvent(event); + bool rc = HandleWindowEvent(event); if (rc) rect = event.GetRect(); return rc; } +bool wxWindowMSW::HandleEnterSizeMove() +{ + wxMoveEvent event(wxPoint(0,0), m_windowId); + event.SetEventType(wxEVT_MOVE_START); + event.SetEventObject(this); + + return HandleWindowEvent(event); +} + +bool wxWindowMSW::HandleExitSizeMove() +{ + wxMoveEvent event(wxPoint(0,0), m_windowId); + event.SetEventType(wxEVT_MOVE_END); + event.SetEventObject(this); + + return HandleWindowEvent(event); +} + bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) { -#if USE_DEFERRED_SIZING +#if wxUSE_DEFERRED_SIZING // when we resize this window, its children are probably going to be // repositioned as well, prepare to use DeferWindowPos() for them int numChildren = 0; @@ -4588,20 +5100,20 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren); if ( !m_hDWP ) { - wxLogLastError(_T("BeginDeferWindowPos")); + wxLogLastError(wxT("BeginDeferWindowPos")); } if (m_hDWP) useDefer = true; } } -#endif // USE_DEFERRED_SIZING +#endif // wxUSE_DEFERRED_SIZING // update this window size bool processed = false; switch ( wParam ) { default: - wxFAIL_MSG( _T("unexpected WM_SIZE parameter") ); + wxFAIL_MSG( wxT("unexpected WM_SIZE parameter") ); // fall through nevertheless case SIZE_MAXHIDE: @@ -4624,10 +5136,10 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) wxSizeEvent event(GetSize(), m_windowId); event.SetEventObject(this); - processed = GetEventHandler()->ProcessEvent(event); + processed = HandleWindowEvent(event); } -#if USE_DEFERRED_SIZING +#if wxUSE_DEFERRED_SIZING // and finally change the positions of all child windows at once if ( useDefer && m_hDWP ) { @@ -4641,7 +5153,7 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) // do put all child controls in place at once if ( !::EndDeferWindowPos(hDWP) ) { - wxLogLastError(_T("EndDeferWindowPos")); + wxLogLastError(wxT("EndDeferWindowPos")); } // Reset our children's pending pos/size values. @@ -4649,12 +5161,11 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) node; node = node->GetNext() ) { - wxWindowMSW *child = node->GetData(); - child->m_pendingPosition = wxDefaultPosition; - child->m_pendingSize = wxDefaultSize; + wxWindowMSW * const child = node->GetData(); + child->MSWEndDeferWindowPos(); } } -#endif // USE_DEFERRED_SIZING +#endif // wxUSE_DEFERRED_SIZING return processed; } @@ -4664,7 +5175,7 @@ bool wxWindowMSW::HandleSizing(wxRect& rect) wxSizeEvent event(rect, m_windowId); event.SetEventObject(this); - bool rc = GetEventHandler()->ProcessEvent(event); + bool rc = HandleWindowEvent(event); if (rc) rect = event.GetRect(); return rc; @@ -4716,8 +5227,11 @@ bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo)) // command messages // --------------------------------------------------------------------------- -bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) +bool wxWindowMSW::HandleCommand(WXWORD id_, WXWORD cmd, WXHWND control) { + // sign extend to int from short before comparing with the other int ids + int id = (signed short)id_; + #if wxUSE_MENUS_NATIVE if ( !cmd && wxCurrentPopupMenu ) { @@ -4740,8 +5254,7 @@ bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) // try the id if ( !win ) { - // must cast to a signed type before comparing with other ids! - win = FindItem((signed short)id); + win = FindItem(id); } if ( win ) @@ -4755,15 +5268,11 @@ bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) // coming from a control to wxEVT_COMMAND_MENU_SELECTED if ( !control ) { - // If no child window, it may be an accelerator, e.g. for a popup menu - // command - - wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED); + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id); event.SetEventObject(this); - event.SetId(id); event.SetInt(id); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } else { @@ -4807,7 +5316,11 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event, event.m_leftDown = (flags & MK_LBUTTON) != 0; event.m_middleDown = (flags & MK_MBUTTON) != 0; event.m_rightDown = (flags & MK_RBUTTON) != 0; - event.m_altDown = ::GetKeyState(VK_MENU) < 0; +#ifdef wxHAS_XBUTTON + event.m_aux1Down = (flags & MK_XBUTTON1) != 0; + event.m_aux2Down = (flags & MK_XBUTTON2) != 0; +#endif // wxHAS_XBUTTON + event.m_altDown = ::wxIsAltDown(); #ifndef __WXWINCE__ event.SetTimestamp(::GetMessageTime()); @@ -4835,7 +5348,7 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event, // still don't get move, enter nor leave events. static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) { - wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") ); + wxCHECK_MSG( x && y, win, wxT("NULL pointer in FindWindowForMouseEvent") ); // first try to find a non transparent child: this allows us to send events // to a static text which is inside a static box, for example @@ -4873,7 +5386,7 @@ static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) ::IsWindowVisible(hwndUnderMouse) && ::IsWindowEnabled(hwndUnderMouse) ) { - wxWindow *winUnderMouse = wxFindWinFromHandle((WXHWND)hwndUnderMouse); + wxWindow *winUnderMouse = wxFindWinFromHandle(hwndUnderMouse); if ( winUnderMouse ) { // translate the mouse coords to the other window coords @@ -4905,13 +5418,33 @@ bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags) wxEVT_RIGHT_DCLICK, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_UP, - wxEVT_MIDDLE_DCLICK + wxEVT_MIDDLE_DCLICK, + 0, // this one is for wxEVT_MOTION which is not used here + wxEVT_AUX1_DOWN, + wxEVT_AUX1_UP, + wxEVT_AUX1_DCLICK, + wxEVT_AUX2_DOWN, + wxEVT_AUX2_UP, + wxEVT_AUX2_DCLICK }; +#ifdef wxHAS_XBUTTON + // the same messages are used for both auxillary mouse buttons so we need + // to adjust the index manually + switch ( msg ) + { + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: + case WM_XBUTTONDBLCLK: + if ( flags & MK_XBUTTON2 ) + msg += wxEVT_AUX2_DOWN - wxEVT_AUX1_DOWN; + } +#endif // wxHAS_XBUTTON + wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]); InitMouseEvent(event, x, y, flags); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags) @@ -4937,20 +5470,16 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags) static bool s_initDone = false; if ( !s_initDone ) { - wxLogNull noLog; - - wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM); + // see comment in wxApp::GetComCtl32Version() explaining the + // use of wxLoadedDLL + wxLoadedDLL dllComCtl32(wxT("comctl32.dll")); if ( dllComCtl32.IsLoaded() ) { s_pfn_TrackMouseEvent = (_TrackMouseEvent_t) - dllComCtl32.GetSymbol(_T("_TrackMouseEvent")); + dllComCtl32.RawGetSymbol(wxT("_TrackMouseEvent")); } s_initDone = true; - - // notice that it's ok to unload comctl32.dll here as it won't - // be really unloaded, being still in use because we link to it - // statically too } if ( s_pfn_TrackMouseEvent ) @@ -4968,7 +5497,7 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags) wxMouseEvent event(wxEVT_ENTER_WINDOW); InitMouseEvent(event, x, y, flags); - (void)GetEventHandler()->ProcessEvent(event); + (void)HandleWindowEvent(event); } } #ifdef HAVE_TRACKMOUSEEVENT @@ -5029,7 +5558,7 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) &s_linesPerRotation, 0)) { // this is not supposed to happen - wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)")); + wxLogLastError(wxT("SystemParametersInfo(GETWHEELSCROLLLINES)")); // the default is 3, so use it if SystemParametersInfo() failed s_linesPerRotation = 3; @@ -5037,7 +5566,7 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) } event.m_linesPerAction = s_linesPerRotation; - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); #else // !wxUSE_MOUSEWHEEL wxUnusedVar(wParam); @@ -5072,7 +5601,7 @@ void wxWindowMSW::GenerateMouseLeave() if ( !::GetCursorPos(&pt) ) #endif { - wxLogLastError(_T("GetCursorPos")); + wxLogLastError(wxT("GetCursorPos")); } // we need to have client coordinates here for symmetry with @@ -5084,7 +5613,7 @@ void wxWindowMSW::GenerateMouseLeave() wxMouseEvent event(wxEVT_LEAVE_WINDOW); InitMouseEvent(event, pt.x, pt.y, state); - (void)GetEventHandler()->ProcessEvent(event); + (void)HandleWindowEvent(event); } // --------------------------------------------------------------------------- @@ -5171,7 +5700,7 @@ bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) event.m_altDown = false; } - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam) @@ -5185,7 +5714,7 @@ bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam) } wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam, wParam)); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam) @@ -5199,9 +5728,10 @@ bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam) } wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam, wParam)); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } +#if wxUSE_MENUS int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel), WXLPARAM WXUNUSED_IN_WINCE(lParam)) { @@ -5236,13 +5766,13 @@ 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->GetItemLabel().wx_str(), wxT('&')); while ( p++ ) { - if ( *p == _T('&') ) + if ( *p == wxT('&') ) { // this is not the accel char, find the real one - p = wxStrchr(p + 1, _T('&')); + p = wxStrchr(p + 1, wxT('&')); } else // got the accel char { @@ -5265,23 +5795,25 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel), else // failed to get the menu text? { // it's not fatal, so don't show error, but still log it - wxLogLastError(_T("GetMenuItemInfo")); + wxLogLastError(wxT("GetMenuItemInfo")); } } #endif return wxNOT_FOUND; } -bool wxWindowMSW::HandleClipboardEvent( WXUINT nMsg ) +#endif // wxUSE_MENUS + +bool wxWindowMSW::HandleClipboardEvent(WXUINT nMsg) { - const wxEventType type = ( nMsg == WM_CUT ) ? wxEVT_COMMAND_TEXT_CUT : - ( nMsg == WM_COPY ) ? wxEVT_COMMAND_TEXT_COPY : - /*( nMsg == WM_PASTE ) ? */ wxEVT_COMMAND_TEXT_PASTE; + const wxEventType type = nMsg == WM_CUT ? wxEVT_COMMAND_TEXT_CUT + : nMsg == WM_COPY ? wxEVT_COMMAND_TEXT_COPY + : /* nMsg == WM_PASTE */ wxEVT_COMMAND_TEXT_PASTE; wxClipboardTextEvent evt(type, GetId()); evt.SetEventObject(this); - return GetEventHandler()->ProcessEvent(evt); + return HandleWindowEvent(evt); } // --------------------------------------------------------------------------- @@ -5366,7 +5898,7 @@ bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) event.SetPosition(wxPoint(x, y)); event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); #else wxUnusedVar(msg); wxUnusedVar(x); @@ -5433,12 +5965,11 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, scrollInfo.fMask = SIF_TRACKPOS; if ( !::GetScrollInfo(GetHwnd(), - orientation == wxHORIZONTAL ? SB_HORZ - : SB_VERT, + WXOrientToSB(orientation), &scrollInfo) ) { // Not necessarily an error, if there are no scrollbars yet. - // wxLogLastError(_T("GetScrollInfo")); + // wxLogLastError(wxT("GetScrollInfo")); } event.SetPosition(scrollInfo.nTrackPos); @@ -5453,7 +5984,7 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, return false; } - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } // ---------------------------------------------------------------------------- @@ -5464,7 +5995,7 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler) { wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(), - false, _T("registering handler for the same message twice") ); + false, wxT("registering handler for the same message twice") ); gs_messageHandlers[msg] = handler; return true; @@ -5475,7 +6006,7 @@ 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?") ); + wxT("unregistering non-registered handler?") ); gs_messageHandlers.erase(i); } @@ -5685,11 +6216,8 @@ int wxCharCodeMSWToWX(int vk, WXLPARAM lParam) return wxk; } -WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual) +WXWORD wxCharCodeWXToMSW(int wxk) { - if ( isVirtual ) - *isVirtual = true; - // check the table first for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ ) { @@ -5752,31 +6280,42 @@ WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual) break; default: - if ( isVirtual ) - *isVirtual = false; - vk = (WXWORD)wxk; - break; + // no VkKeyScan() under CE unfortunately, we need to test how does + // it handle OEM keys +#ifndef __WXWINCE__ + // check to see if its one of the OEM key codes. + BYTE vks = LOBYTE(VkKeyScan(wxk)); + if ( vks != 0xff ) + { + vk = vks; + } + else +#endif // !__WXWINCE__ + { + vk = (WXWORD)wxk; + } } return vk; } -#ifndef SM_SWAPBUTTON - #define SM_SWAPBUTTON 23 -#endif - // small helper for wxGetKeyState() and wxGetMouseState() static inline bool wxIsKeyDown(WXWORD vk) { - switch (vk) + // SM_SWAPBUTTON is not available under CE, so don't swap buttons there +#ifdef SM_SWAPBUTTON + if ( vk == VK_LBUTTON || vk == VK_RBUTTON ) { - case VK_LBUTTON: - if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_RBUTTON; - break; - case VK_RBUTTON: - if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_LBUTTON; - break; + if ( ::GetSystemMetrics(SM_SWAPBUTTON) ) + { + if ( vk == VK_LBUTTON ) + vk = VK_RBUTTON; + else // vk == VK_RBUTTON + vk = VK_LBUTTON; + } } +#endif // SM_SWAPBUTTON + // 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 @@ -5821,10 +6360,14 @@ wxMouseState wxGetMouseState() ms.SetLeftDown(wxIsKeyDown(VK_LBUTTON)); ms.SetMiddleDown(wxIsKeyDown(VK_MBUTTON)); ms.SetRightDown(wxIsKeyDown(VK_RBUTTON)); - - ms.SetControlDown(wxIsKeyDown(VK_CONTROL)); - ms.SetShiftDown(wxIsKeyDown(VK_SHIFT)); - ms.SetAltDown(wxIsKeyDown(VK_MENU)); +#ifdef wxHAS_XBUTTON + ms.SetAux1Down(wxIsKeyDown(VK_XBUTTON1)); + ms.SetAux2Down(wxIsKeyDown(VK_XBUTTON2)); +#endif // wxHAS_XBUTTON + + ms.SetControlDown(wxIsCtrlDown ()); + ms.SetShiftDown (wxIsShiftDown()); + ms.SetAltDown (wxIsAltDown ()); // ms.SetMetaDown(); return ms; @@ -5836,7 +6379,7 @@ wxWindow *wxGetActiveWindow() HWND hWnd = GetActiveWindow(); if ( hWnd != 0 ) { - return wxFindWinFromHandle((WXHWND) hWnd); + return wxFindWinFromHandle(hWnd); } return NULL; } @@ -5848,10 +6391,10 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set // by code in msw/radiobox.cpp), for all the others we just search up the // window hierarchy - wxWindow *win = (wxWindow *)NULL; + wxWindow *win = NULL; if ( hwnd ) { - win = wxFindWinFromHandle((WXHWND)hwnd); + win = wxFindWinFromHandle(hwnd); if ( !win ) { #if wxUSE_RADIOBOX @@ -5895,7 +6438,7 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) #endif hwnd = ::GetParent(hwnd); - win = wxFindWinFromHandle((WXHWND)hwnd); + win = wxFindWinFromHandle(hwnd); } return win; @@ -5906,28 +6449,8 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE // in active frames and dialogs, regardless of where the focus is. static HHOOK wxTheKeyboardHook = 0; -static FARPROC wxTheKeyboardHookProc = 0; -int APIENTRY _EXPORT -wxKeyboardHook(int nCode, WORD wParam, DWORD lParam); - -void wxSetKeyboardHook(bool doIt) -{ - if ( doIt ) - { - wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance()); - wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(), - - GetCurrentThreadId() - // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right? - ); - } - else - { - UnhookWindowsHookEx(wxTheKeyboardHook); - } -} -int APIENTRY _EXPORT +int APIENTRY wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) { DWORD hiWord = HIWORD(lParam); @@ -5971,9 +6494,32 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam); } +void wxSetKeyboardHook(bool doIt) +{ + if ( doIt ) + { + wxTheKeyboardHook = ::SetWindowsHookEx + ( + WH_KEYBOARD, + (HOOKPROC)wxKeyboardHook, + NULL, // must be NULL for process hook + ::GetCurrentThreadId() + ); + if ( !wxTheKeyboardHook ) + { + wxLogLastError(wxT("SetWindowsHookEx(wxKeyboardHook)")); + } + } + else // uninstall + { + if ( wxTheKeyboardHook ) + ::UnhookWindowsHookEx(wxTheKeyboardHook); + } +} + #endif // !__WXMICROWIN__ -#ifdef __WXDEBUG__ +#if wxDEBUG_LEVEL >= 2 const wxChar *wxGetMessageName(int message) { switch ( message ) @@ -6131,6 +6677,10 @@ const wxChar *wxGetMessageName(int message) case 0x0120: return wxT("WM_MENUCHAR"); case 0x0121: return wxT("WM_ENTERIDLE"); + case 0x0127: return wxT("WM_CHANGEUISTATE"); + case 0x0128: return wxT("WM_UPDATEUISTATE"); + case 0x0129: return wxT("WM_QUERYUISTATE"); + case 0x0132: return wxT("WM_CTLCOLORMSGBOX"); case 0x0133: return wxT("WM_CTLCOLOREDIT"); case 0x0134: return wxT("WM_CTLCOLORLISTBOX"); @@ -6151,6 +6701,9 @@ const wxChar *wxGetMessageName(int message) case 0x0208: return wxT("WM_MBUTTONUP"); case 0x0209: return wxT("WM_MBUTTONDBLCLK"); case 0x020A: return wxT("WM_MOUSEWHEEL"); + case 0x020B: return wxT("WM_XBUTTONDOWN"); + case 0x020C: return wxT("WM_XBUTTONUP"); + case 0x020D: return wxT("WM_XBUTTONDBLCLK"); case 0x0210: return wxT("WM_PARENTNOTIFY"); case 0x0211: return wxT("WM_ENTERMENULOOP"); case 0x0212: return wxT("WM_EXITMENULOOP"); @@ -6439,7 +6992,7 @@ const wxChar *wxGetMessageName(int message) return s_szBuf.c_str(); } } -#endif //__WXDEBUG__ +#endif // wxDEBUG_LEVEL >= 2 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win) { @@ -6515,10 +7068,10 @@ static void WinCEUnregisterHotKey(int modifiers, int id) typedef BOOL (WINAPI *UnregisterFunc1Proc)(UINT, UINT); UnregisterFunc1Proc procUnregisterFunc; - hCoreDll = LoadLibrary(_T("coredll.dll")); + hCoreDll = LoadLibrary(wxT("coredll.dll")); if (hCoreDll) { - procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, _T("UnregisterFunc1")); + procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, wxT("UnregisterFunc1")); if (procUnregisterFunc) procUnregisterFunc(modifiers, id); FreeLibrary(hCoreDll); @@ -6546,7 +7099,7 @@ bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode) if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) ) { - wxLogLastError(_T("RegisterHotKey")); + wxLogLastError(wxT("RegisterHotKey")); return false; } @@ -6562,7 +7115,7 @@ bool wxWindowMSW::UnregisterHotKey(int hotkeyId) if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) ) { - wxLogLastError(_T("UnregisterHotKey")); + wxLogLastError(wxT("UnregisterHotKey")); return false; } @@ -6585,7 +7138,7 @@ bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) event.m_altDown = (win_modifiers & MOD_ALT) != 0; event.m_metaDown = (win_modifiers & MOD_WIN) != 0; - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } #endif // wxUSE_ACCEL @@ -6615,7 +7168,7 @@ public: if ( !ms_hMsgHookProc ) { - wxLogLastError(_T("SetWindowsHookEx(WH_GETMESSAGE)")); + wxLogLastError(wxT("SetWindowsHookEx(WH_GETMESSAGE)")); return false; }