X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/34040e3126a6714928377e6f81cc2a9eb476075f..921c65ed3d889117c600387cebb0bce2470cff8e:/src/msw/window.cpp?ds=sidebyside diff --git a/src/msw/window.cpp b/src/msw/window.cpp index fc14d47191..031585be7c 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -47,6 +47,7 @@ #include "wx/msgdlg.h" #include "wx/settings.h" #include "wx/statbox.h" + #include "wx/sizer.h" #endif #if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__) @@ -54,6 +55,7 @@ #endif #include "wx/module.h" +#include "wx/sysopt.h" #if wxUSE_DRAG_AND_DROP #include "wx/dnd.h" @@ -106,20 +108,21 @@ #include #endif -#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) /* && !defined(__WXWINCE__) */ ) || defined(__CYGWIN10__) - #ifdef __WIN95__ - #include - #endif -#elif !defined(__WXMICROWIN__) && !defined(__WXWINCE__) // broken compiler - #include "wx/msw/gnuwin32/extra.h" -#endif +#include #include "wx/msw/missing.h" #if defined(__WXWINCE__) -#include "wx/msw/wince/missing.h" + #include "wx/msw/wince/missing.h" #endif +#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) + #define HAVE_TRACKMOUSEEVENT +#endif // everything needed for TrackMouseEvent() + +#define USE_DEFERRED_SIZING 1 +#define USE_DEFER_BUG_WORKAROUND 1 + // --------------------------------------------------------------------------- // global variables // --------------------------------------------------------------------------- @@ -128,7 +131,11 @@ wxMenu *wxCurrentPopupMenu = NULL; #endif // wxUSE_MENUS_NATIVE +#ifdef __WXWINCE__ +extern wxChar *wxCanvasClassName; +#else extern const wxChar *wxCanvasClassName; +#endif // true if we had already created the std colour map, used by // wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT) @@ -151,11 +158,6 @@ void wxRemoveHandleAssociation(wxWindowMSW *win); extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win); wxWindow *wxFindWinFromHandle(WXHWND hWnd); -// this magical function is used to translate VK_APPS key presses to right -// mouse clicks -static void TranslateKbdEventToMouse(wxWindowMSW *win, - int *x, int *y, WPARAM *flags); - // get the text metrics for the current font static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win); @@ -180,6 +182,8 @@ static inline void wxBringWindowToTop(HWND hwnd) } } +#ifndef __WXWINCE__ + // ensure that all our parent windows have WS_EX_CONTROLPARENT style static void EnsureParentHasControlParentStyle(wxWindow *parent) { @@ -196,7 +200,6 @@ static void EnsureParentHasControlParentStyle(wxWindow *parent) but if the parent doesn't have it, it wouldn't recurse inside it later on and so wouldn't have a chance of getting back to this window neither. */ -#ifndef __WXWINCE__ while ( parent && !parent->IsTopLevel() ) { LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE); @@ -209,8 +212,24 @@ static void EnsureParentHasControlParentStyle(wxWindow *parent) parent = parent->GetParent(); } +} + #endif // !__WXWINCE__ + +#ifdef __WXWINCE__ +// On Windows CE, GetCursorPos can return an error, so use this function +// instead +bool GetCursorPosWinCE(POINT* pt) +{ + if (!GetCursorPos(pt)) + { + DWORD pos = GetMessagePos(); + pt->x = LOWORD(pos); + pt->y = HIWORD(pos); + } + return true; } +#endif // --------------------------------------------------------------------------- // event tables @@ -258,7 +277,7 @@ wxBEGIN_FLAGS( wxWindowStyle ) wxFLAGS_MEMBER(wxBORDER_RAISED) wxFLAGS_MEMBER(wxBORDER_STATIC) wxFLAGS_MEMBER(wxBORDER_NONE) - + // old style border flags wxFLAGS_MEMBER(wxSIMPLE_BORDER) wxFLAGS_MEMBER(wxSUNKEN_BORDER) @@ -280,16 +299,16 @@ wxBEGIN_FLAGS( wxWindowStyle ) wxEND_FLAGS( wxWindowStyle ) wxBEGIN_PROPERTIES_TABLE(wxWindow) - wxEVENT_PROPERTY( Close , wxEVT_CLOSE_WINDOW , wxCloseEvent) - wxEVENT_PROPERTY( Create , wxEVT_CREATE , wxWindowCreateEvent ) - wxEVENT_PROPERTY( Destroy , wxEVT_DESTROY , wxWindowDestroyEvent ) + wxEVENT_PROPERTY( Close , wxEVT_CLOSE_WINDOW , wxCloseEvent) + wxEVENT_PROPERTY( Create , wxEVT_CREATE , wxWindowCreateEvent ) + wxEVENT_PROPERTY( Destroy , wxEVT_DESTROY , wxWindowDestroyEvent ) // Always constructor Properties first - wxREADONLY_PROPERTY( Parent,wxWindow*, GetParent, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( Id,wxWindowID, SetId, GetId, -1, 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) - wxPROPERTY( Position,wxPoint, SetPosition , GetPosition, wxPoint(-1,-1) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos - wxPROPERTY( Size,wxSize, SetSize, GetSize, wxSize(-1,-1) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size - wxPROPERTY( WindowStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style + wxREADONLY_PROPERTY( Parent,wxWindow*, GetParent, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Id,wxWindowID, SetId, GetId, -1 /*wxID_ANY*/ , 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) + wxPROPERTY( Position,wxPoint, SetPosition , GetPosition, wxDefaultPosition , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos + wxPROPERTY( Size,wxSize, SetSize, GetSize, wxDefaultSize , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size + wxPROPERTY( WindowStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style // Then all relations of the object graph @@ -297,23 +316,23 @@ wxBEGIN_PROPERTIES_TABLE(wxWindow) // and finally all other properties - wxPROPERTY( ExtraStyle , long , SetExtraStyle , GetExtraStyle , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle - wxPROPERTY( BackgroundColour , wxColour , SetBackgroundColour , GetBackgroundColour , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg - wxPROPERTY( ForegroundColour , wxColour , SetForegroundColour , GetForegroundColour , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg - wxPROPERTY( Enabled , bool , Enable , IsEnabled , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( Shown , bool , Show , IsShown , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( ExtraStyle , long , SetExtraStyle , GetExtraStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle + wxPROPERTY( BackgroundColour , wxColour , SetBackgroundColour , GetBackgroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg + wxPROPERTY( ForegroundColour , wxColour , SetForegroundColour , GetForegroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg + wxPROPERTY( Enabled , bool , Enable , IsEnabled , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Shown , bool , Show , IsShown , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) #if 0 // possible property candidates (not in xrc) or not valid in all subclasses - wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxT("") ) - wxPROPERTY( Font , wxFont , SetFont , GetWindowFont , ) - wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxT("") ) - // MaxHeight, Width , MinHeight , Width - // TODO switch label to control and title to toplevels + wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxEmptyString ) + wxPROPERTY( Font , wxFont , SetFont , GetWindowFont , ) + wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxEmptyString ) + // MaxHeight, Width , MinHeight , Width + // TODO switch label to control and title to toplevels - wxPROPERTY( ThemeEnabled , bool , SetThemeEnabled , GetThemeEnabled , ) - //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , ) - // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , ) - wxPROPERTY( AutoLayout , bool , SetAutoLayout , GetAutoLayout , ) + wxPROPERTY( ThemeEnabled , bool , SetThemeEnabled , GetThemeEnabled , ) + //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , ) + // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , ) + wxPROPERTY( AutoLayout , bool , SetAutoLayout , GetAutoLayout , ) @@ -331,9 +350,11 @@ wxCONSTRUCTOR_DUMMY(wxWindow) #endif // __WXUNIVERSAL__/__WXMSW__ BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase) - EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground) EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged) + EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground) +#ifdef __WXWINCE__ EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog) +#endif END_EVENT_TABLE() // =========================================================================== @@ -433,10 +454,8 @@ void wxWindowMSW::Init() m_childrenDisabled = NULL; m_frozenness = 0; - // wxWnd - m_hMenu = 0; - m_hWnd = 0; + m_hDWP = 0; m_xThumbSize = 0; m_yThumbSize = 0; @@ -446,6 +465,9 @@ void wxWindowMSW::Init() m_lastMouseY = -1; m_lastMouseEvent = -1; #endif // wxUSE_MOUSEEVENT_HACK + + m_pendingPosition = wxDefaultPosition; + m_pendingSize = wxDefaultSize; } // Destructor @@ -464,7 +486,12 @@ wxWindowMSW::~wxWindowMSW() { frame->SetLastFocus(NULL); } - break; + + // apparently sometimes we can end up with our grand parent + // pointing to us as well: this is surely a bug in focus handling + // code but it's not clear where it happens so for now just try to + // fix it here by not breaking out of the loop + //break; } } #endif // __WXUNIVERSAL__ @@ -488,6 +515,7 @@ wxWindowMSW::~wxWindowMSW() } delete m_childrenDisabled; + } // real construction (Init() must have been called before!) @@ -522,7 +550,12 @@ bool wxWindowMSW::Create(wxWindow *parent, msflags |= WS_VISIBLE; } - return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle); + if ( !MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle) ) + return false; + + InheritAttributes(); + + return true; } // --------------------------------------------------------------------------- @@ -573,7 +606,7 @@ void wxWindowMSW::SetFocusFromKbd() } // Get the window with the focus -wxWindow *wxWindowBase::FindFocus() +wxWindow *wxWindowBase::DoFindFocus() { HWND hWnd = ::GetFocus(); if ( hWnd ) @@ -746,7 +779,11 @@ bool wxWindowMSW::SetCursor(const wxCursor& cursor) // Change the cursor NOW if we're within the correct window POINT point; +#ifdef __WXWINCE__ + ::GetCursorPosWinCE(&point); +#else ::GetCursorPos(&point); +#endif RECT rect = wxGetWindowRect(hWnd); @@ -771,12 +808,6 @@ void wxWindowMSW::WarpPointer (int x, int y) // scrolling stuff // --------------------------------------------------------------------------- -// convert wxHORIZONTAL/wxVERTICAL to SB_HORZ/SB_VERT -static inline int wxDirToWinStyle(int orient) -{ - return orient == wxHORIZONTAL ? SB_HORZ : SB_VERT; -} - inline int GetScrollPosition(HWND hWnd, int wOrient) { #ifdef __WXMICROWIN__ @@ -902,11 +933,12 @@ void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect) else { pr = NULL; + } #ifdef __WXWINCE__ // FIXME: is this the exact equivalent of the line below? - ::ScrollWindowEx(GetHwnd(), dx, dy, pr, pr, 0, 0, SW_ERASE|SW_INVALIDATE); + ::ScrollWindowEx(GetHwnd(), dx, dy, pr, pr, 0, 0, SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE); #else ::ScrollWindow(GetHwnd(), dx, dy, pr, pr); #endif @@ -969,7 +1001,7 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) // we don't need to subclass the window of our own class (in the Windows // sense of the word) - if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) ) + if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) ) { wxSetWindowProc(hwnd, wxWndProc); } @@ -977,7 +1009,7 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) { // don't bother restoring it neither: this also makes it easy to // implement IsOfStandardClass() method which returns true for the - // standard controls and false for the wxWindows own windows as it can + // standard controls and false for the wxWidgets own windows as it can // simply check m_oldWndProc m_oldWndProc = NULL; } @@ -991,7 +1023,7 @@ void wxWindowMSW::UnsubclassWin() HWND hwnd = GetHwnd(); if ( hwnd ) { - m_hWnd = 0; + SetHWND(0); wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") ); @@ -1007,6 +1039,27 @@ void wxWindowMSW::UnsubclassWin() } } +void wxWindowMSW::AssociateHandle(WXWidget handle) +{ + if ( m_hWnd ) + { + if ( !::DestroyWindow(GetHwnd()) ) + wxLogLastError(wxT("DestroyWindow")); + } + + WXHWND wxhwnd = (WXHWND)handle; + + SetHWND(wxhwnd); + SubclassWin(wxhwnd); +} + +void wxWindowMSW::DissociateHandle() +{ + // this also calls SetHWND(0) for us + UnsubclassWin(); +} + + bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC wndProc) { // Unicows note: the code below works, but only because WNDCLASS contains @@ -1016,26 +1069,28 @@ bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC wndProc) // Unicows_{Set,Get}WindowLong and Unicows_RegisterClass to our own // versions that keep track of fake<->real wnd proc mapping. - // On WinCE (at least), the wndproc comparison doesn't work, - // so have to use something like this. + // On WinCE (at least), the wndproc comparison doesn't work, + // so have to use something like this. #ifdef __WXWINCE__ - extern const wxChar *wxCanvasClassName; - extern const wxChar *wxCanvasClassNameNR; - 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 || - str == wxMDIFrameClassName || - str == wxMDIFrameClassNameNoRedraw || - str == wxMDIChildFrameClassName || - str == wxMDIChildFrameClassNameNoRedraw || - str == _T("wxTLWHiddenParent")) - return true; // Effectively means don't subclass - else - return false; + wxUnusedVar(wndProc); + + extern wxChar *wxCanvasClassName; + extern wxChar *wxCanvasClassNameNR; + 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 || + str == wxMDIFrameClassName || + str == wxMDIFrameClassNameNoRedraw || + str == wxMDIChildFrameClassName || + str == wxMDIChildFrameClassNameNoRedraw || + str == _T("wxTLWHiddenParent")) + return true; // Effectively means don't subclass + else + return false; #else WNDCLASS cls; if ( !::GetClassInfo(wxGetInstance(), wxGetWindowClass(hWnd), &cls) ) @@ -1093,7 +1148,7 @@ void wxWindowMSW::SetWindowStyleFlag(long flags) ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal); - // we must call SetWindowPos() to flash the cached extended style and + // we must call SetWindowPos() to flush the cached extended style and // also to make the change to wxSTAY_ON_TOP style take effect: just // setting the style simply doesn't work if ( !::SetWindowPos(GetHwnd(), @@ -1109,14 +1164,26 @@ void wxWindowMSW::SetWindowStyleFlag(long flags) WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const { - // translate the style - WXDWORD style = WS_CHILD | WS_VISIBLE; + // translate common wxWidgets styles to Windows ones - if ( flags & wxCLIP_CHILDREN ) + // most of windows are child ones, those which are not (such as + // wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle() + WXDWORD style = WS_CHILD; + + // using this flag results in very significant reduction in flicker, + // especially with controls inside the static boxes (as the interior of the + // box is not redrawn twice).but sometimes results in redraw problems, so + // optionally allow the old code to continue to use it provided a special + // system option is turned on + if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children")) + || (flags & wxCLIP_CHILDREN) ) style |= WS_CLIPCHILDREN; - if ( flags & wxCLIP_SIBLINGS ) - style |= WS_CLIPSIBLINGS; + // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially + // don't support overlapping windows and it only makes sense for them and, + // presumably, gives the system some extra work (to manage more clipping + // regions), so avoid it alltogether + if ( flags & wxVSCROLL ) style |= WS_VSCROLL; @@ -1194,7 +1261,11 @@ bool wxWindowMSW::IsMouseInWindow() const { // get the mouse position POINT pt; +#ifdef __WXWINCE__ + ::GetCursorPosWinCE(&pt); +#else ::GetCursorPos(&pt); +#endif // find the window which currently has the cursor and go up the window // chain until we find this window - or exhaust it @@ -1207,6 +1278,7 @@ bool wxWindowMSW::IsMouseInWindow() const void wxWindowMSW::OnInternalIdle() { +#ifndef HAVE_TRACKMOUSEEVENT // Check if we need to send a LEAVE event if ( m_mouseInWindow ) { @@ -1214,42 +1286,10 @@ void wxWindowMSW::OnInternalIdle() // or doesn't have mouse capture if ( !IsMouseInWindow() ) { - // Generate a LEAVE event - m_mouseInWindow = false; - - // Unfortunately the mouse button and keyboard state may have - // changed by the time the OnInternalIdle function is called, so 'state' - // may be meaningless. - int state = 0; - if ( wxIsShiftDown() ) - state |= MK_SHIFT; - if ( wxIsCtrlDown() ) - state |= MK_CONTROL; - if ( GetKeyState( VK_LBUTTON ) ) - state |= MK_LBUTTON; - if ( GetKeyState( VK_MBUTTON ) ) - state |= MK_MBUTTON; - if ( GetKeyState( VK_RBUTTON ) ) - state |= MK_RBUTTON; - - POINT pt; - if ( !::GetCursorPos(&pt) ) - { - wxLogLastError(_T("GetCursorPos")); - } - - // we need to have client coordinates here for symmetry with - // wxEVT_ENTER_WINDOW - RECT rect = wxGetWindowRect(GetHwnd()); - pt.x -= rect.left; - pt.y -= rect.top; - - wxMouseEvent event2(wxEVT_LEAVE_WINDOW); - InitMouseEvent(event2, pt.x, pt.y, state); - - (void)GetEventHandler()->ProcessEvent(event2); + GenerateMouseLeave(); } } +#endif // !HAVE_TRACKMOUSEEVENT if (wxUpdateUIEvent::CanUpdate(this)) UpdateWindowUI(wxUPDATE_UI_FROMIDLE); @@ -1287,7 +1327,8 @@ void wxWindowMSW::Freeze() { if ( !m_frozenness++ ) { - SendSetRedraw(GetHwnd(), false); + if ( IsShown() ) + SendSetRedraw(GetHwnd(), false); } } @@ -1297,11 +1338,14 @@ void wxWindowMSW::Thaw() if ( !--m_frozenness ) { - SendSetRedraw(GetHwnd(), true); + if ( IsShown() ) + { + SendSetRedraw(GetHwnd(), true); - // we need to refresh everything or otherwise he invalidated area is not - // repainted - Refresh(); + // we need to refresh everything or otherwise the invalidated area + // is not going to be repainted + Refresh(); + } } } @@ -1310,18 +1354,32 @@ void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect) HWND hWnd = GetHwnd(); if ( hWnd ) { + RECT mswRect; + const RECT *pRect; if ( rect ) { - RECT mswRect; mswRect.left = rect->x; mswRect.top = rect->y; mswRect.right = rect->x + rect->width; mswRect.bottom = rect->y + rect->height; - ::InvalidateRect(hWnd, &mswRect, eraseBack); + pRect = &mswRect; } else - ::InvalidateRect(hWnd, NULL, eraseBack); + { + pRect = NULL; + } + + // RedrawWindow not available on SmartPhone or eVC++ 3 +#if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400) + UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN; + if ( eraseBack ) + flags |= RDW_ERASE; + + ::RedrawWindow(hWnd, pRect, NULL, flags); +#else + ::InvalidateRect(hWnd, pRect, eraseBack); +#endif } } @@ -1366,6 +1424,8 @@ void wxWindowMSW::DragAcceptFiles(bool accept) HWND hWnd = GetHwnd(); if ( hWnd ) ::DragAcceptFiles(hWnd, (BOOL)accept); +#else + wxUnusedVar(accept); #endif } @@ -1491,10 +1551,24 @@ void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height) width = 0; if (height < 0) height = 0; - if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) ) - { - wxLogLastError(wxT("MoveWindow")); - } + + // if our parent had prepared a defer window handle for us, use it (unless + // we are a top level window) + wxWindowMSW *parent = GetParent(); + +#if USE_DEFERRED_SIZING + HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL; +#else + HDWP hdwp = 0; +#endif + + wxMoveWindowDeferred(hdwp, this, GetHwnd(), x, y, width, height); + +#if USE_DEFERRED_SIZING + if ( parent ) + // hdwp must be updated as it may have been changed + parent->m_hDWP = (WXHANDLE)hdwp; +#endif } // set the size of the window: if the dimensions are positive, just use them, @@ -1509,9 +1583,28 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) { // get the current size and position... int currentX, currentY; + int currentW, currentH; + +#if USE_DEFER_BUG_WORKAROUND + currentX = m_pendingPosition.x; + if (currentX == wxDefaultCoord) + GetPosition(¤tX, NULL); + + currentY = m_pendingPosition.y; + if (currentY == wxDefaultCoord) + GetPosition(NULL, ¤tY); + + currentW = m_pendingSize.x; + if (currentW == wxDefaultCoord) + GetSize(¤tW, NULL); + + currentH = m_pendingSize.y; + if (currentH == wxDefaultCoord) + GetSize(NULL, ¤tH); +#else GetPosition(¤tX, ¤tY); - int currentW,currentH; GetSize(¤tW, ¤tH); +#endif // ... and don't do anything (avoiding flicker) if it's already ok if ( x == currentX && y == currentY && @@ -1520,15 +1613,15 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) return; } - if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + if ( x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) x = currentX; - if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + if ( y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) y = currentY; AdjustForParentClientOrigin(x, y, sizeFlags); - wxSize size(-1, -1); - if ( width == -1 ) + wxSize size = wxDefaultSize; + if ( width == wxDefaultCoord ) { if ( sizeFlags & wxSIZE_AUTO_WIDTH ) { @@ -1542,11 +1635,11 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) } } - if ( height == -1 ) + if ( height == wxDefaultCoord ) { if ( sizeFlags & wxSIZE_AUTO_HEIGHT ) { - if ( size.x == -1 ) + if ( size.x == wxDefaultCoord ) { size = DoGetBestSize(); } @@ -1561,6 +1654,24 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) } } +#if USE_DEFER_BUG_WORKAROUND + // We don't actually use the hdwp here, but we need to know whether to + // save the pending dimensions or not. This isn't done in DoMoveWindow + // (where the hdwp is used) because some controls have thier own + // DoMoveWindow so it is easier to catch it here. + HDWP hdwp = GetParent() && !IsTopLevel() ? (HDWP)GetParent()->m_hDWP : NULL; + if (hdwp) + { + m_pendingPosition = wxPoint(x, y); + m_pendingSize = wxSize(width, height); + } + else + { + m_pendingPosition = wxDefaultPosition; + m_pendingSize = wxDefaultSize; + } +#endif + DoMoveWindow(x, y, width, height); } @@ -1584,8 +1695,8 @@ void wxWindowMSW::DoSetClientSize(int width, int height) ::GetClientRect(GetHwnd(), &rectClient); // if the size is already ok, stop here (rectClient.left = top = 0) - if ( (rectClient.right == width || width == -1) && - (rectClient.bottom == height || height == -1) ) + if ( (rectClient.right == width || width == wxDefaultCoord) && + (rectClient.bottom == height || height == wxDefaultCoord) ) { break; } @@ -1621,13 +1732,6 @@ void wxWindowMSW::DoSetClientSize(int width, int height) } } -// For implementation purposes - sometimes decorations make the client area -// smaller -wxPoint wxWindowMSW::GetClientAreaOrigin() const -{ - return wxPoint(0, 0); -} - // --------------------------------------------------------------------------- // text metrics // --------------------------------------------------------------------------- @@ -1653,31 +1757,22 @@ void wxWindowMSW::GetTextExtent(const wxString& string, int *descent, int *externalLeading, const wxFont *theFont) const { - const wxFont *fontToUse = theFont; - if ( !fontToUse ) - fontToUse = &m_font; + wxASSERT_MSG( !theFont || theFont->Ok(), + _T("invalid font in GetTextExtent()") ); - HWND hWnd = GetHwnd(); - HDC dc = ::GetDC(hWnd); + wxFont fontToUse; + if (theFont) + fontToUse = *theFont; + else + fontToUse = GetFont(); - HFONT fnt = 0; - HFONT hfontOld = 0; - if ( fontToUse && fontToUse->Ok() ) - { - fnt = (HFONT)((wxFont *)fontToUse)->GetResourceHandle(); // const_cast - if ( fnt ) - hfontOld = (HFONT)SelectObject(dc,fnt); - } + WindowHDC hdc(GetHwnd()); + SelectInHDC selectFont(hdc, GetHfontOf(fontToUse)); SIZE sizeRect; TEXTMETRIC tm; - GetTextExtentPoint(dc, string, (int)string.Length(), &sizeRect); - GetTextMetrics(dc, &tm); - - if ( fontToUse && fnt && hfontOld ) - SelectObject(dc, hfontOld); - - ReleaseDC(hWnd, dc); + ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect); + GetTextMetrics(hdc, &tm); if ( x ) *x = sizeRect.cx; @@ -1727,6 +1822,12 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) menu->SetInvokingWindow(this); menu->UpdateUI(); + if ( x == wxDefaultCoord && y == wxDefaultCoord ) + { + wxPoint mouse = ScreenToClient(wxGetMousePosition()); + x = mouse.x; y = mouse.y; + } + HWND hWnd = GetHwnd(); HMENU hMenu = GetHmenuOf(menu); POINT point; @@ -1734,9 +1835,10 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) point.y = y; ::ClientToScreen(hWnd, &point); wxCurrentPopupMenu = menu; +#if defined(__WXWINCE__) UINT flags = 0; -#if !defined(__WXWINCE__) - flags = TPM_RIGHTBUTTON; +#else + UINT flags = TPM_RIGHTBUTTON; #endif ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL); @@ -1781,7 +1883,6 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) // here we try to do all the job which ::IsDialogMessage() usually does // internally -#if 1 if ( msg->message == WM_KEYDOWN ) { bool bCtrlDown = wxIsCtrlDown(); @@ -1805,7 +1906,8 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) } bool bForward = true, - bWindowChange = false; + bWindowChange = false, + bFromTab = false; // should we process this message specially? bool bProcess = true; @@ -1819,6 +1921,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) // Ctrl-Tab cycles thru notebook pages bWindowChange = bCtrlDown; bForward = !bShiftDown; + bFromTab = true; } break; @@ -1839,8 +1942,21 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) case VK_ESCAPE: { #if wxUSE_BUTTON - wxButton *btn = wxDynamicCast(FindWindow(wxID_CANCEL), - wxButton); + wxButton *btn = wxDynamicCast(FindWindow(wxID_CANCEL),wxButton); + + // our own wxLogDialog should react to Esc + // without Cancel button but this is a private class + // so let's try recognize it by content + #if wxUSE_LOG_DIALOG + if ( !btn && + wxDynamicCast(this,wxDialog) && + FindWindow(wxID_MORE) && + FindWindow(wxID_OK) && + !FindWindow(wxID_CANCEL) && + GetTitle().MakeLower().StartsWith(wxTheApp->GetAppName().c_str()) + ) + btn = wxDynamicCast(FindWindow(wxID_OK),wxButton); + #endif // wxUSE_LOG_DIALOG if ( btn && btn->IsEnabled() ) { // if we do have a cancel button, do press it @@ -1881,7 +1997,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) bProcess = false; } // FIXME: this should be handled by - // wxNavigationKeyEvent handler and not here!! + // wxNavigationKeyEvent handler and not here! else { #if wxUSE_BUTTON @@ -1895,8 +2011,8 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) return true; } else // no default button - { #endif // wxUSE_BUTTON + { // this is a quick and dirty test for a text // control if ( !(lDlgCode & DLGC_HASSETSEL) ) @@ -1930,6 +2046,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) wxNavigationKeyEvent event; event.SetDirection(bForward); event.SetWindowChange(bWindowChange); + event.SetFromTab(bFromTab); event.SetEventObject(this); if ( GetEventHandler()->ProcessEvent(event) ) @@ -1938,35 +2055,6 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) } } } -#else // 0 - // let ::IsDialogMessage() do almost everything and handle just the - // things it doesn't here: Ctrl-TAB for switching notebook pages - if ( msg->message == WM_KEYDOWN ) - { - // don't process system keys here - if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) ) - { - if ( (msg->wParam == VK_TAB) && wxIsCtrlDown() ) - { - // find the first notebook parent and change its page - wxWindow *win = this; - wxNotebook *nbook = NULL; - while ( win && !nbook ) - { - nbook = wxDynamicCast(win, wxNotebook); - win = win->GetParent(); - } - - if ( nbook ) - { - bool forward = !wxIsShiftDown(); - - nbook->AdvanceSelection(forward); - } - } - } - } -#endif // 1/0 // 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 @@ -2114,13 +2202,10 @@ void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, } void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, - WXWORD *nCtlColor, WXHDC *hdc, WXHWND *hwnd) + WXHDC *hdc, WXHWND *hwnd) { -#ifndef __WXMICROWIN__ - *nCtlColor = CTLCOLOR_BTN; *hwnd = (WXHWND)lParam; *hdc = (WXHDC)wParam; -#endif } void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, @@ -2132,7 +2217,7 @@ void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, } // --------------------------------------------------------------------------- -// Main wxWindows window proc and the window proc for wxWindow +// Main wxWidgets window proc and the window proc for wxWindow // --------------------------------------------------------------------------- // Hook for new window just as it's being created, when the window isn't yet @@ -2193,7 +2278,6 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l { bool allow; WXLRESULT result; - WXHICON hIcon; WXHBRUSH hBrush; } rc; @@ -2222,6 +2306,10 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l (void)HandleDestroy(); break; + case WM_SIZE: + processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam); + break; + case WM_MOVE: processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; @@ -2244,37 +2332,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l } } break; -#endif - - case WM_SIZE: - switch ( wParam ) - { - case SIZE_MAXHIDE: - case SIZE_MAXSHOW: - // we're not interested in these messages at all - break; - - case SIZE_MINIMIZED: - // we shouldn't send sizev events for these messages as the - // client size may be negative which breaks existing code - // - // OTOH we might send another (wxMinimizedEvent?) one or - // add an additional parameter to wxSizeEvent if this is - // useful to anybody - break; - - default: - wxFAIL_MSG( _T("unexpected WM_SIZE parameter") ); - // fall through nevertheless - - case SIZE_MAXIMIZED: - case SIZE_RESTORED: - processed = HandleSize(LOWORD(lParam), HIWORD(lParam), - wParam); - } - break; -#if !defined(__WXWINCE__) case WM_SIZING: { LPRECT pRect = (LPRECT)lParam; @@ -2292,10 +2350,36 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l } } break; -#endif +#endif // !__WXWINCE__ + + case WM_WINDOWPOSCHANGED: + { + WINDOWPOS *lpPos = (WINDOWPOS *)lParam; + + if ( !(lpPos->flags & SWP_NOSIZE) ) + { + RECT rc; + ::GetClientRect(GetHwnd(), &rc); + + AutoHRGN hrgnClient(::CreateRectRgnIndirect(&rc)); + AutoHRGN hrgnNew(::CreateRectRgn(lpPos->x, lpPos->y, + lpPos->cx, lpPos->cy)); + AutoHRGN hrgn(::CreateRectRgn(0, 0, 0, 0)); + + // we need to invalidate any new exposed areas here + // to force them to repaint + if ( ::CombineRgn(hrgn, hrgnNew, hrgnClient, RGN_DIFF) != NULLREGION ) + ::InvalidateRgn(GetHwnd(), hrgn, TRUE); + if ( ::CombineRgn(hrgn, hrgnClient, hrgnNew, RGN_DIFF) != NULLREGION ) + ::InvalidateRgn(GetHwnd(), hrgn, TRUE); + + } + } + break; #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) case WM_ACTIVATEAPP: + // This implicitly sends a wxEVT_ACTIVATE_APP event wxTheApp->SetActive(wParam != 0, FindFocus()); break; #endif @@ -2318,50 +2402,34 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l processed = HandleKillFocus((WXHWND)(HWND)wParam); break; + case WM_PRINTCLIENT: + processed = HandlePrintClient((WXHDC)wParam); + break; + case WM_PAINT: + if ( wParam ) { - if ( wParam ) - { - // cast to wxWindow is needed for wxUniv - wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam); - processed = HandlePaint(); - } - else - { - processed = HandlePaint(); - } - break; - } + wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam); -#ifndef __WXWINCE__ - case WM_PRINT: + processed = HandlePaint(); + } + else // no DC given { - // Don't call the wx handlers in this case - if ( wxIsKindOf(this, wxListCtrl) ) - break; - - if ( lParam & PRF_ERASEBKGND ) - HandleEraseBkgnd((WXHDC)(HDC)wParam); - - wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam); processed = HandlePaint(); } break; -#endif case WM_CLOSE: #ifdef __WXUNIVERSAL__ // Universal uses its own wxFrame/wxDialog, so we don't receive // close events unless we have this. Close(); - processed = true; - rc.result = TRUE; -#else +#endif // __WXUNIVERSAL__ + // don't let the DefWindowProc() destroy our window - we'll do it // ourselves in ~wxWindow processed = true; rc.result = TRUE; -#endif break; case WM_SHOWWINDOW: @@ -2374,62 +2442,21 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l wParam); break; - // Seems to be broken currently -#if 0 // ndef __WXWINCE__ +#ifdef HAVE_TRACKMOUSEEVENT case WM_MOUSELEAVE: - { - wxASSERT_MSG( !m_mouseInWindow, wxT("the mouse should be in a window to generate this event!") ); - - // only process this message if the mouse is not in the window, - // This can also check for children in composite windows. - // however, this may mean the the wxEVT_LEAVE_WINDOW is never sent - // if the mouse does not enter the window from it's child before - // leaving the scope of the window. ( perhaps this can be picked - // up in the OnIdle code as before, for this special case ) - if ( /*IsComposite() && */ !IsMouseInWindow() ) + // filter out excess WM_MOUSELEAVE events sent after PopupMenu() (on XP at least) + if ( m_mouseInWindow ) { - m_mouseInWindow = false; - - // Unfortunately no mouse state is passed with a WM_MOUSE_LEAVE - int state = 0; - if ( wxIsShiftDown() ) - state |= MK_SHIFT; - if ( wxIsCtrlDown() ) - state |= MK_CONTROL; - if ( GetKeyState( VK_LBUTTON ) ) - state |= MK_LBUTTON; - if ( GetKeyState( VK_MBUTTON ) ) - state |= MK_MBUTTON; - if ( GetKeyState( VK_RBUTTON ) ) - state |= MK_RBUTTON; - - POINT pt; - if ( !::GetCursorPos(&pt) ) - { - wxLogLastError(_T("GetCursorPos")); - } - - // we need to have client coordinates here for symmetry with - // wxEVT_ENTER_WINDOW - RECT rect = wxGetWindowRect(GetHwnd()); - pt.x -= rect.left; - pt.y -= rect.top; - - wxMouseEvent event2(wxEVT_LEAVE_WINDOW); - InitMouseEvent(event2, pt.x, pt.y, state); - - (void)GetEventHandler()->ProcessEvent(event2); + GenerateMouseLeave(); } + // always pass processed back as false, this allows the window - // manager to process the message too. This is needed to ensure - // windows XP themes work properly as the mouse moves over widgets - // like buttons. - processed = false; - } - break; -#endif - // __WXWINCE__ - + // manager to process the message too. This is needed to + // ensure windows XP themes work properly as the mouse moves + // over widgets like buttons. So don't set processed to true here. + break; +#endif // HAVE_TRACKMOUSEEVENT + #if wxUSE_MOUSEWHEEL case WM_MOUSEWHEEL: processed = HandleMouseWheel(wParam, lParam); @@ -2487,19 +2514,23 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l // this should never happen wxCHECK_MSG( win, 0, _T("FindWindowForMouseEvent() returned NULL") ); + } + processed = win->HandleMouseEvent(message, x, y, wParam); + + // if the app didn't eat the event, handle it in the default + // way, that is by giving this window the focus + if ( !processed ) + { // for the standard classes their WndProc sets the focus to // them anyhow and doing it from here results in some weird - // problems, but for our windows we want them to acquire - // focus when clicked + // problems, so don't do it for them (unnecessary anyhow) if ( !win->IsOfStandardClass() ) { if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() ) win->SetFocus(); } } - - processed = win->HandleMouseEvent(message, x, y, wParam); } break; @@ -2519,10 +2550,6 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l break; #endif // __WXMICROWIN__ - case WM_SYSCOMMAND: - processed = HandleSysCommand(wParam, lParam); - break; - case WM_COMMAND: { WORD id, cmd; @@ -2650,13 +2677,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l // special case of VK_APPS: treat it the same as right mouse // click because both usually pop up a context menu case VK_APPS: - { - WPARAM flags; - int x, y; - - TranslateKbdEventToMouse(this, &x, &y, &flags); - processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags); - } + processed = HandleMouseEvent(WM_RBUTTONDOWN, -1, -1, 0); break; #endif // VK_APPS @@ -2675,11 +2696,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l // special case of VK_APPS: treat it the same as right mouse button if ( wParam == VK_APPS ) { - WPARAM flags; - int x, y; - - TranslateKbdEventToMouse(this, &x, &y, &flags); - processed = HandleMouseEvent(WM_RBUTTONUP, x, y, flags); + processed = HandleMouseEvent(WM_RBUTTONUP, -1, -1, 0); } else #endif // VK_APPS @@ -2724,7 +2741,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l break; // CTLCOLOR messages are sent by children to query the parent for their - // colors#ifndef __WXMICROWIN__ + // colors #ifndef __WXMICROWIN__ case WM_CTLCOLORMSGBOX: case WM_CTLCOLOREDIT: @@ -2734,18 +2751,11 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORSTATIC: { - WXWORD nCtlColor; WXHDC hdc; WXHWND hwnd; - UnpackCtlColor(wParam, lParam, &nCtlColor, &hdc, &hwnd); - - processed = HandleCtlColor(&rc.hBrush, - (WXHDC)hdc, - (WXHWND)hwnd, - nCtlColor, - message, - wParam, - lParam); + UnpackCtlColor(wParam, lParam, &hdc, &hwnd); + + processed = HandleCtlColor(&rc.hBrush, (WXHDC)hdc, (WXHWND)hwnd); } break; #endif // !__WXMICROWIN__ @@ -2857,7 +2867,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), #ifdef __WXWINCE__ - wxPoint(0, 0) + wxPoint(0,0) #else wxPoint(info->MousePos.x, info->MousePos.y) #endif @@ -2949,7 +2959,7 @@ wxWinHashTable *wxWinHandleHash = NULL; wxWindow *wxFindWinFromHandle(WXHWND hWnd) { - return wxWinHandleHash->Get((long)hWnd); + return (wxWindow*)wxWinHandleHash->Get((long)hWnd); } void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) @@ -2999,7 +3009,7 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, bool nonDefault = false; - if ( pos.x == -1 ) + if ( pos.x == wxDefaultCoord ) { // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we // can just as well set it to CW_USEDEFAULT as well @@ -3012,7 +3022,7 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, // neither because it is not handled as a special value by Windows then // and so we have to choose some default value for it x = pos.x; - y = pos.y == -1 ? DEFAULT_Y : pos.y; + y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y; nonDefault = true; } @@ -3020,7 +3030,7 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, /* NB: there used to be some code here which set the initial size of the window to the client size of the parent if no explicit size was - specified. This was wrong because wxWindows programs often assume + specified. This was wrong because wxWidgets programs often assume that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke it. To see why, you should understand that Windows sends WM_SIZE from inside ::CreateWindow() anyhow. However, ::CreateWindow() is called @@ -3029,17 +3039,17 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, event goes to some base class OnSize() instead). So the WM_SIZE we rely on is the one sent when the parent frame resizes its children but here is the problem: if the child already has just the right - size, nothing will happen as both wxWindows and Windows check for + size, nothing will happen as both wxWidgets and Windows check for this and ignore any attempts to change the window size to the size it already has - so no WM_SIZE would be sent. */ - + // we don't use CW_USEDEFAULT here for several reasons: // // 1. it results in huge frames on modern screens (1000*800 is not // uncommon on my 1280*1024 screen) which is way too big for a half - // empty frame of most of wxWindows samples for example) + // empty frame of most of wxWidgets samples for example) // // 2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which // the default is for whatever reason 8*8 which breaks client <-> @@ -3052,12 +3062,26 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, // level window in some smart way which we can't do, but we can // guess a reasonably good size for a new window just as well // ourselves - if ( size.x == -1 || size.y == -1) + + // However, on PocketPC devices, we must use the default + // size if possible. +#ifdef _WIN32_WCE + if (size.x == wxDefaultCoord) + w = CW_USEDEFAULT; + else + w = size.x; + if (size.y == wxDefaultCoord) + h = CW_USEDEFAULT; + else + h = size.y; +#else + if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord) { nonDefault = true; } w = WidthDefault(size.x); h = HeightDefault(size.y); +#endif AdjustForParentClientOrigin(x, y); @@ -3096,41 +3120,22 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, // do create the window wxWindowCreationHook hook(this); -#ifdef __WXWINCE__ - if (extendedStyle == 0) - { - m_hWnd = (WXHWND)::CreateWindow - ( - className, - title ? title : wxEmptyString, - style, - x, y, w, h, - (HWND)MSWGetParent(), - (HMENU)controlId, - wxGetInstance(), - NULL // no extra data - ); - } - else -#endif - { - m_hWnd = (WXHWND)::CreateWindowEx - ( - extendedStyle, - className, - title ? title : wxEmptyString, - style, - x, y, w, h, - (HWND)MSWGetParent(), - (HMENU)controlId, - wxGetInstance(), - NULL // no extra data - ); - } + m_hWnd = (WXHWND)::CreateWindowEx + ( + extendedStyle, + className, + title ? title : m_windowName.c_str(), + style, + x, y, w, h, + (HWND)MSWGetParent(), + (HMENU)controlId, + wxGetInstance(), + NULL // no extra data + ); if ( !m_hWnd ) { - wxLogSysError(_("Can't create window of class %s"), wclass); + wxLogSysError(_("Can't create window of class %s"), className.c_str()); return false; } @@ -3286,6 +3291,8 @@ bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl), return true; } } +#else + wxUnusedVar(lParam); #endif // wxUSE_TOOLTIPS return false; @@ -3299,8 +3306,8 @@ bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl), bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd) { -#ifndef __WXWINCE__ - wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1); +#ifdef ENDSESSION_LOGOFF + wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY); event.SetEventObject(wxTheApp); event.SetCanVeto(true); event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF); @@ -3316,13 +3323,15 @@ bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd) return rc; #else + wxUnusedVar(logOff); + wxUnusedVar(mayEnd); return false; #endif } bool wxWindowMSW::HandleEndSession(bool endSession, long logOff) { -#ifndef __WXWINCE__ +#ifdef ENDSESSION_LOGOFF // do nothing if the session isn't ending if ( !endSession ) return false; @@ -3331,13 +3340,15 @@ bool wxWindowMSW::HandleEndSession(bool endSession, long logOff) if ( (this != wxTheApp->GetTopWindow()) ) return false; - wxCloseEvent event(wxEVT_END_SESSION, -1); + wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY); event.SetEventObject(wxTheApp); event.SetCanVeto(false); event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) ); return wxTheApp->ProcessEvent(event); #else + wxUnusedVar(endSession); + wxUnusedVar(logOff); return false; #endif } @@ -3354,6 +3365,8 @@ bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT cs, bool *mayCreate) #ifndef __WXWINCE__ if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT ) EnsureParentHasControlParentStyle(GetParent()); +#else + wxUnusedVar(cs); #endif // !__WXWINCE__ // TODO: should generate this event from WM_NCCREATE @@ -3402,6 +3415,13 @@ bool wxWindowMSW::HandleActivate(int state, bool wxWindowMSW::HandleSetFocus(WXHWND hwnd) { + // Strangly enough, some controls get set focus events when they are being + // deleted, even if they already had focus before. + if ( m_isBeingDeleted ) + { + return false; + } + // notify the parent keeping track of focus for the kbd navigation // purposes that we got it wxChildFocusEvent eventFocus((wxWindow *)this); @@ -3476,7 +3496,7 @@ bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status)) { wxShowEvent event(GetId(), show); - event.m_eventObject = this; + event.SetEventObject(this); return GetEventHandler()->ProcessEvent(event); } @@ -3484,7 +3504,7 @@ bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status)) bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) { wxInitDialogEvent event(GetId()); - event.m_eventObject = this; + event.SetEventObject(this); return GetEventHandler()->ProcessEvent(event); } @@ -3492,6 +3512,7 @@ bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) { #if defined (__WXMICROWIN__) || defined(__WXWINCE__) + wxUnusedVar(wParam); return false; #else // __WXMICROWIN__ HDROP hFilesInfo = (HDROP) wParam; @@ -3518,7 +3539,7 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) DragFinish (hFilesInfo); wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files); - event.m_eventObject = this; + event.SetEventObject(this); POINT dropPoint; DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint); @@ -3553,7 +3574,11 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), // 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)) +#else if ( !::GetCursorPos(&pt) ) +#endif { wxLogLastError(wxT("GetCursorPos")); } @@ -3638,7 +3663,12 @@ wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id), { wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData); - wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), false ); + // see comment before the same test in MSWOnMeasureItem() below + if ( !pMenuItem ) + return false; + + wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem), + false, _T("MSWOnDrawItem: bad wxMenuItem pointer") ); // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent // the DC from being released @@ -3666,7 +3696,13 @@ wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id), #else // !wxUSE_OWNER_DRAWN // we may still have owner-drawn buttons internally because we have to make // them owner-drawn to support colour change - wxControl *item = wxDynamicCast(FindItem(id), wxButton); + wxControl *item = +# if wxUSE_BUTTON + wxDynamicCast(FindItem(id), wxButton) +# else + NULL +# endif + ; #endif // USE_OWNER_DRAWN if ( item ) @@ -3680,9 +3716,7 @@ wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id), } bool -wxWindowMSW::MSWOnMeasureItem(int WXUNUSED_UNLESS_ODRAWN(id), - WXMEASUREITEMSTRUCT * - WXUNUSED_UNLESS_ODRAWN(itemStruct)) +wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) { #if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE // is it a menu item? @@ -3691,7 +3725,16 @@ wxWindowMSW::MSWOnMeasureItem(int WXUNUSED_UNLESS_ODRAWN(id), { wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData); - wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), false ); + // according to Carsten Fuchs the pointer may be NULL under XP if an + // MDI child frame is initially maximized, see this for more info: + // http://article.gmane.org/gmane.comp.lib.wxwidgets.general/27745 + // + // so silently ignore it instead of asserting + if ( !pMenuItem ) + return false; + + wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem), + false, _T("MSWOnMeasureItem: bad wxMenuItem pointer") ); size_t w, h; bool rc = pMenuItem->OnMeasureItem(&w, &h); @@ -3707,7 +3750,10 @@ wxWindowMSW::MSWOnMeasureItem(int WXUNUSED_UNLESS_ODRAWN(id), { return item->MSWOnMeasure(itemStruct); } -#endif // wxUSE_OWNER_DRAWN +#else + wxUnusedVar(id); + wxUnusedVar(itemStruct); +#endif // wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE return false; } @@ -3736,53 +3782,26 @@ bool wxWindowMSW::HandleDisplayChange() return GetEventHandler()->ProcessEvent(event); } -bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, - WXHDC pDC, - WXHWND pWnd, - WXUINT nCtlColor, - WXUINT message, - WXWPARAM wParam, - WXLPARAM lParam) -{ #ifndef __WXMICROWIN__ - WXHBRUSH hBrush = 0; -#ifdef __WXWINCE__ - if (false) +bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, WXHDC hDC, WXHWND hWnd) +{ +#if !wxUSE_CONTROLS || defined(__WXUNIVERSAL__) + wxUnusedVar(hDC); + wxUnusedVar(hWnd); #else - if ( nCtlColor == CTLCOLOR_DLG ) -#endif - { - hBrush = OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); - } -#if wxUSE_CONTROLS + wxControl *item = wxDynamicCast(FindItemByHWND(hWnd, true), wxControl); + + if ( item ) + *brush = item->MSWControlColor(hDC, hWnd); else - { - wxControl *item = (wxControl *)FindItemByHWND(pWnd, true); - if ( item ) - hBrush = item->OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); - } #endif // wxUSE_CONTROLS + *brush = NULL; - if ( hBrush ) - *brush = hBrush; - - return hBrush != 0; -#else // __WXMICROWIN__ - return false; -#endif + return *brush != NULL; } -// Define for each class of dialog and control -WXHBRUSH wxWindowMSW::OnCtlColor(WXHDC WXUNUSED(hDC), - WXHWND WXUNUSED(hWnd), - WXUINT WXUNUSED(nCtlColor), - WXUINT WXUNUSED(message), - WXWPARAM WXUNUSED(wParam), - WXLPARAM WXUNUSED(lParam)) -{ - return (WXHBRUSH)0; -} +#endif // __WXMICROWIN__ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange) { @@ -3844,7 +3863,7 @@ bool wxWindowMSW::HandleQueryNewPalette() while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent(); if (win->HasCustomPalette()) { /* realize the palette to see whether redrawing is needed */ - HDC hdc = GetDC((HWND) GetHWND()); + HDC hdc = ::GetDC((HWND) GetHWND()); win->m_palette.SetHPALETTE( (WXHPALETTE) ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) ); @@ -3893,20 +3912,6 @@ void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) node = node->GetNext(); } - - // update the colours we use if they were not set explicitly by the user: - // this must be done or OnCtlColor() would continue to use the old colours - if ( !m_hasFgCol ) - { - m_foregroundColour = wxSystemSettings:: - GetSystemColour(wxSYS_COLOUR_WINDOWTEXT); - } - - if ( !m_hasBgCol ) - { - m_backgroundColour = wxSystemSettings:: - GetSystemColour(wxSYS_COLOUR_BTNFACE); - } } extern wxCOLORMAP *wxGetStdColourMap() @@ -3927,6 +3932,7 @@ extern wxCOLORMAP *wxGetStdColourMap() // we want to avoid Windows' "help" and for this we need to have a // 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")); if ( stdColourBitmap.Ok() ) { @@ -3981,9 +3987,6 @@ extern wxCOLORMAP *wxGetStdColourMap() bool wxWindowMSW::HandlePaint() { -// if (GetExtraStyle() & wxWS_EX_THEMED_BACKGROUND) -// return FALSE; - HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle if ( !hRegion ) wxLogLastError(wxT("CreateRectRgn")); @@ -4023,33 +4026,6 @@ void wxWindowMSW::OnPaint(wxPaintEvent& event) bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) { - // Prevents flicker when dragging - if ( ::IsIconic(GetHwnd()) ) - return true; - -#if 0 - if (GetParent() && GetParent()->GetExtraStyle() & wxWS_EX_THEMED_BACKGROUND) - { - return false; - } - - if (GetExtraStyle() & wxWS_EX_THEMED_BACKGROUND) - { - if (wxUxThemeEngine::Get()) - { - WXHTHEME hTheme = wxUxThemeEngine::Get()->m_pfnOpenThemeData(GetHWND(), L"TAB"); - if (hTheme) - { - WXURECT rect; - ::GetClientRect((HWND) GetHWND(), (RECT*) & rect); - wxUxThemeEngine::Get()->m_pfnDrawThemeBackground(hTheme, hdc, 10 /* TABP_BODY */, 0, &rect, &rect); - wxUxThemeEngine::Get()->m_pfnCloseThemeData(hTheme); - return true; - } - } - } -#endif - wxDCTemp dc(hdc); dc.SetHDC(hdc); @@ -4070,28 +4046,119 @@ bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) void wxWindowMSW::OnEraseBackground(wxEraseEvent& event) { - RECT rect; - ::GetClientRect(GetHwnd(), &rect); + // 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; + } - COLORREF ref = PALETTERGB(m_backgroundColour.Red(), - m_backgroundColour.Green(), - m_backgroundColour.Blue()); - HBRUSH hBrush = ::CreateSolidBrush(ref); - if ( !hBrush ) - wxLogLastError(wxT("CreateSolidBrush")); + if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM ) + { + // 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; + } - HDC hdc = (HDC)event.GetDC()->GetHDC(); -#ifndef __WXWINCE__ - int mode = ::SetMapMode(hdc, MM_TEXT); -#endif + // do default background painting + if ( !DoEraseBackground(GetHdcOf(*event.GetDC())) ) + { + // let the system paint the background + event.Skip(); + } +} + +bool wxWindowMSW::DoEraseBackground(WXHDC hDC) +{ + HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC); + if ( !hbr ) + return false; - ::FillRect(hdc, &rect, hBrush); - ::DeleteObject(hBrush); + wxFillRect(GetHwnd(), (HDC)hDC, hbr); -#ifndef __WXWINCE__ - ::SetMapMode(hdc, mode); -#endif + return true; +} + +WXHBRUSH +wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd) +{ + if ( m_hasBgCol ) + { + // our background colour applies to: + // 1. this window itself, always + // 2. all children unless the colour is "not inheritable" + // 3. even if it is not inheritable, our immediate transparent + // children should still inherit it -- but not any transparent + // 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 || + m_inheritBgCol || + (win && win->HasTransparentBackground() && + win->GetParent() == this) ) + { + // draw children with the same colour as the parent + wxBrush * + brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()); + + return (WXHBRUSH)GetHbrushOf(*brush); + } + } + + return 0; +} + +WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, WXHWND hWndToPaint) +{ + if ( !hWndToPaint ) + hWndToPaint = GetHWND(); + + for ( wxWindowMSW *win = this; win; win = win->GetParent() ) + { + WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, hWndToPaint); + if ( hBrush ) + return hBrush; + + // background is not inherited beyond top level windows + if ( win->IsTopLevel() ) + break; + } + + return 0; +} + +bool wxWindowMSW::HandlePrintClient(WXHDC hDC) +{ + // 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; + + for ( wxWindow *win = GetParent(); win; win = win->GetParent() ) + { + if ( win->MSWPrintChild(hDC, (wxWindow *)this) ) + return true; + + if ( win->IsTopLevel() || win->InheritsBackgroundColour() ) + break; + } + + return false; } // --------------------------------------------------------------------------- @@ -4116,7 +4183,8 @@ bool wxWindowMSW::HandleMaximize() bool wxWindowMSW::HandleMove(int x, int y) { - wxMoveEvent event(wxPoint(x, y), m_windowId); + wxPoint point(x,y); + wxMoveEvent event(point, m_windowId); event.SetEventObject(this); return GetEventHandler()->ProcessEvent(event); @@ -4133,16 +4201,100 @@ bool wxWindowMSW::HandleMoving(wxRect& rect) return rc; } -bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), - WXUINT WXUNUSED(flag)) +bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) { - // don't use w and h parameters as they specify the client size while - // according to the docs EVT_SIZE handler is supposed to receive the total - // size - wxSizeEvent event(GetSize(), m_windowId); - event.SetEventObject(this); +#if USE_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; + for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD); + child; + child = ::GetWindow(child, GW_HWNDNEXT) ) + { + numChildren ++; + } - return GetEventHandler()->ProcessEvent(event); + // Protect against valid m_hDWP being overwritten + bool useDefer = false; + + if ( numChildren > 1 ) + { + if (!m_hDWP) + { + m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren); + if ( !m_hDWP ) + { + wxLogLastError(_T("BeginDeferWindowPos")); + } + if (m_hDWP) + useDefer = true; + } + } +#endif + + // update this window size + bool processed = false; + switch ( wParam ) + { + default: + wxFAIL_MSG( _T("unexpected WM_SIZE parameter") ); + // fall through nevertheless + + case SIZE_MAXHIDE: + case SIZE_MAXSHOW: + // we're not interested in these messages at all + break; + + case SIZE_MINIMIZED: + processed = HandleMinimize(); + break; + + case SIZE_MAXIMIZED: + /* processed = */ HandleMaximize(); + // fall through to send a normal size event as well + + case SIZE_RESTORED: + // don't use w and h parameters as they specify the client size + // while according to the docs EVT_SIZE handler is supposed to + // receive the total size + wxSizeEvent event(GetSize(), m_windowId); + event.SetEventObject(this); + + processed = GetEventHandler()->ProcessEvent(event); + } + +#if USE_DEFERRED_SIZING + // and finally change the positions of all child windows at once + if ( useDefer && m_hDWP ) + { + // reset m_hDWP to NULL so that child windows don't try to use our + // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't + // happen anyhow normally but who knows what weird flow of control we + // may have depending on what the users EVT_SIZE handler does...) + HDWP hDWP = (HDWP)m_hDWP; + m_hDWP = NULL; + + // do put all child controls in place at once + if ( !::EndDeferWindowPos(hDWP) ) + { + wxLogLastError(_T("EndDeferWindowPos")); + } + +#if USE_DEFER_BUG_WORKAROUND + // Reset our children's pending pos/size values. + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *child = node->GetData(); + child->m_pendingPosition = wxDefaultPosition; + child->m_pendingSize = wxDefaultSize; + } +#endif + } +#endif + + return processed; } bool wxWindowMSW::HandleSizing(wxRect& rect) @@ -4159,6 +4311,7 @@ bool wxWindowMSW::HandleSizing(wxRect& rect) bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo) { #ifdef __WXWINCE__ + wxUnusedVar(mmInfo); return false; #else MINMAXINFO *info = (MINMAXINFO *)mmInfo; @@ -4170,25 +4323,25 @@ bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo) maxWidth = GetMaxWidth(), maxHeight = GetMaxHeight(); - if ( minWidth != -1 ) + if ( minWidth != wxDefaultCoord ) { info->ptMinTrackSize.x = minWidth; rc = true; } - if ( minHeight != -1 ) + if ( minHeight != wxDefaultCoord ) { info->ptMinTrackSize.y = minHeight; rc = true; } - if ( maxWidth != -1 ) + if ( maxWidth != wxDefaultCoord ) { info->ptMaxTrackSize.x = maxWidth; rc = true; } - if ( maxHeight != -1 ) + if ( maxHeight != wxDefaultCoord ) { info->ptMaxTrackSize.y = maxHeight; rc = true; @@ -4251,34 +4404,26 @@ bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) return GetEventHandler()->ProcessEvent(event); } -#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__) else { +#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__) // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND // notifications to its parent which we want to reflect back to // wxSpinCtrl wxSpinCtrl *spin = wxSpinCtrl::GetSpinForTextCtrl(control); if ( spin && spin->ProcessTextCommand(cmd, id) ) return true; - } #endif // wxUSE_SPINCTRL - return false; -} - -bool wxWindowMSW::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam)) -{ -#ifndef __WXWINCE__ - // 4 bits are reserved - switch ( wParam & 0xFFFFFFF0 ) - { - case SC_MAXIMIZE: - return HandleMaximize(); - - case SC_MINIMIZE: - return HandleMinimize(); - } +#if wxUSE_CHOICE && defined(__SMARTPHONE__) + // the listbox ctrl which is logically part of wxChoice sends WM_COMMAND + // notifications to its parent which we want to reflect back to + // wxChoice + wxChoice *choice = wxChoice::GetChoiceForListBox(control); + if ( choice && choice->MSWCommand(cmd, id) ) + return true; #endif + } return false; } @@ -4301,16 +4446,13 @@ 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) & 0x80000000) != 0; - // Returns different negative values on WinME and WinNT, - // so simply test for negative value. event.m_altDown = ::GetKeyState(VK_MENU) < 0; #ifndef __WXWINCE__ event.SetTimestamp(::GetMessageTime()); #endif - event.m_eventObject = this; + event.SetEventObject(this); event.SetId(GetId()); #if wxUSE_MOUSEEVENT_HACK @@ -4387,7 +4529,7 @@ static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) // bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags) { // the mouse events take consecutive IDs from WM_MOUSEFIRST to - // WM_MOUSELAST, so it's enough to substract WM_MOUSEMOVE == WM_MOUSEFIRST + // WM_MOUSELAST, so it's enough to subtract WM_MOUSEMOVE == WM_MOUSEFIRST // from the message id and take the value in the table to get wxWin event // id static const wxEventType eventsMouse[] = @@ -4422,19 +4564,18 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags) { // Generate an ENTER event m_mouseInWindow = true; -#if _WIN32_WINNT >= 0x0400 -#ifndef __WXWINCE__ - TRACKMOUSEEVENT trackinfo; - trackinfo.cbSize = sizeof(trackinfo); +#ifdef HAVE_TRACKMOUSEEVENT + WinStruct trackinfo; + trackinfo.dwFlags = TME_LEAVE; trackinfo.hwndTrack = GetHwnd(); - //Use the commctrl.h _TrackMouseEvent, which will call the - // appropriate TrackMouseEvent or emulate it ( win95 ) - // else we need _WIN32_WINNT >= 0x0400 + + // Use the commctrl.h _TrackMouseEvent(), which will call the real + // TrackMouseEvent() if available or emulate it _TrackMouseEvent(&trackinfo); -#endif -#endif +#endif // HAVE_TRACKMOUSEEVENT + wxMouseEvent event(wxEVT_ENTER_WINDOW); InitMouseEvent(event, x, y, flags); @@ -4489,14 +4630,53 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) event.m_linesPerAction = s_linesPerRotation; return GetEventHandler()->ProcessEvent(event); -#else - (void) wParam; - (void) lParam; +#else // !wxUSE_MOUSEWHEEL + wxUnusedVar(wParam); + wxUnusedVar(lParam); return false; -#endif +#endif // wxUSE_MOUSEWHEEL/!wxUSE_MOUSEWHEEL } +void wxWindowMSW::GenerateMouseLeave() +{ + m_mouseInWindow = false; + + int state = 0; + if ( wxIsShiftDown() ) + state |= MK_SHIFT; + if ( wxIsCtrlDown() ) + state |= MK_CONTROL; + + // Only the high-order bit should be tested + if ( GetKeyState( VK_LBUTTON ) & (1<<15) ) + state |= MK_LBUTTON; + if ( GetKeyState( VK_MBUTTON ) & (1<<15) ) + state |= MK_MBUTTON; + if ( GetKeyState( VK_RBUTTON ) & (1<<15) ) + state |= MK_RBUTTON; + + POINT pt; +#ifdef __WXWINCE__ + if ( !::GetCursorPosWinCE(&pt) ) +#else + if ( !::GetCursorPos(&pt) ) +#endif + { + wxLogLastError(_T("GetCursorPos")); + } + + // we need to have client coordinates here for symmetry with + // wxEVT_ENTER_WINDOW + RECT rect = wxGetWindowRect(GetHwnd()); + pt.x -= rect.left; + pt.y -= rect.top; + + wxMouseEvent event(wxEVT_LEAVE_WINDOW); + InitMouseEvent(event, pt.x, pt.y, state); + + (void)GetEventHandler()->ProcessEvent(event); +} // --------------------------------------------------------------------------- // keyboard handling @@ -4515,8 +4695,11 @@ wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType, event.m_controlDown = wxIsCtrlDown(); event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN; - event.m_eventObject = (wxWindow *)this; // const_cast + event.SetEventObject((wxWindow *)this); // const_cast event.m_keyCode = id; +#if wxUSE_UNICODE + event.m_uniChar = (wxChar) wParam; +#endif event.m_rawCode = (wxUint32) wParam; event.m_rawFlags = (wxUint32) lParam; #ifndef __WXWINCE__ @@ -4525,7 +4708,11 @@ wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType, // translate the position to client coords POINT pt; +#ifdef __WXWINCE__ + GetCursorPosWinCE(&pt); +#else GetCursorPos(&pt); +#endif RECT rect; GetWindowRect(GetHwnd(),&rect); pt.x -= rect.left; @@ -4679,7 +4866,7 @@ int wxWindowMSW::HandleMenuChar(int chAccel, WXLPARAM lParam) // FIXME-UNICODE: this comparison doesn't risk to work // for non ASCII accelerator characters I'm afraid, but // what can we do? - if ( wxToupper(*p) == chAccel ) + if ( (wchar_t)wxToupper(*p) == (wchar_t)chAccel ) { return i; } @@ -4699,6 +4886,9 @@ int wxWindowMSW::HandleMenuChar(int chAccel, WXLPARAM lParam) wxLogLastError(_T("GetMenuItemInfo")); } } +#else + wxUnusedVar(chAccel); + wxUnusedVar(lParam); #endif return wxNOT_FOUND; } @@ -4787,6 +4977,10 @@ bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) return GetEventHandler()->ProcessEvent(event); #else + wxUnusedVar(msg); + wxUnusedVar(x); + wxUnusedVar(y); + wxUnusedVar(flags); return false; #endif } @@ -4797,7 +4991,7 @@ bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, WXWORD pos, WXHWND control) -{ +{ if ( control && control != m_hWnd ) // Prevent infinite recursion { wxWindow *child = wxFindWinFromHandle(control); @@ -4808,32 +5002,32 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, wxScrollWinEvent event; event.SetPosition(pos); event.SetOrientation(orientation); - event.m_eventObject = this; + event.SetEventObject(this); switch ( wParam ) { case SB_TOP: - event.m_eventType = wxEVT_SCROLLWIN_TOP; + event.SetEventType(wxEVT_SCROLLWIN_TOP); break; case SB_BOTTOM: - event.m_eventType = wxEVT_SCROLLWIN_BOTTOM; + event.SetEventType(wxEVT_SCROLLWIN_BOTTOM); break; case SB_LINEUP: - event.m_eventType = wxEVT_SCROLLWIN_LINEUP; + event.SetEventType(wxEVT_SCROLLWIN_LINEUP); break; case SB_LINEDOWN: - event.m_eventType = wxEVT_SCROLLWIN_LINEDOWN; + event.SetEventType(wxEVT_SCROLLWIN_LINEDOWN); break; case SB_PAGEUP: - event.m_eventType = wxEVT_SCROLLWIN_PAGEUP; + event.SetEventType(wxEVT_SCROLLWIN_PAGEUP); break; case SB_PAGEDOWN: - event.m_eventType = wxEVT_SCROLLWIN_PAGEDOWN; + event.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN); break; case SB_THUMBPOSITION: @@ -4859,9 +5053,9 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, event.SetPosition(scrollInfo.nTrackPos); } - event.m_eventType = wParam == SB_THUMBPOSITION + event.SetEventType( wParam == SB_THUMBPOSITION ? wxEVT_SCROLLWIN_THUMBRELEASE - : wxEVT_SCROLLWIN_THUMBTRACK; + : wxEVT_SCROLLWIN_THUMBTRACK ); break; default: @@ -4875,22 +5069,20 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, // global functions // =========================================================================== -void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font) +void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font) { TEXTMETRIC tm; HDC dc = ::GetDC((HWND) wnd); - HFONT fnt =0; HFONT was = 0; - if ( the_font ) - { - // the_font->UseResource(); - // the_font->RealizeResource(); - fnt = (HFONT)((wxFont *)the_font)->GetResourceHandle(); // const_cast - if ( fnt ) - was = (HFONT) SelectObject(dc,fnt); - } + + // the_font.UseResource(); + // the_font.RealizeResource(); + HFONT fnt = (HFONT)the_font.GetResourceHandle(); // const_cast + if ( fnt ) + was = (HFONT) SelectObject(dc,fnt); + GetTextMetrics(dc, &tm); - if ( the_font && fnt && was ) + if ( fnt && was ) { SelectObject(dc,was); } @@ -4901,8 +5093,7 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font) if ( y ) *y = tm.tmHeight + tm.tmExternalLeading; - // if ( the_font ) - // the_font->ReleaseResource(); + // the_font.ReleaseResource(); } // Returns 0 if was a normal ASCII value, not a special key. This indicates that @@ -4918,7 +5109,7 @@ int wxCharCodeMSWToWX(int keySym, WXLPARAM lParam) case VK_CLEAR: id = WXK_CLEAR; break; case VK_SHIFT: id = WXK_SHIFT; break; case VK_CONTROL: id = WXK_CONTROL; break; - case VK_MENU : id = WXK_MENU; break; + case VK_MENU : id = WXK_ALT; break; case VK_PAUSE: id = WXK_PAUSE; break; case VK_CAPITAL: id = WXK_CAPITAL; break; case VK_SPACE: id = WXK_SPACE; break; @@ -4979,6 +5170,8 @@ int wxCharCodeMSWToWX(int keySym, WXLPARAM lParam) case VK_NUMLOCK: id = WXK_NUMLOCK; break; case VK_SCROLL: id = WXK_SCROLL; break; + // the mapping for these keys may be incorrect on non-US keyboards so + // maybe we shouldn't map them to ASCII values at all case VK_OEM_1: id = ';'; break; case VK_OEM_PLUS: id = '+'; break; case VK_OEM_COMMA: id = ','; break; @@ -5011,18 +5204,19 @@ int wxCharCodeMSWToWX(int keySym, WXLPARAM lParam) return id; } -int wxCharCodeWXToMSW(int id, bool *isVirtual) +WXWORD wxCharCodeWXToMSW(int id, bool *isVirtual) { *isVirtual = true; - int keySym; + WXWORD keySym; switch (id) { case WXK_CANCEL: keySym = VK_CANCEL; break; case WXK_CLEAR: keySym = VK_CLEAR; break; case WXK_SHIFT: keySym = VK_SHIFT; break; case WXK_CONTROL: keySym = VK_CONTROL; break; - case WXK_MENU : keySym = VK_MENU; break; + case WXK_ALT: keySym = VK_MENU; break; case WXK_PAUSE: keySym = VK_PAUSE; break; + case WXK_CAPITAL: keySym = VK_CAPITAL; break; case WXK_PRIOR: keySym = VK_PRIOR; break; case WXK_NEXT : keySym = VK_NEXT; break; case WXK_END: keySym = VK_END; break; @@ -5081,7 +5275,7 @@ int wxCharCodeWXToMSW(int id, bool *isVirtual) default: { *isVirtual = false; - keySym = id; + keySym = (WORD)id; break; } } @@ -5091,13 +5285,35 @@ int wxCharCodeWXToMSW(int id, bool *isVirtual) bool wxGetKeyState(wxKeyCode key) { bool bVirtual; - int vkey = wxCharCodeWXToMSW(key, &bVirtual); - - //there aren't WXK_ macros for non-virtual key codes - if (bVirtual == false) - return false; - return GetKeyState(vkey) < 0; + wxASSERT_MSG(key != WXK_LBUTTON && key != WXK_RBUTTON && key != + WXK_MBUTTON, wxT("can't use wxGetKeyState() for mouse buttons")); + +//High order with GetAsyncKeyState only available on WIN32 +#ifdef __WIN32__ + //If the requested key is a LED key, return + //true if the led is pressed + if (key == WXK_NUMLOCK || + key == WXK_CAPITAL || + key == WXK_SCROLL) + { +#endif + //low order bit means LED is highlighted, + //high order means key is down + //Here, for compat with other ports we want both + return GetKeyState( wxCharCodeWXToMSW(key, &bVirtual) ) != 0; + +#ifdef __WIN32__ + } + else + { + //normal key + //low order bit means key pressed since last call + //high order means key is down + //We want only the high order bit - the key may not be down if only low order + return ( GetAsyncKeyState( wxCharCodeWXToMSW(key, &bVirtual) ) & (1<<15) ) != 0; + } +#endif } wxWindow *wxGetActiveWindow() @@ -5209,7 +5425,7 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) event.m_altDown = true; - event.m_eventObject = NULL; + event.SetEventObject(NULL); event.m_keyCode = id; event.m_shiftDown = wxIsShiftDown(); event.m_controlDown = wxIsCtrlDown(); @@ -5226,7 +5442,7 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) else { handler = wxTheApp; - event.SetId(-1); + event.SetId(wxID_ANY); } if ( handler && handler->ProcessEvent(event) ) @@ -5654,26 +5870,6 @@ const char *wxGetMessageName(int message) } #endif //__WXDEBUG__ -static void TranslateKbdEventToMouse(wxWindowMSW *win, - int *x, int *y, WPARAM *flags) -{ - // construct the key mask - WPARAM& fwKeys = *flags; - - fwKeys = MK_RBUTTON; - if ( wxIsCtrlDown() ) - fwKeys |= MK_CONTROL; - if ( wxIsShiftDown() ) - fwKeys |= MK_SHIFT; - - // simulate right mouse button click - DWORD dwPos = ::GetMessagePos(); - *x = GET_X_LPARAM(dwPos); - *y = GET_Y_LPARAM(dwPos); - - win->ScreenToClient(x, y); -} - static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win) { // prepare the DC @@ -5737,13 +5933,36 @@ wxWindow* wxFindWindowAtPoint(const wxPoint& pt) wxPoint wxGetMousePosition() { POINT pt; +#ifdef __WXWINCE__ + GetCursorPosWinCE(&pt); +#else GetCursorPos( & pt ); +#endif return wxPoint(pt.x, pt.y); } #if wxUSE_HOTKEY +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) +static void WinCEUnregisterHotKey(int modifiers, int id) +{ + // Register hotkeys for the hardware buttons + HINSTANCE hCoreDll; + typedef BOOL (WINAPI *UnregisterFunc1Proc)(UINT, UINT); + + UnregisterFunc1Proc procUnregisterFunc; + hCoreDll = LoadLibrary(_T("coredll.dll")); + if (hCoreDll) + { + procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, _T("UnregisterFunc1")); + if (procUnregisterFunc) + procUnregisterFunc(modifiers, id); + FreeLibrary(hCoreDll); + } +} +#endif + bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode) { UINT win_modifiers=0; @@ -5756,6 +5975,12 @@ bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode) if ( modifiers & wxMOD_WIN ) win_modifiers |= MOD_WIN; +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) + // Required for PPC and Smartphone hardware buttons + if (keycode >= WXK_SPECIAL1 && keycode <= WXK_SPECIAL20) + WinCEUnregisterHotKey(win_modifiers, hotkeyId); +#endif + if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) ) { wxLogLastError(_T("RegisterHotKey")); @@ -5768,6 +5993,10 @@ bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode) bool wxWindowMSW::UnregisterHotKey(int hotkeyId) { +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) + WinCEUnregisterHotKey(MOD_WIN, hotkeyId); +#endif + if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) ) { wxLogLastError(_T("UnregisterHotKey")); @@ -5778,6 +6007,8 @@ bool wxWindowMSW::UnregisterHotKey(int hotkeyId) return true; } +#if wxUSE_ACCEL + bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) { int hotkeyId = wParam; @@ -5794,8 +6025,35 @@ bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) return GetEventHandler()->ProcessEvent(event); } +#endif // wxUSE_ACCEL + #endif // wxUSE_HOTKEY +// Moves a window by deferred method or normal method +bool wxMoveWindowDeferred(HDWP& hdwp, wxWindowBase* win, HWND hWnd, int x, int y, int width, int height) +{ + if ( hdwp ) + { + hdwp = ::DeferWindowPos(hdwp, hWnd, NULL, + x, y, width, height, + SWP_NOZORDER); + if ( !hdwp ) + { + wxLogLastError(_T("DeferWindowPos")); + } + } + + // otherwise (or if deferring failed) move the window in place immediately + if ( !hdwp ) + { + if ( !::MoveWindow(hWnd, x, y, width, height, win->IsShown()) ) + { + wxLogLastError(wxT("MoveWindow")); + } + } + return hdwp != NULL; +} + // Not tested under WinCE #ifndef __WXWINCE__ @@ -5807,9 +6065,9 @@ bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) class wxIdleWakeUpModule : public wxModule { public: - virtual bool OnInit() + virtual bool OnInit() { - ms_hMsgHookProc = ::SetWindowsHookEx + ms_hMsgHookProc = ::SetWindowsHookEx ( WH_GETMESSAGE, &wxIdleWakeUpModule::MsgHookProc, @@ -5825,26 +6083,30 @@ public: } return true; - } + } - virtual void OnExit() + virtual void OnExit() { - ::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc); - } + ::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc); + } - static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam) + static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam) { - MSG *msg = (MSG*)lParam; - if ( msg->message == WM_NULL ) - { + MSG *msg = (MSG*)lParam; + + // only process the message if it is actually going to be removed from + // the message queue, this prevents that the same event from being + // processed multiple times if now someone just called PeekMessage() + if ( msg->message == WM_NULL && wParam == PM_REMOVE ) + { wxTheApp->ProcessPendingEvents(); - } + } - return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam); - }; + return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam); + }; private: - static HHOOK ms_hMsgHookProc; + static HHOOK ms_hMsgHookProc; DECLARE_DYNAMIC_CLASS(wxIdleWakeUpModule) }; @@ -5854,4 +6116,37 @@ HHOOK wxIdleWakeUpModule::ms_hMsgHookProc = 0; IMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule, wxModule) #endif // __WXWINCE__ - + +#ifdef __WXWINCE__ + +#if wxUSE_STATBOX +static void wxAdjustZOrder(wxWindow* parent) +{ + if (parent->IsKindOf(CLASSINFO(wxStaticBox))) + { + // Set the z-order correctly + SetWindowPos((HWND) parent->GetHWND(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); + } + + wxWindowList::compatibility_iterator current = parent->GetChildren().GetFirst(); + while (current) + { + wxWindow *childWin = current->GetData(); + wxAdjustZOrder(childWin); + current = current->GetNext(); + } +} +#endif + +// We need to adjust the z-order of static boxes in WinCE, to +// make 'contained' controls visible +void wxWindowMSW::OnInitDialog( wxInitDialogEvent& event ) +{ +#if wxUSE_STATBOX + wxAdjustZOrder(this); +#endif + + event.Skip(); +} +#endif +