X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0f7a546d9cb38a62a5d626b38e67bcc94f12a0fb..8f974c520a8733158591891458fda10fae4c3950:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 628d0b76ec..3d030562ba 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: windows.cpp +// Name: src/msw/windows.cpp // Purpose: wxWindow // Author: Julian Smart // Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation @@ -39,7 +39,6 @@ #include "wx/dcclient.h" #include "wx/utils.h" #include "wx/app.h" - #include "wx/panel.h" #include "wx/layout.h" #include "wx/dialog.h" #include "wx/frame.h" @@ -47,8 +46,7 @@ #include "wx/button.h" #include "wx/msgdlg.h" #include "wx/settings.h" - - #include + #include "wx/statbox.h" #endif #if wxUSE_OWNER_DRAWN @@ -84,7 +82,7 @@ #include -#ifndef __GNUWIN32_OLD__ +#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__)) || defined(__CYGWIN10__) #include #include #endif @@ -93,11 +91,11 @@ #include #endif -#if !defined(__GNUWIN32_OLD__) && !defined(__TWIN32__) +#if (!defined(__GNUWIN32_OLD__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__)) || defined(__CYGWIN10__) #ifdef __WIN95__ #include #endif -#else // broken compiler +#elif !defined(__WXMICROWIN__) // broken compiler #ifndef __TWIN32__ #include "wx/msw/gnuwin32/extra.h" #endif @@ -111,7 +109,11 @@ #if wxUSE_MOUSEWHEEL #ifndef WM_MOUSEWHEEL #define WM_MOUSEWHEEL 0x020A + #endif + #ifndef WHEEL_DELTA #define WHEEL_DELTA 120 + #endif + #ifndef SPI_GETWHEELSCROLLLINES #define SPI_GETWHEELSCROLLLINES 104 #endif #endif @@ -124,8 +126,10 @@ // the last Windows message we got (MT-UNSAFE) extern MSG s_currentMsg; +#if wxUSE_MENUS_NATIVE wxMenu *wxCurrentPopupMenu = NULL; -extern wxList WXDLLEXPORT wxPendingDelete; +#endif // wxUSE_MENUS_NATIVE + extern const wxChar *wxCanvasClassName; // --------------------------------------------------------------------------- @@ -140,29 +144,38 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, const char *wxGetMessageName(int message); #endif //__WXDEBUG__ -void wxRemoveHandleAssociation(wxWindow *win); -void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win); +void wxRemoveHandleAssociation(wxWindowMSW *win); +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(wxWindow *win, int *x, int *y, WPARAM *flags); +static void TranslateKbdEventToMouse(wxWindowMSW *win, + int *x, int *y, WPARAM *flags); // get the text metrics for the current font -static TEXTMETRIC wxGetTextMetrics(const wxWindow *win); +static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win); + +// check if the mouse is in the window or its child +//static bool IsMouseInWindow(HWND hwnd); // --------------------------------------------------------------------------- // event tables // --------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) - -BEGIN_EVENT_TABLE(wxWindow, wxWindowBase) - EVT_ERASE_BACKGROUND(wxWindow::OnEraseBackground) - EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged) - EVT_INIT_DIALOG(wxWindow::OnInitDialog) - EVT_IDLE(wxWindow::OnIdle) - EVT_SET_FOCUS(wxWindow::OnSetFocus) +// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu() +// method +#ifdef __WXUNIVERSAL__ + IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase) +#else // __WXMSW__ + IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) +#endif // __WXUNIVERSAL__/__WXMSW__ + +BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase) + EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground) + EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged) + EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog) + EVT_IDLE(wxWindowMSW::OnIdle) END_EVENT_TABLE() // =========================================================================== @@ -174,18 +187,23 @@ END_EVENT_TABLE() // --------------------------------------------------------------------------- // Find an item given the MS Windows id -wxWindow *wxWindow::FindItem(long id) const +wxWindow *wxWindowMSW::FindItem(long id) const { - wxControl *item = wxDynamicThisCast(this, wxControl); +#if wxUSE_CONTROLS + wxControl *item = wxDynamicCastThis(wxControl); if ( item ) { - // i it we or one of our "internal" children? - if ( item->GetId() == id || - (item->GetSubcontrols().Index(id) != wxNOT_FOUND) ) + // is it we or one of our "internal" children? + if ( item->GetId() == id +#ifndef __WXUNIVERSAL__ + || (item->GetSubcontrols().Index(id) != wxNOT_FOUND) +#endif // __WXUNIVERSAL__ + ) { return item; } } +#endif // wxUSE_CONTROLS wxWindowList::Node *current = GetChildren().GetFirst(); while (current) @@ -203,7 +221,7 @@ wxWindow *wxWindow::FindItem(long id) const } // Find an item given the MS Windows handle -wxWindow *wxWindow::FindItemByHWND(WXHWND hWnd, bool controlOnly) const +wxWindow *wxWindowMSW::FindItemByHWND(WXHWND hWnd, bool controlOnly) const { wxWindowList::Node *current = GetChildren().GetFirst(); while (current) @@ -215,7 +233,11 @@ wxWindow *wxWindow::FindItemByHWND(WXHWND hWnd, bool controlOnly) const if ( wnd ) return wnd; - if ( !controlOnly || parent->IsKindOf(CLASSINFO(wxControl)) ) + if ( !controlOnly +#if wxUSE_CONTROLS + || parent->IsKindOf(CLASSINFO(wxControl)) +#endif // wxUSE_CONTROLS + ) { wxWindow *item = current->GetData(); if ( item->GetHWND() == hWnd ) @@ -233,7 +255,7 @@ wxWindow *wxWindow::FindItemByHWND(WXHWND hWnd, bool controlOnly) const } // Default command handler -bool wxWindow::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id)) +bool wxWindowMSW::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id)) { return FALSE; } @@ -242,14 +264,13 @@ bool wxWindow::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id)) // constructors and such // ---------------------------------------------------------------------------- -void wxWindow::Init() +void wxWindowMSW::Init() { // generic InitBase(); // MSW specific m_doubleClickAllowed = 0; - m_winCaptured = FALSE; m_isBeingDeleted = FALSE; m_oldWndProc = 0; @@ -279,17 +300,32 @@ void wxWindow::Init() } // Destructor -wxWindow::~wxWindow() +wxWindowMSW::~wxWindowMSW() { m_isBeingDeleted = TRUE; MSWDetachWindowMenu(); - if ( m_parent ) - m_parent->RemoveChild(this); + // VS: make sure there's no wxFrame with last focus set to us: + for (wxWindow *win = GetParent(); win; win = win->GetParent()) + { + wxFrame *frame = wxDynamicCast(win, wxFrame); + if ( frame ) + { + if ( frame->GetLastFocus() == this ) + frame->SetLastFocus((wxWindow*)NULL); + break; + } + } + // VS: destroy children first and _then_ detach *this from its parent. + // If we'd do it the other way around, children wouldn't be able + // find their parent frame (see above). DestroyChildren(); + if ( m_parent ) + m_parent->RemoveChild(this); + if ( m_hWnd ) { // VZ: test temp removed to understand what really happens here @@ -305,29 +341,38 @@ wxWindow::~wxWindow() } // real construction (Init() must have been called before!) -bool wxWindow::Create(wxWindow *parent, wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) +bool wxWindowMSW::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) { wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") ); +#if wxUSE_STATBOX + // wxGTK doesn't allow to create controls with static box as the parent so + // this will result in a crash when the program is ported to wxGTK - warn + // about it + // + // the correct solution is to create the controls as siblings of the + // static box + wxASSERT_MSG( !wxDynamicCastThis(wxStaticBox), + _T("wxStaticBox can't be used as a window parent!") ); +#endif // wxUSE_STATBOX + if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) return FALSE; parent->AddChild(this); - DWORD msflags = 0; - if ( style & wxBORDER ) - msflags |= WS_BORDER; -/* Not appropriate for non-frame/dialog windows, and - may clash with other window styles. - if ( style & wxTHICK_FRAME ) - msflags |= WS_THICKFRAME; -*/ - //msflags |= WS_CHILD /* | WS_CLIPSIBLINGS */ | WS_VISIBLE; - msflags |= WS_CHILD | WS_VISIBLE; + // all windows are created visible + DWORD msflags = WS_CHILD | WS_VISIBLE; + +#ifdef __WXUNIVERSAL__ + // no 3d effects, we draw them ourselves + WXDWORD exStyle = 0; +#else // !wxUniversal if ( style & wxCLIP_CHILDREN ) msflags |= WS_CLIPCHILDREN; if ( style & wxCLIP_SIBLINGS ) @@ -338,8 +383,12 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, // Even with extended styles, need to combine with WS_BORDER // for them to look right. - if ( want3D || (m_windowStyle & wxSIMPLE_BORDER) || (m_windowStyle & wxRAISED_BORDER ) || - (m_windowStyle & wxSUNKEN_BORDER) || (m_windowStyle & wxDOUBLE_BORDER)) + if ( want3D || + (m_windowStyle & (wxBORDER | + wxSIMPLE_BORDER | + wxRAISED_BORDER | + wxSUNKEN_BORDER | + wxDOUBLE_BORDER)) ) { msflags |= WS_BORDER; } @@ -351,8 +400,20 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, m_lDlgCode = DLGC_WANTARROWS | DLGC_WANTCHARS | DLGC_WANTTAB | DLGC_WANTMESSAGE; } +#endif // wxUniversal/!wxUniversal + + if ( style & wxPOPUP_WINDOW ) + { + // a popup window floats on top of everything + exStyle |= WS_EX_TOPMOST | WS_EX_TOOLWINDOW; + + // it is also created hidden as other top level windows + msflags &= ~WS_VISIBLE; + m_isShown = FALSE; + } - return MSWCreate(m_windowId, parent, wxCanvasClassName, this, NULL, + return MSWCreate(m_windowId, parent, wxCanvasClassName, + (wxWindow *)this, NULL, pos.x, pos.y, WidthDefault(size.x), HeightDefault(size.y), msflags, NULL, exStyle); @@ -362,11 +423,35 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, // basic operations // --------------------------------------------------------------------------- -void wxWindow::SetFocus() +void wxWindowMSW::SetFocus() { HWND hWnd = GetHwnd(); - if ( hWnd ) - ::SetFocus(hWnd); + wxCHECK_RET( hWnd, _T("can't set focus to invalid window") ); + +#ifndef __WXMICROWIN__ + ::SetLastError(0); +#endif + + if ( !::SetFocus(hWnd) ) + { + // was there really an error? +#ifndef __WXMICROWIN__ + DWORD dwRes = ::GetLastError(); +#else + + DWORD dwRes = 0; +#endif + if ( dwRes ) + { + wxLogApiError(_T("SetFocus"), dwRes); + } + + // VZ: just why does this happen sometimes?? any idea? +#if 0 + HWND hwndFocus = ::GetFocus(); + wxASSERT_MSG( hwndFocus == hWnd, _T("SetFocus() didn't work?") ); +#endif // 0 + } } // Get the window with the focus @@ -375,13 +460,13 @@ wxWindow *wxWindowBase::FindFocus() HWND hWnd = ::GetFocus(); if ( hWnd ) { - return wxFindWinFromHandle((WXHWND) hWnd); + return wxGetWindowFromHWND((WXHWND)hWnd); } return NULL; } -bool wxWindow::Enable(bool enable) +bool wxWindowMSW::Enable(bool enable) { if ( !wxWindowBase::Enable(enable) ) return FALSE; @@ -392,7 +477,7 @@ bool wxWindow::Enable(bool enable) // VZ: no, this is a bad idea: imagine that you have a dialog with some // disabled controls and disable it - you really wouldn't like the - // disabled controls eb reenabled too when you reenable the dialog! + // disabled controls be reenabled too when you reenable the dialog! #if 0 wxWindowList::Node *node = GetChildren().GetFirst(); while ( node ) @@ -407,7 +492,7 @@ bool wxWindow::Enable(bool enable) return TRUE; } -bool wxWindow::Show(bool show) +bool wxWindowMSW::Show(bool show) { if ( !wxWindowBase::Show(show) ) return FALSE; @@ -418,55 +503,86 @@ bool wxWindow::Show(bool show) if ( show ) { +#ifdef __WXMICROWIN__ + // It seems that MicroWindows brings the _parent_ of the + // window to the top, which can be the wrong one. + + // activate (set focus to) specified window + ::SetFocus(hWnd); + + // raise top level parent to top of z order + ::SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, + SWP_NOMOVE|SWP_NOSIZE); +#else BringWindowToTop(hWnd); +#endif } return TRUE; } // Raise the window to the top of the Z order -void wxWindow::Raise() +void wxWindowMSW::Raise() { +#ifdef __WIN16__ ::BringWindowToTop(GetHwnd()); +#else // Win32 +#ifdef __WXMICROWIN__ + // It seems that MicroWindows brings the _parent_ of the + // window to the top, which can be the wrong one. + + // activate (set focus to) specified window + ::SetFocus(GetHwnd()); + + // raise top level parent to top of z order + ::SetWindowPos(GetHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); +#else + ::SetForegroundWindow(GetHwnd()); +#endif +#endif } // Lower the window to the bottom of the Z order -void wxWindow::Lower() +void wxWindowMSW::Lower() { ::SetWindowPos(GetHwnd(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } -void wxWindow::SetTitle( const wxString& title) +void wxWindowMSW::SetTitle( const wxString& title) { SetWindowText(GetHwnd(), title.c_str()); } -wxString wxWindow::GetTitle() const +wxString wxWindowMSW::GetTitle() const { return wxGetWindowText(GetHWND()); } -void wxWindow::CaptureMouse() +void wxWindowMSW::CaptureMouse() { HWND hWnd = GetHwnd(); - if ( hWnd && !m_winCaptured ) + if ( hWnd ) { - SetCapture(hWnd); - m_winCaptured = TRUE; + ::SetCapture(hWnd); } } -void wxWindow::ReleaseMouse() +void wxWindowMSW::ReleaseMouse() { - if ( m_winCaptured ) + if ( !::ReleaseCapture() ) { - ReleaseCapture(); - m_winCaptured = FALSE; + wxLogLastError(_T("ReleaseCapture")); } } -bool wxWindow::SetFont(const wxFont& font) +/* static */ wxWindow *wxWindowBase::GetCapture() +{ + HWND hwnd = ::GetCapture(); + return hwnd ? wxFindWinFromHandle((WXHWND)hwnd) : (wxWindow *)NULL; +} + +bool wxWindowMSW::SetFont(const wxFont& font) { if ( !wxWindowBase::SetFont(font) ) { @@ -486,7 +602,7 @@ bool wxWindow::SetFont(const wxFont& font) return TRUE; } -bool wxWindow::SetCursor(const wxCursor& cursor) +bool wxWindowMSW::SetCursor(const wxCursor& cursor) { if ( !wxWindowBase::SetCursor(cursor) ) { @@ -512,24 +628,18 @@ bool wxWindow::SetCursor(const wxCursor& cursor) return TRUE; } -void wxWindow::WarpPointer (int x_pos, int y_pos) +void wxWindowMSW::WarpPointer (int x, int y) { - // Move the pointer to (x_pos,y_pos) coordinates. They are expressed in - // pixel coordinates, relatives to the canvas -- So, we first need to - // substract origin of the window, then convert to screen position + ClientToScreen(&x, &y); - int x = x_pos; int y = y_pos; - RECT rect; - GetWindowRect (GetHwnd(), &rect); - - x += rect.left; - y += rect.top; - - SetCursorPos (x, y); + if ( !::SetCursorPos(x, y) ) + { + wxLogLastError(_T("SetCursorPos")); + } } #if WXWIN_COMPATIBILITY -void wxWindow::MSWDeviceToLogical (float *x, float *y) const +void wxWindowMSW::MSWDeviceToLogical (float *x, float *y) const { } #endif // WXWIN_COMPATIBILITY @@ -539,7 +649,7 @@ void wxWindow::MSWDeviceToLogical (float *x, float *y) const // --------------------------------------------------------------------------- #if WXWIN_COMPATIBILITY -void wxWindow::SetScrollRange(int orient, int range, bool refresh) +void wxWindowMSW::SetScrollRange(int orient, int range, bool refresh) { #if defined(__WIN95__) @@ -585,7 +695,7 @@ void wxWindow::SetScrollRange(int orient, int range, bool refresh) #endif } -void wxWindow::SetScrollPage(int orient, int page, bool refresh) +void wxWindowMSW::SetScrollPage(int orient, int page, bool refresh) { #if defined(__WIN95__) SCROLLINFO info; @@ -615,7 +725,7 @@ void wxWindow::SetScrollPage(int orient, int page, bool refresh) #endif } -int wxWindow::OldGetScrollRange(int orient) const +int wxWindowMSW::OldGetScrollRange(int orient) const { int wOrient; if ( orient == wxHORIZONTAL ) @@ -647,7 +757,7 @@ int wxWindow::OldGetScrollRange(int orient) const return 0; } -int wxWindow::GetScrollPage(int orient) const +int wxWindowMSW::GetScrollPage(int orient) const { if ( orient == wxHORIZONTAL ) return m_xThumbSize; @@ -657,25 +767,32 @@ int wxWindow::GetScrollPage(int orient) const #endif // WXWIN_COMPATIBILITY -int wxWindow::GetScrollPos(int orient) const +inline int GetScrollPosition(HWND hWnd, int wOrient) +{ +#ifdef __WXMICROWIN__ + return ::GetScrollPosWX(hWnd, wOrient); +#else + return ::GetScrollPos(hWnd, wOrient); +#endif +} + +int wxWindowMSW::GetScrollPos(int orient) const { int wOrient; if ( orient == wxHORIZONTAL ) wOrient = SB_HORZ; else wOrient = SB_VERT; + HWND hWnd = GetHwnd(); - if ( hWnd ) - { - return ::GetScrollPos(hWnd, wOrient); - } - else - return 0; + wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") ); + + return GetScrollPosition(hWnd, wOrient); } // This now returns the whole range, not just the number // of positions that we can scroll. -int wxWindow::GetScrollRange(int orient) const +int wxWindowMSW::GetScrollRange(int orient) const { int wOrient; if ( orient == wxHORIZONTAL ) @@ -710,7 +827,7 @@ int wxWindow::GetScrollRange(int orient) const return 0; } -int wxWindow::GetScrollThumb(int orient) const +int wxWindowMSW::GetScrollThumb(int orient) const { if ( orient == wxHORIZONTAL ) return m_xThumbSize; @@ -718,7 +835,7 @@ int wxWindow::GetScrollThumb(int orient) const return m_yThumbSize; } -void wxWindow::SetScrollPos(int orient, int pos, bool refresh) +void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh) { #if defined(__WIN95__) SCROLLINFO info; @@ -753,7 +870,7 @@ void wxWindow::SetScrollPos(int orient, int pos, bool refresh) } // New function that will replace some of the above. -void wxWindow::SetScrollbar(int orient, int pos, int thumbVisible, +void wxWindowMSW::SetScrollbar(int orient, int pos, int thumbVisible, int range, bool refresh) { #if defined(__WIN95__) @@ -809,28 +926,65 @@ void wxWindow::SetScrollbar(int orient, int pos, int thumbVisible, } } -void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) +void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect) { - RECT rect2; - if ( rect ) + RECT rect; + if ( prect ) { - rect2.left = rect->x; - rect2.top = rect->y; - rect2.right = rect->x + rect->width; - rect2.bottom = rect->y + rect->height; + rect.left = prect->x; + rect.top = prect->y; + rect.right = prect->x + prect->width; + rect.bottom = prect->y + prect->height; } - if ( rect ) - ::ScrollWindow(GetHwnd(), dx, dy, &rect2, NULL); - else - ::ScrollWindow(GetHwnd(), dx, dy, NULL, NULL); + ::ScrollWindow(GetHwnd(), dx, dy, prect ? &rect : NULL, NULL); +} + +static bool ScrollVertically(HWND hwnd, int kind, int count) +{ + int posStart = GetScrollPosition(hwnd, SB_VERT); + + int pos = posStart; + for ( int n = 0; n < count; n++ ) + { + ::SendMessage(hwnd, WM_VSCROLL, kind, 0); + + int posNew = GetScrollPosition(hwnd, SB_VERT); + if ( posNew == pos ) + { + // don't bother to continue, we're already at top/bottom + break; + } + + pos = posNew; + } + + return pos != posStart; +} + +bool wxWindowMSW::ScrollLines(int lines) +{ + bool down = lines > 0; + + return ScrollVertically(GetHwnd(), + down ? SB_LINEDOWN : SB_LINEUP, + down ? lines : -lines); +} + +bool wxWindowMSW::ScrollPages(int pages) +{ + bool down = pages > 0; + + return ScrollVertically(GetHwnd(), + down ? SB_PAGEDOWN : SB_PAGEUP, + down ? pages : -pages); } // --------------------------------------------------------------------------- // subclassing // --------------------------------------------------------------------------- -void wxWindow::SubclassWin(WXHWND hWnd) +void wxWindowMSW::SubclassWin(WXHWND hWnd) { wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") ); @@ -840,10 +994,13 @@ void wxWindow::SubclassWin(WXHWND hWnd) wxAssociateWinWithHandle(hwnd, this); m_oldWndProc = (WXFARPROC) GetWindowLong(hwnd, GWL_WNDPROC); + + wxASSERT( (WXFARPROC) m_oldWndProc != (WXFARPROC) wxWndProc ); + SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc); } -void wxWindow::UnsubclassWin() +void wxWindowMSW::UnsubclassWin() { wxRemoveHandleAssociation(this); @@ -865,7 +1022,7 @@ void wxWindow::UnsubclassWin() } // Make a Windows extended style from the given wxWindows window style -WXDWORD wxWindow::MakeExtendedStyle(long style, bool eliminateBorders) +WXDWORD wxWindowMSW::MakeExtendedStyle(long style, bool eliminateBorders) { WXDWORD exStyle = 0; if ( style & wxTRANSPARENT_WINDOW ) @@ -891,12 +1048,16 @@ WXDWORD wxWindow::MakeExtendedStyle(long style, bool eliminateBorders) // Determines whether native 3D effects or CTL3D should be used, // applying a default border style if required, and returning an extended // style to pass to CreateWindowEx. -WXDWORD wxWindow::Determine3DEffects(WXDWORD defaultBorderStyle, +WXDWORD wxWindowMSW::Determine3DEffects(WXDWORD defaultBorderStyle, bool *want3D) const { // If matches certain criteria, then assume no 3D effects // unless specifically requested (dealt with in MakeExtendedStyle) - if ( !GetParent() || !IsKindOf(CLASSINFO(wxControl)) || (m_windowStyle & wxNO_BORDER) ) + if ( !GetParent() +#if wxUSE_CONTROLS + || !IsKindOf(CLASSINFO(wxControl)) +#endif // wxUSE_CONTROLS + || (m_windowStyle & wxNO_BORDER) ) { *want3D = FALSE; return MakeExtendedStyle(m_windowStyle, FALSE); @@ -951,7 +1112,7 @@ WXDWORD wxWindow::Determine3DEffects(WXDWORD defaultBorderStyle, // If nothing defined for this, try the parent. // E.g. we may be a button loaded from a resource, with no callback function // defined. -void wxWindow::OnCommand(wxWindow& win, wxCommandEvent& event) +void wxWindowMSW::OnCommand(wxWindow& win, wxCommandEvent& event) { if ( GetEventHandler()->ProcessEvent(event) ) return; @@ -961,7 +1122,7 @@ void wxWindow::OnCommand(wxWindow& win, wxCommandEvent& event) #endif // WXWIN_COMPATIBILITY_2 #if WXWIN_COMPATIBILITY -wxObject* wxWindow::GetChild(int number) const +wxObject* wxWindowMSW::GetChild(int number) const { // Return a pointer to the Nth object in the Panel wxNode *node = GetChildren().First(); @@ -979,27 +1140,40 @@ wxObject* wxWindow::GetChild(int number) const #endif // WXWIN_COMPATIBILITY // Setup background and foreground colours correctly -void wxWindow::SetupColours() +void wxWindowMSW::SetupColours() { if ( GetParent() ) SetBackgroundColour(GetParent()->GetBackgroundColour()); } -void wxWindow::OnIdle(wxIdleEvent& WXUNUSED(event)) +bool wxWindowMSW::IsMouseInWindow() const +{ + // get the mouse position + POINT pt; + ::GetCursorPos(&pt); + + // find the window which currently has the cursor and go up the window + // chain until we find this window - or exhaust it + HWND hwnd = ::WindowFromPoint(pt); + while ( hwnd && (hwnd != GetHwnd()) ) + hwnd = ::GetParent(hwnd); + + return hwnd != NULL; +} + +void wxWindowMSW::OnIdle(wxIdleEvent& WXUNUSED(event)) { // Check if we need to send a LEAVE event if ( m_mouseInWindow ) { - POINT pt; - ::GetCursorPos(&pt); - if ( ::WindowFromPoint(pt) != GetHwnd() ) + if ( !IsMouseInWindow() ) { // Generate a LEAVE event m_mouseInWindow = FALSE; - // Unfortunately the mouse button and keyboard state may have changed - // by the time the OnIdle function is called, so 'state' may be - // meaningless. + // Unfortunately the mouse button and keyboard state may have + // changed by the time the OnIdle function is called, so 'state' + // may be meaningless. int state = 0; if ( wxIsShiftDown() ) state |= MK_SHIFT; @@ -1012,10 +1186,26 @@ void wxWindow::OnIdle(wxIdleEvent& WXUNUSED(event)) if ( GetKeyState( VK_RBUTTON ) ) state |= MK_RBUTTON; - wxMouseEvent event(wxEVT_LEAVE_WINDOW); - InitMouseEvent(event, pt.x, pt.y, state); + POINT pt; + if ( !::GetCursorPos(&pt) ) + { + wxLogLastError(_T("GetCursorPos")); + } - (void)GetEventHandler()->ProcessEvent(event); + // we need to have client coordinates here for symmetry with + // wxEVT_ENTER_WINDOW + RECT rect; + if ( !::GetWindowRect(GetHwnd(), &rect) ) + { + wxLogLastError(_T("GetWindowRect")); + } + pt.x -= rect.left; + pt.y -= rect.top; + + wxMouseEvent event2(wxEVT_LEAVE_WINDOW); + InitMouseEvent(event2, pt.x, pt.y, state); + + (void)GetEventHandler()->ProcessEvent(event2); } } @@ -1023,7 +1213,7 @@ void wxWindow::OnIdle(wxIdleEvent& WXUNUSED(event)) } // Set this window to be the child of 'parent'. -bool wxWindow::Reparent(wxWindowBase *parent) +bool wxWindowMSW::Reparent(wxWindowBase *parent) { if ( !wxWindowBase::Reparent(parent) ) return FALSE; @@ -1036,15 +1226,34 @@ bool wxWindow::Reparent(wxWindowBase *parent) return TRUE; } -void wxWindow::Clear() +void wxWindowMSW::Clear() { - wxClientDC dc(this); + wxClientDC dc((wxWindow *)this); wxBrush brush(GetBackgroundColour(), wxSOLID); dc.SetBackground(brush); dc.Clear(); } -void wxWindow::Refresh(bool eraseBack, const wxRect *rect) +static inline void SendSetRedraw(HWND hwnd, bool on) +{ + ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0); +} + +void wxWindowMSW::Freeze() +{ + SendSetRedraw(GetHwnd(), FALSE); +} + +void wxWindowMSW::Thaw() +{ + SendSetRedraw(GetHwnd(), TRUE); + + // we need to refresh everything or otherwise he invalidated area is not + // repainted + Refresh(); +} + +void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect) { HWND hWnd = GetHwnd(); if ( hWnd ) @@ -1064,13 +1273,27 @@ void wxWindow::Refresh(bool eraseBack, const wxRect *rect) } } +void wxWindowMSW::Update() +{ + if ( !::UpdateWindow(GetHwnd()) ) + { + wxLogLastError(_T("UpdateWindow")); + } + +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + // just calling UpdateWindow() is not enough, what we did in our WM_PAINT + // handler needs to be really drawn right now + (void)::GdiFlush(); +#endif // __WIN32__ +} + // --------------------------------------------------------------------------- // drag and drop // --------------------------------------------------------------------------- #if wxUSE_DRAG_AND_DROP -void wxWindow::SetDropTarget(wxDropTarget *pDropTarget) +void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget) { if ( m_dropTarget != 0 ) { m_dropTarget->Revoke(m_hWnd); @@ -1086,7 +1309,7 @@ void wxWindow::SetDropTarget(wxDropTarget *pDropTarget) // old style file-manager drag&drop support: we retain the old-style // DragAcceptFiles in parallel with SetDropTarget. -void wxWindow::DragAcceptFiles(bool accept) +void wxWindowMSW::DragAcceptFiles(bool accept) { HWND hWnd = GetHwnd(); if ( hWnd ) @@ -1099,7 +1322,7 @@ void wxWindow::DragAcceptFiles(bool accept) #if wxUSE_TOOLTIPS -void wxWindow::DoSetToolTip(wxToolTip *tooltip) +void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip) { wxWindowBase::DoSetToolTip(tooltip); @@ -1114,7 +1337,7 @@ void wxWindow::DoSetToolTip(wxToolTip *tooltip) // --------------------------------------------------------------------------- // Get total size -void wxWindow::DoGetSize(int *x, int *y) const +void wxWindowMSW::DoGetSize(int *x, int *y) const { HWND hWnd = GetHwnd(); RECT rect; @@ -1132,7 +1355,7 @@ void wxWindow::DoGetSize(int *x, int *y) const *y = rect.bottom - rect.top; } -void wxWindow::DoGetPosition(int *x, int *y) const +void wxWindowMSW::DoGetPosition(int *x, int *y) const { HWND hWnd = GetHwnd(); @@ -1175,7 +1398,7 @@ void wxWindow::DoGetPosition(int *x, int *y) const *y = point.y; } -void wxWindow::DoScreenToClient(int *x, int *y) const +void wxWindowMSW::DoScreenToClient(int *x, int *y) const { POINT pt; if ( x ) @@ -1192,7 +1415,7 @@ void wxWindow::DoScreenToClient(int *x, int *y) const *y = pt.y; } -void wxWindow::DoClientToScreen(int *x, int *y) const +void wxWindowMSW::DoClientToScreen(int *x, int *y) const { POINT pt; if ( x ) @@ -1210,7 +1433,7 @@ void wxWindow::DoClientToScreen(int *x, int *y) const } // Get size *available for subwindows* i.e. excluding menu bar etc. -void wxWindow::DoGetClientSize(int *x, int *y) const +void wxWindowMSW::DoGetClientSize(int *x, int *y) const { HWND hWnd = GetHwnd(); RECT rect; @@ -1221,7 +1444,7 @@ void wxWindow::DoGetClientSize(int *x, int *y) const *y = rect.bottom; } -void wxWindow::DoMoveWindow(int x, int y, int width, int height) +void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height) { if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) ) { @@ -1237,7 +1460,7 @@ void wxWindow::DoMoveWindow(int x, int y, int width, int height) // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate // the width/height to best suit our contents, otherwise we reuse the current // width/height -void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags) +void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) { // get the current size and position... int currentX, currentY; @@ -1296,7 +1519,7 @@ void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags) DoMoveWindow(x, y, width, height); } -void wxWindow::DoSetClientSize(int width, int height) +void wxWindowMSW::DoSetClientSize(int width, int height) { wxWindow *parent = GetParent(); HWND hWnd = GetHwnd(); @@ -1336,14 +1559,14 @@ void wxWindow::DoSetClientSize(int width, int height) // For implementation purposes - sometimes decorations make the client area // smaller -wxPoint wxWindow::GetClientAreaOrigin() const +wxPoint wxWindowMSW::GetClientAreaOrigin() const { return wxPoint(0, 0); } // Makes an adjustment to the window position (for example, a frame that has // a toolbar that it manages itself). -void wxWindow::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) +void wxWindowMSW::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) { // don't do it for the dialogs/frames - they float independently of their // parent @@ -1353,7 +1576,8 @@ void wxWindow::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent ) { wxPoint pt(parent->GetClientAreaOrigin()); - x += pt.x; y += pt.y; + x += pt.x; + y += pt.y; } } } @@ -1362,23 +1586,23 @@ void wxWindow::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) // text metrics // --------------------------------------------------------------------------- -int wxWindow::GetCharHeight() const +int wxWindowMSW::GetCharHeight() const { return wxGetTextMetrics(this).tmHeight; } -int wxWindow::GetCharWidth() const +int wxWindowMSW::GetCharWidth() const { // +1 is needed because Windows apparently adds it when calculating the // dialog units size in pixels #if wxDIALOG_UNIT_COMPATIBILITY - return wxGetTextMetrics(this).tmAveCharWidth ; + return wxGetTextMetrics(this).tmAveCharWidth; #else return wxGetTextMetrics(this).tmAveCharWidth + 1; #endif } -void wxWindow::GetTextExtent(const wxString& string, +void wxWindowMSW::GetTextExtent(const wxString& string, int *x, int *y, int *descent, int *externalLeading, const wxFont *theFont) const @@ -1424,36 +1648,36 @@ void wxWindow::GetTextExtent(const wxString& string, // Caret manipulation // --------------------------------------------------------------------------- -void wxWindow::CreateCaret(int w, int h) +void wxWindowMSW::CreateCaret(int w, int h) { SetCaret(new wxCaret(this, w, h)); } -void wxWindow::CreateCaret(const wxBitmap *WXUNUSED(bitmap)) +void wxWindowMSW::CreateCaret(const wxBitmap *WXUNUSED(bitmap)) { wxFAIL_MSG("not implemented"); } -void wxWindow::ShowCaret(bool show) +void wxWindowMSW::ShowCaret(bool show) { wxCHECK_RET( m_caret, "no caret to show" ); m_caret->Show(show); } -void wxWindow::DestroyCaret() +void wxWindowMSW::DestroyCaret() { SetCaret(NULL); } -void wxWindow::SetCaretPos(int x, int y) +void wxWindowMSW::SetCaretPos(int x, int y) { wxCHECK_RET( m_caret, "no caret to move" ); m_caret->Move(x, y); } -void wxWindow::GetCaretPos(int *x, int *y) const +void wxWindowMSW::GetCaretPos(int *x, int *y) const { wxCHECK_RET( m_caret, "no caret to get position of" ); @@ -1465,7 +1689,26 @@ void wxWindow::GetCaretPos(int *x, int *y) const // popup menu // --------------------------------------------------------------------------- -bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y) +// yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue +// immediately, without waiting for the next event loop iteration +// +// NB: this function should probably be made public later as it can almost +// surely replace wxYield() elsewhere as well +static void wxYieldForCommandsOnly() +{ + // peek all WM_COMMANDs (it will always return WM_QUIT too but we don't + // want to process it here) + MSG msg; + while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) + && msg.message != WM_QUIT ) + { + wxTheApp->DoMessage((WXMSG *)&msg); + } +} + +#if wxUSE_MENUS_NATIVE + +bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) { menu->SetInvokingWindow(this); menu->UpdateUI(); @@ -1478,7 +1721,16 @@ bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y) ::ClientToScreen(hWnd, &point); wxCurrentPopupMenu = menu; ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL); - wxYieldIfNeeded(); + + // we need to do it righ now as otherwise the events are never going to be + // sent to wxCurrentPopupMenu from HandleCommand() + // + // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't + // help and we'd still need wxYieldForCommandsOnly() as the menu may be + // destroyed as soon as we return (it can be a local variable in the caller + // for example) and so we do need to process the event immediately + wxYieldForCommandsOnly(); + wxCurrentPopupMenu = NULL; menu->SetInvokingWindow(NULL); @@ -1486,11 +1738,13 @@ bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y) return TRUE; } +#endif // wxUSE_MENUS_NATIVE + // =========================================================================== // pre/post message processing // =========================================================================== -long wxWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +long wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { if ( m_oldWndProc ) return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); @@ -1498,8 +1752,10 @@ long wxWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam); } -bool wxWindow::MSWProcessMessage(WXMSG* pMsg) +bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) { + // wxUniversal implements tab traversal itself +#ifndef __WXUNIVERSAL__ if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) ) { // intercept dialog navigation keys @@ -1587,17 +1843,13 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) bProcess = FALSE; } + // FIXME: this should be handled by + // wxNavigationKeyEvent handler and not here!! else { - wxPanel *panel = wxDynamicThisCast(this, wxPanel); - wxButton *btn = NULL; - if ( panel ) - { - // panel may have a default button which should - // be activated by Enter - btn = panel->GetDefaultItem(); - } - +#if wxUSE_BUTTON + wxButton *btn = wxDynamicCast(GetDefaultItem(), + wxButton); if ( btn && btn->IsEnabled() ) { // if we do have a default button, do press it @@ -1605,9 +1857,14 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) return TRUE; } - // else: but if it does not it makes sense to make - // it work like a TAB - and that's what we do. - // Note that Ctrl-Enter always works this way. + else // no default button +#endif // wxUSE_BUTTON + { + // no special function for enter and don't even + // let IsDialogMessage() have it: it seems to + // do something really strange with it + return FALSE; + } } } break; @@ -1625,18 +1882,11 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) if ( GetEventHandler()->ProcessEvent(event) ) { - wxButton *btn = wxDynamicCast(FindFocus(), wxButton); - if ( btn ) - { - // the button which has focus should be default - btn->SetDefault(); - } - return TRUE; } } } -#else +#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 ) @@ -1664,7 +1914,7 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) } } } -#endif // 0 +#endif // 1/0 if ( ::IsDialogMessage(GetHwnd(), msg) ) { @@ -1672,6 +1922,7 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) return TRUE; } } +#endif // __WXUNIVERSAL__ #if wxUSE_TOOLTIPS if ( m_tooltip ) @@ -1686,9 +1937,19 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) return FALSE; } -bool wxWindow::MSWTranslateMessage(WXMSG* pMsg) +bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg) { +#if wxUSE_ACCEL && !defined(__WXUNIVERSAL__) return m_acceleratorTable.Translate(this, pMsg); +#else + return FALSE; +#endif // wxUSE_ACCEL +} + +bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* pMsg) +{ + // preprocess all messages by default + return TRUE; } // --------------------------------------------------------------------------- @@ -1697,7 +1958,7 @@ bool wxWindow::MSWTranslateMessage(WXMSG* pMsg) #ifdef __WIN32__ -void wxWindow::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, +void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, WORD *id, WXHWND *hwnd, WORD *cmd) { *id = LOWORD(wParam); @@ -1705,7 +1966,7 @@ void wxWindow::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, *cmd = HIWORD(wParam); } -void wxWindow::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam, +void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam, WXWORD *state, WXWORD *minimized, WXHWND *hwnd) { *state = LOWORD(wParam); @@ -1713,7 +1974,7 @@ void wxWindow::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam, *hwnd = (WXHWND)lParam; } -void wxWindow::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, +void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, WXWORD *code, WXWORD *pos, WXHWND *hwnd) { *code = LOWORD(wParam); @@ -1721,15 +1982,17 @@ void wxWindow::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, *hwnd = (WXHWND)lParam; } -void wxWindow::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, +void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, WXWORD *nCtlColor, WXHDC *hdc, WXHWND *hwnd) { +#ifndef __WXMICROWIN__ *nCtlColor = CTLCOLOR_BTN; *hwnd = (WXHWND)lParam; *hdc = (WXHDC)wParam; +#endif } -void wxWindow::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, +void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, WXWORD *item, WXWORD *flags, WXHMENU *hmenu) { *item = (WXWORD)wParam; @@ -1739,7 +2002,7 @@ void wxWindow::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, #else // Win16 -void wxWindow::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, +void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, WXWORD *id, WXHWND *hwnd, WXWORD *cmd) { *id = (WXWORD)wParam; @@ -1747,7 +2010,7 @@ void wxWindow::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam, *cmd = HIWORD(lParam); } -void wxWindow::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam, +void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam, WXWORD *state, WXWORD *minimized, WXHWND *hwnd) { *state = (WXWORD)wParam; @@ -1755,7 +2018,7 @@ void wxWindow::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam, *hwnd = (WXHWND)HIWORD(lParam); } -void wxWindow::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, +void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, WXWORD *code, WXWORD *pos, WXHWND *hwnd) { *code = (WXWORD)wParam; @@ -1763,7 +2026,7 @@ void wxWindow::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam, *hwnd = (WXHWND)HIWORD(lParam); } -void wxWindow::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, +void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, WXWORD *nCtlColor, WXHDC *hdc, WXHWND *hwnd) { *hwnd = (WXHWND)LOWORD(lParam); @@ -1771,7 +2034,7 @@ void wxWindow::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam, *hdc = (WXHDC)wParam; } -void wxWindow::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, +void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, WXWORD *item, WXWORD *flags, WXHMENU *hmenu) { *item = (WXWORD)wParam; @@ -1787,7 +2050,7 @@ void wxWindow::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, // Hook for new window just as it's being created, when the window isn't yet // associated with the handle -wxWindow *wxWndHook = NULL; +wxWindowMSW *wxWndHook = NULL; // Main window proc LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -1798,7 +2061,7 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w wxGetMessageName(message), wParam, lParam); #endif // __WXDEBUG__ - wxWindow *wnd = wxFindWinFromHandle((WXHWND) hWnd); + wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd); // when we get the first message for the HWND we just created, we associate // it with wxWindow stored in wxWndHook @@ -1837,7 +2100,7 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w return rc; } -long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) +long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) { // did we process the message? bool processed = FALSE; @@ -1877,8 +2140,38 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) break; case WM_SIZE: - processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam); + 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; + +#ifndef __WXMICROWIN__ + case WM_ACTIVATEAPP: + wxTheApp->SetActive(wParam != 0, FindFocus()); break; +#endif case WM_ACTIVATE: { @@ -1926,12 +2219,6 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) #endif case WM_LBUTTONDOWN: - // set focus to this window - if (AcceptsFocus()) - SetFocus(); - - // fall through - case WM_LBUTTONUP: case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: @@ -1940,12 +2227,70 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDBLCLK: - processed = HandleMouseEvent(message, + { + processed = FALSE; +#ifdef __WXMICROWIN__ + // MicroWindows seems to ignore the fact that a window is + // disabled. So catch mouse events and throw them away if + // necessary. + wxWindowMSW* win = this; + while (win) + { + if (!win->IsEnabled()) + { + processed = TRUE; + break; + } + win = win->GetParent(); + if (win && win->IsTopLevel()) + break; + } +#endif // __WXMICROWIN__ + if (!processed) + { + if (message == WM_LBUTTONDOWN && AcceptsFocus()) + SetFocus(); + processed = HandleMouseEvent(message, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), - wParam); - break; + wParam); + } + break; + } + +#ifdef __WXMICROWIN__ + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCLBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_NCRBUTTONDBLCLK: +#if 0 + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCMBUTTONDBLCLK: +#endif + { + // MicroWindows seems to ignore the fact that a window + // is disabled. So catch mouse events and throw them away if necessary. + processed = FALSE; + wxWindowMSW* win = this; + while (win) + { + if (!win->IsEnabled()) + { + processed = TRUE; + break; + } + win = win->GetParent(); + if (win && win->IsTopLevel()) + break; + } + break; + } +#endif // __WXMICROWIN__ +#ifdef MM_JOY1MOVE case MM_JOY1MOVE: case MM_JOY2MOVE: case MM_JOY1ZMOVE: @@ -1959,6 +2304,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) GET_Y_LPARAM(lParam), wParam); break; +#endif // __WXMICROWIN__ case WM_SYSCOMMAND: processed = HandleSysCommand(wParam, lParam); @@ -1981,6 +2327,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) #endif // Win95 // for these messages we must return TRUE if process the message +#ifdef WM_DRAWITEM case WM_DRAWITEM: case WM_MEASUREITEM: { @@ -2000,6 +2347,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) rc.result = TRUE; } break; +#endif // defined(WM_DRAWITEM) case WM_GETDLGCODE: if ( m_lDlgCode ) @@ -2108,7 +2456,8 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) break; // CTLCOLOR messages are sent by children to query the parent for their - // colors + // colors#ifndef __WXMICROWIN__ +#ifndef __WXMICROWIN__ #ifdef __WIN32__ case WM_CTLCOLORMSGBOX: case WM_CTLCOLOREDIT: @@ -2135,6 +2484,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) lParam); } break; +#endif // !__WXMICROWIN__ // the return value for this message is ignored case WM_SYSCOLORCHANGE: @@ -2197,36 +2547,67 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) rc.result = TRUE; } break; -#ifdef __WIN32__ + +#if defined(__WIN32__) && defined(WM_HELP) case WM_HELP: - { - HELPINFO* info = (HELPINFO*) lParam; - // Don't yet process menu help events, just windows - if (info->iContextType == HELPINFO_WINDOW) { - wxWindow* subjectOfHelp = this; - bool eventProcessed = FALSE; - while (subjectOfHelp && !eventProcessed) + HELPINFO* info = (HELPINFO*) lParam; + // Don't yet process menu help events, just windows + if (info->iContextType == HELPINFO_WINDOW) + { + wxWindowMSW* subjectOfHelp = this; + bool eventProcessed = FALSE; + while (subjectOfHelp && !eventProcessed) + { + wxHelpEvent helpEvent(wxEVT_HELP, + subjectOfHelp->GetId(), + wxPoint(info->MousePos.x, + info->MousePos.y) ); + helpEvent.SetEventObject(this); + eventProcessed = + GetEventHandler()->ProcessEvent(helpEvent); + + // Go up the window hierarchy until the event is + // handled (or not) + subjectOfHelp = subjectOfHelp->GetParent(); + } + + processed = eventProcessed; + } + else if (info->iContextType == HELPINFO_MENUITEM) { - wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), wxPoint(info->MousePos.x, info->MousePos.y) ) ; // info->iCtrlId); + wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId); helpEvent.SetEventObject(this); - eventProcessed = GetEventHandler()->ProcessEvent(helpEvent); + processed = GetEventHandler()->ProcessEvent(helpEvent); - // Go up the window hierarchy until the event is handled (or not) - subjectOfHelp = subjectOfHelp->GetParent(); } - processed = eventProcessed; + //else: processed is already FALSE } - else if (info->iContextType == HELPINFO_MENUITEM) + break; + + case WM_CONTEXTMENU: { - wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId) ; - helpEvent.SetEventObject(this); - processed = GetEventHandler()->ProcessEvent(helpEvent); + // we don't convert from screen to client coordinates as + // the event may be handled by a parent window + wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + + wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); + processed = GetEventHandler()->ProcessEvent(evtCtx); } - else processed = FALSE; break; - } -#endif +#endif // __WIN32__ + +#ifdef __WXUNIVERSAL__ + case WM_NCHITTEST: + // we shouldn't allow the windows which don't want to get focus to + // get it + if ( !AcceptsFocus() ) + { + rc.result = HTTRANSPARENT; + processed = TRUE; + } + break; +#endif // __WXUNIVERSAL__ } if ( !processed ) @@ -2272,7 +2653,7 @@ wxWindow *wxFindWinFromHandle(WXHWND hWnd) static int gs_AssociationCount = 0; #endif -void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win) +void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) { // adding NULL hWnd is (first) surely a result of an error and // (secondly) breaks menu command processing @@ -2297,7 +2678,7 @@ void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win) } } -void wxRemoveHandleAssociation(wxWindow *win) +void wxRemoveHandleAssociation(wxWindowMSW *win) { #if 0 // def __WXDEBUG__ if (wxWinHandleList->Member(win)) @@ -2311,12 +2692,13 @@ void wxRemoveHandleAssociation(wxWindow *win) // Default destroyer - override if you destroy it in some other way // (e.g. with MDI child windows) -void wxWindow::MSWDestroyWindow() +void wxWindowMSW::MSWDestroyWindow() { } -void wxWindow::MSWDetachWindowMenu() +void wxWindowMSW::MSWDetachWindowMenu() { +#ifndef __WXUNIVERSAL__ if ( m_hMenu ) { wxChar buf[1024]; @@ -2343,20 +2725,21 @@ void wxWindow::MSWDetachWindowMenu() } } } +#endif } -bool wxWindow::MSWCreate(int id, - wxWindow *parent, - const wxChar *wclass, - wxWindow *WXUNUSED(wx_win), - const wxChar *title, - int x, - int y, - int width, - int height, - WXDWORD style, - const wxChar *dialog_template, - WXDWORD extendedStyle) +bool wxWindowMSW::MSWCreate(int id, + wxWindow *parent, + const wxChar *wclass, + wxWindow * WXUNUSED(wx_win), + const wxChar *title, + int x, + int y, + int width, + int height, + WXDWORD style, + const wxChar *dialog_template, + WXDWORD extendedStyle) { int x1 = CW_USEDEFAULT; int y1 = 0; @@ -2365,13 +2748,13 @@ bool wxWindow::MSWCreate(int id, // Find parent's size, if it exists, to set up a possible default // panel size the size of the parent window - RECT parent_rect; + RECT rectParent; if ( parent ) { - ::GetClientRect((HWND) parent->GetHWND(), &parent_rect); + ::GetClientRect(GetHwndOf(parent), &rectParent); - width1 = parent_rect.right - parent_rect.left; - height1 = parent_rect.bottom - parent_rect.top; + width1 = rectParent.right - rectParent.left; + height1 = rectParent.bottom - rectParent.top; } if ( x != -1 ) @@ -2397,10 +2780,26 @@ bool wxWindow::MSWCreate(int id, } #endif // 0 - HWND hParent = parent ? GetHwndOf(parent) : NULL; + HWND hParent; + if ( GetWindowStyleFlag() & wxPOPUP_WINDOW ) + { + // popup windows should have desktop as parent because they shouldn't + // be limited to the parents client area as child windows usually are + hParent = ::GetDesktopWindow(); + } + else if ( parent ) + { + hParent = GetHwndOf(parent); + } + else + { + // top level window + hParent = NULL; + } wxWndHook = this; +#ifndef __WXMICROWIN__ if ( dialog_template ) { // for the dialogs without wxDIALOG_NO_PARENT style, use the top level @@ -2474,16 +2873,21 @@ bool wxWindow::MSWCreate(int id, { wxLogLastError(wxT("MoveWindow")); } + } else // creating a normal window, not a dialog +#endif // !__WXMICROWIN__ { int controlId = 0; if ( style & WS_CHILD ) - { + { controlId = id; - // all child windows should clip their siblings - // style |= /* WS_CLIPSIBLINGS */ ; - } + + if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS ) + { + style |= WS_CLIPSIBLINGS; + } + } wxString className(wclass); if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE ) @@ -2541,8 +2945,9 @@ bool wxWindow::MSWCreate(int id, #ifdef __WIN95__ // FIXME: VZ: I'm not sure at all that the order of processing is correct -bool wxWindow::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) +bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) { +#ifndef __WXMICROWIN__ LPNMHDR hdr = (LPNMHDR)lParam; HWND hWnd = hdr->hwndFrom; wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd); @@ -2568,9 +2973,12 @@ bool wxWindow::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) // finally try this window too (catches toolbar case) return MSWOnNotify(idCtrl, lParam, result); +#else // __WXMICROWIN__ + return FALSE; +#endif } -bool wxWindow::MSWOnNotify(int WXUNUSED(idCtrl), +bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl), WXLPARAM lParam, WXLPARAM* WXUNUSED(result)) { @@ -2594,7 +3002,7 @@ bool wxWindow::MSWOnNotify(int WXUNUSED(idCtrl), // end session messages // --------------------------------------------------------------------------- -bool wxWindow::HandleQueryEndSession(long logOff, bool *mayEnd) +bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd) { wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1); event.SetEventObject(wxTheApp); @@ -2613,7 +3021,7 @@ bool wxWindow::HandleQueryEndSession(long logOff, bool *mayEnd) return rc; } -bool wxWindow::HandleEndSession(bool endSession, long logOff) +bool wxWindowMSW::HandleEndSession(bool endSession, long logOff) { // do nothing if the session isn't ending if ( !endSession ) @@ -2634,10 +3042,10 @@ bool wxWindow::HandleEndSession(bool endSession, long logOff) // window creation/destruction // --------------------------------------------------------------------------- -bool wxWindow::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate) +bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate) { // TODO: should generate this event from WM_NCCREATE - wxWindowCreateEvent event(this); + wxWindowCreateEvent event((wxWindow *)this); (void)GetEventHandler()->ProcessEvent(event); *mayCreate = TRUE; @@ -2645,9 +3053,9 @@ bool wxWindow::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate) return TRUE; } -bool wxWindow::HandleDestroy() +bool wxWindowMSW::HandleDestroy() { - wxWindowDestroyEvent event(this); + wxWindowDestroyEvent event((wxWindow *)this); (void)GetEventHandler()->ProcessEvent(event); // delete our drop target if we've got one @@ -2669,34 +3077,7 @@ bool wxWindow::HandleDestroy() // activation/focus // --------------------------------------------------------------------------- -void wxWindow::OnSetFocus(wxFocusEvent& event) -{ - // panel wants to track the window which was the last to have focus in it, - // so we want to set ourselves as the window which last had focus - // - // notice that it's also important to do it upwards the tree becaus - // otherwise when the top level panel gets focus, it won't set it back to - // us, but to some other sibling - wxWindow *win = this; - while ( win ) - { - wxWindow *parent = win->GetParent(); - wxPanel *panel = wxDynamicCast(parent, wxPanel); - if ( panel ) - { - panel->SetLastFocus(win); - } - - win = parent; - } - - wxLogTrace(_T("focus"), _T("%s (0x%08x) gets focus"), - GetClassInfo()->GetClassName(), GetHandle()); - - event.Skip(); -} - -bool wxWindow::HandleActivate(int state, +bool wxWindowMSW::HandleActivate(int state, bool WXUNUSED(minimized), WXHWND WXUNUSED(activate)) { @@ -2708,8 +3089,13 @@ bool wxWindow::HandleActivate(int state, return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleSetFocus(WXHWND WXUNUSED(hwnd)) +bool wxWindowMSW::HandleSetFocus(WXHWND hwnd) { + // notify the parent keeping track of focus for the kbd navigation + // purposes that we got it + wxChildFocusEvent eventFocus(this); + (void)GetEventHandler()->ProcessEvent(eventFocus); + #if wxUSE_CARET // Deal with caret if ( m_caret ) @@ -2718,13 +3104,25 @@ bool wxWindow::HandleSetFocus(WXHWND WXUNUSED(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); } -bool wxWindow::HandleKillFocus(WXHWND WXUNUSED(hwnd)) +bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) { #if wxUSE_CARET // Deal with caret @@ -2734,9 +3132,22 @@ bool wxWindow::HandleKillFocus(WXHWND WXUNUSED(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 + wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId); event.SetEventObject(this); + // wxFindWinFromHandle() may return NULL, it is ok + event.SetWindow(wxFindWinFromHandle(hwnd)); + return GetEventHandler()->ProcessEvent(event); } @@ -2744,7 +3155,7 @@ bool wxWindow::HandleKillFocus(WXHWND WXUNUSED(hwnd)) // miscellaneous // --------------------------------------------------------------------------- -bool wxWindow::HandleShow(bool show, int WXUNUSED(status)) +bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status)) { wxShowEvent event(GetId(), show); event.m_eventObject = this; @@ -2752,7 +3163,7 @@ bool wxWindow::HandleShow(bool show, int WXUNUSED(status)) return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) +bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) { wxInitDialogEvent event(GetId()); event.m_eventObject = this; @@ -2760,8 +3171,9 @@ bool wxWindow::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleDropFiles(WXWPARAM wParam) +bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) { +#ifndef __WXMICROWIN__ HDROP hFilesInfo = (HDROP) wParam; POINT dropPoint; DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint); @@ -2793,12 +3205,16 @@ bool wxWindow::HandleDropFiles(WXWPARAM wParam) delete[] files; return rc; +#else // __WXMICROWIN__ + return FALSE; +#endif } -bool wxWindow::HandleSetCursor(WXHWND WXUNUSED(hWnd), - short nHitTest, - int WXUNUSED(mouseMsg)) +bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), + short nHitTest, + int WXUNUSED(mouseMsg)) { +#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 @@ -2875,6 +3291,7 @@ bool wxWindow::HandleSetCursor(WXHWND WXUNUSED(hWnd), // cursor set, stop here return TRUE; } +#endif // __WXMICROWIN__ // pass up the window chain return FALSE; @@ -2884,9 +3301,11 @@ bool wxWindow::HandleSetCursor(WXHWND WXUNUSED(hWnd), // owner drawn stuff // --------------------------------------------------------------------------- -bool wxWindow::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) +bool wxWindowMSW::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) { #if wxUSE_OWNER_DRAWN + +#if wxUSE_MENUS_NATIVE // is it a menu item? if ( id == 0 ) { @@ -2895,32 +3314,37 @@ bool wxWindow::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); - // prepare to call OnDrawItem() - wxDC dc; - dc.SetHDC((WXHDC)pDrawStruct->hDC, FALSE); + // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent + // the DC from being released + wxDCTemp dc((WXHDC)pDrawStruct->hDC); wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top, pDrawStruct->rcItem.right - pDrawStruct->rcItem.left, pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top); return pMenuItem->OnDrawItem - ( - dc, rect, - (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction, - (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState - ); + ( + dc, + rect, + (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction, + (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState + ); } +#endif // wxUSE_MENUS_NATIVE +#if wxUSE_CONTROLS wxWindow *item = FindItem(id); if ( item && item->IsKindOf(CLASSINFO(wxControl)) ) { return ((wxControl *)item)->MSWOnDraw(itemStruct); } +#endif // wxUSE_CONTROLS + #endif // USE_OWNER_DRAWN return FALSE; } -bool wxWindow::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) +bool wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) { #if wxUSE_OWNER_DRAWN // is it a menu item? @@ -2948,7 +3372,7 @@ bool wxWindow::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) // colours and palettes // --------------------------------------------------------------------------- -bool wxWindow::HandleSysColorChange() +bool wxWindowMSW::HandleSysColorChange() { wxSysColourChangedEvent event; event.SetEventObject(this); @@ -2956,7 +3380,7 @@ bool wxWindow::HandleSysColorChange() return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleCtlColor(WXHBRUSH *brush, +bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor, @@ -2964,37 +3388,43 @@ bool wxWindow::HandleCtlColor(WXHBRUSH *brush, WXWPARAM wParam, WXLPARAM lParam) { +#ifndef __WXMICROWIN__ WXHBRUSH hBrush = 0; if ( nCtlColor == CTLCOLOR_DLG ) { hBrush = OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); } +#if wxUSE_CONTROLS else { wxControl *item = (wxControl *)FindItemByHWND(pWnd, TRUE); if ( item ) hBrush = item->OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam); } +#endif // wxUSE_CONTROLS if ( hBrush ) *brush = hBrush; return hBrush != 0; +#else // __WXMICROWIN__ + return FALSE; +#endif } // Define for each class of dialog and control -WXHBRUSH wxWindow::OnCtlColor(WXHDC WXUNUSED(hDC), - WXHWND WXUNUSED(hWnd), - WXUINT WXUNUSED(nCtlColor), - WXUINT WXUNUSED(message), - WXWPARAM WXUNUSED(wParam), - WXLPARAM WXUNUSED(lParam)) +WXHBRUSH wxWindowMSW::OnCtlColor(WXHDC WXUNUSED(hDC), + WXHWND WXUNUSED(hWnd), + WXUINT WXUNUSED(nCtlColor), + WXUINT WXUNUSED(message), + WXWPARAM WXUNUSED(wParam), + WXLPARAM WXUNUSED(lParam)) { return (WXHBRUSH)0; } -bool wxWindow::HandlePaletteChanged(WXHWND hWndPalChange) +bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange) { wxPaletteChangedEvent event(GetId()); event.SetEventObject(this); @@ -3003,7 +3433,7 @@ bool wxWindow::HandlePaletteChanged(WXHWND hWndPalChange) return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleQueryNewPalette() +bool wxWindowMSW::HandleQueryNewPalette() { wxQueryNewPaletteEvent event(GetId()); event.SetEventObject(this); @@ -3012,7 +3442,7 @@ bool wxWindow::HandleQueryNewPalette() } // Responds to colour changes: passes event on to children. -void wxWindow::OnSysColourChanged(wxSysColourChangedEvent& event) +void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& event) { wxNode *node = GetChildren().First(); while ( node ) @@ -3034,7 +3464,7 @@ void wxWindow::OnSysColourChanged(wxSysColourChangedEvent& event) // painting // --------------------------------------------------------------------------- -bool wxWindow::HandlePaint() +bool wxWindowMSW::HandlePaint() { #ifdef __WIN32__ HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle @@ -3044,41 +3474,54 @@ bool wxWindow::HandlePaint() wxLogLastError(wxT("GetUpdateRgn")); m_updateRegion = wxRegion((WXHRGN) hRegion); -#else +#else // Win16 RECT updateRect; - ::GetUpdateRect(GetHwnd(), & updateRect, FALSE); + ::GetUpdateRect(GetHwnd(), &updateRect, FALSE); m_updateRegion = wxRegion(updateRect.left, updateRect.top, updateRect.right - updateRect.left, updateRect.bottom - updateRect.top); -#endif +#endif // Win32/16 wxPaintEvent event(m_windowId); event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + bool processed = GetEventHandler()->ProcessEvent(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); + + return processed; } // Can be called from an application's OnPaint handler -void wxWindow::OnPaint(wxPaintEvent& event) +void wxWindowMSW::OnPaint(wxPaintEvent& event) { +#ifdef __WXUNIVERSAL__ + event.Skip(); +#else HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject()); if (hDC != 0) { MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0); } +#endif } -bool wxWindow::HandleEraseBkgnd(WXHDC hdc) +bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) { // Prevents flicker when dragging if ( ::IsIconic(GetHwnd()) ) return TRUE; - wxDC dc; + wxDCTemp dc(hdc); dc.SetHDC(hdc); - dc.SetWindow(this); + dc.SetWindow((wxWindow *)this); dc.BeginDrawing(); wxEraseEvent event(m_windowId, &dc); @@ -3086,13 +3529,14 @@ bool wxWindow::HandleEraseBkgnd(WXHDC hdc) bool rc = GetEventHandler()->ProcessEvent(event); dc.EndDrawing(); + + // must be called manually as ~wxDC doesn't do anything for wxDCTemp dc.SelectOldObjects(hdc); - dc.SetHDC((WXHDC) NULL); return rc; } -void wxWindow::OnEraseBackground(wxEraseEvent& event) +void wxWindowMSW::OnEraseBackground(wxEraseEvent& event) { RECT rect; ::GetClientRect(GetHwnd(), &rect); @@ -3117,7 +3561,7 @@ void wxWindow::OnEraseBackground(wxEraseEvent& event) // moving and resizing // --------------------------------------------------------------------------- -bool wxWindow::HandleMinimize() +bool wxWindowMSW::HandleMinimize() { wxIconizeEvent event(m_windowId); event.SetEventObject(this); @@ -3125,7 +3569,7 @@ bool wxWindow::HandleMinimize() return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleMaximize() +bool wxWindowMSW::HandleMaximize() { wxMaximizeEvent event(m_windowId); event.SetEventObject(this); @@ -3133,7 +3577,7 @@ bool wxWindow::HandleMaximize() return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleMove(int x, int y) +bool wxWindowMSW::HandleMove(int x, int y) { wxMoveEvent event(wxPoint(x, y), m_windowId); event.SetEventObject(this); @@ -3141,7 +3585,7 @@ bool wxWindow::HandleMove(int x, int y) return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleSize(int w, int h, WXUINT WXUNUSED(flag)) +bool wxWindowMSW::HandleSize(int w, int h, WXUINT WXUNUSED(flag)) { wxSizeEvent event(wxSize(w, h), m_windowId); event.SetEventObject(this); @@ -3149,7 +3593,7 @@ bool wxWindow::HandleSize(int w, int h, WXUINT WXUNUSED(flag)) return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleGetMinMaxInfo(void *mmInfo) +bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo) { MINMAXINFO *info = (MINMAXINFO *)mmInfo; @@ -3182,31 +3626,13 @@ bool wxWindow::HandleGetMinMaxInfo(void *mmInfo) return rc; } -// generate an artificial resize event -/* FUNCTION IS NOW A MEMBER OF wxFrame - gt -void wxWindow::SendSizeEvent() -{ - RECT r; -#ifdef __WIN16__ - ::GetWindowRect(GetHwnd(), &r); -#else - if ( !::GetWindowRect(GetHwnd(), &r) ) - { - wxLogLastError(_T("GetWindowRect")); - } -#endif - - (void)::PostMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED, - MAKELPARAM(r.right - r.left, r.bottom - r.top)); -} -*/ - // --------------------------------------------------------------------------- // command messages // --------------------------------------------------------------------------- -bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) +bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) { +#if wxUSE_MENUS_NATIVE if ( wxCurrentPopupMenu ) { wxMenu *popupMenu = wxCurrentPopupMenu; @@ -3214,6 +3640,7 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) return popupMenu->MSWCommand(cmd, id); } +#endif // wxUSE_MENUS_NATIVE wxWindow *win = (wxWindow*) NULL; if ( cmd == 0 || cmd == 1 ) // menu or accel - use id @@ -3250,7 +3677,7 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) return GetEventHandler()->ProcessEvent(event); } -#if wxUSE_SPINCTRL +#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__) else { // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND @@ -3265,7 +3692,7 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) return FALSE; } -bool wxWindow::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam)) +bool wxWindowMSW::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam)) { // 4 bits are reserved switch ( wParam & 0xFFFFFFF0 ) @@ -3284,16 +3711,22 @@ bool wxWindow::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam)) // mouse events // --------------------------------------------------------------------------- -void wxWindow::InitMouseEvent(wxMouseEvent& event, int x, int y, WXUINT flags) +void wxWindowMSW::InitMouseEvent(wxMouseEvent& event, + int x, int y, + WXUINT flags) { - event.m_x = x; - event.m_y = y; - event.m_shiftDown = ((flags & MK_SHIFT) != 0); - event.m_controlDown = ((flags & MK_CONTROL) != 0); - event.m_leftDown = ((flags & MK_LBUTTON) != 0); - event.m_middleDown = ((flags & MK_MBUTTON) != 0); - event.m_rightDown = ((flags & MK_RBUTTON) != 0); + // our client coords are not quite the same as Windows ones + wxPoint pt = GetClientAreaOrigin(); + event.m_x = x - pt.x; + event.m_y = y - pt.y; + + event.m_shiftDown = (flags & MK_SHIFT) != 0; + event.m_controlDown = (flags & MK_CONTROL) != 0; + 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; + event.SetTimestamp(s_currentMsg.time); event.m_eventObject = this; @@ -3302,10 +3735,9 @@ void wxWindow::InitMouseEvent(wxMouseEvent& event, int x, int y, WXUINT flags) m_lastMouseY = y; m_lastMouseEvent = event.GetEventType(); #endif // wxUSE_MOUSEEVENT_HACK - } -bool wxWindow::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags) +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 @@ -3331,17 +3763,24 @@ bool wxWindow::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags) return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags) +bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags) { if ( !m_mouseInWindow ) { - // Generate an ENTER event - m_mouseInWindow = TRUE; + // it would be wrong to assume that just because we get a mouse move + // event that the mouse is inside the window: although this is usually + // true, it is not if we had captured the mouse, so we need to check + // the mouse coordinates here + if ( !HasCapture() || IsMouseInWindow() ) + { + // Generate an ENTER event + m_mouseInWindow = TRUE; - wxMouseEvent event(wxEVT_ENTER_WINDOW); - InitMouseEvent(event, x, y, flags); + wxMouseEvent event(wxEVT_ENTER_WINDOW); + InitMouseEvent(event, x, y, flags); - (void)GetEventHandler()->ProcessEvent(event); + (void)GetEventHandler()->ProcessEvent(event); + } } #if wxUSE_MOUSEEVENT_HACK @@ -3351,7 +3790,7 @@ bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags) if ( (m_lastMouseEvent == wxEVT_RIGHT_DOWN || m_lastMouseEvent == wxEVT_LEFT_DOWN || m_lastMouseEvent == wxEVT_MIDDLE_DOWN) && - (m_lastMouseX == event.m_x && m_lastMouseY == event.m_y) ) + (m_lastMouseX == x && m_lastMouseY == y) ) { m_lastMouseEvent = wxEVT_MOTION; @@ -3363,7 +3802,7 @@ bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags) } -bool wxWindow::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) +bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) { #if wxUSE_MOUSEWHEEL wxMouseEvent event(wxEVT_MOUSEWHEEL); @@ -3397,6 +3836,9 @@ bool wxWindow::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) return GetEventHandler()->ProcessEvent(event); #else + (void) wParam; + (void) lParam; + return FALSE; #endif } @@ -3408,7 +3850,7 @@ bool wxWindow::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) // create the key event of the given type for the given key - used by // HandleChar and HandleKeyDown/Up -wxKeyEvent wxWindow::CreateKeyEvent(wxEventType evType, +wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType, int id, WXLPARAM lParam) const { @@ -3438,7 +3880,7 @@ wxKeyEvent wxWindow::CreateKeyEvent(wxEventType evType, // isASCII is TRUE only when we're called from WM_CHAR handler and not from // WM_KEYDOWN one -bool wxWindow::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) +bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) { bool ctrlDown = FALSE; @@ -3491,7 +3933,7 @@ bool wxWindow::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) return FALSE; } -bool wxWindow::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam) +bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam) { int id = wxCharCodeMSWToWX(wParam); @@ -3513,7 +3955,7 @@ bool wxWindow::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam) return FALSE; } -bool wxWindow::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam) +bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam) { int id = wxCharCodeMSWToWX(wParam); @@ -3537,8 +3979,9 @@ bool wxWindow::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam) // joystick // --------------------------------------------------------------------------- -bool wxWindow::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) +bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) { +#ifdef JOY_BUTTON1 int change = 0; if ( flags & JOY_BUTTON1CHG ) change = wxJOY_BUTTON1; @@ -3615,13 +4058,16 @@ bool wxWindow::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) event.SetEventObject(this); return GetEventHandler()->ProcessEvent(event); +#else + return FALSE; +#endif } // --------------------------------------------------------------------------- // scrolling // --------------------------------------------------------------------------- -bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam, +bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, WXWORD pos, WXHWND control) { if ( control ) @@ -3776,14 +4222,11 @@ int wxCharCodeMSWToWX(int keySym) case VK_NUMPAD7: id = WXK_NUMPAD7; break; case VK_NUMPAD8: id = WXK_NUMPAD8; break; case VK_NUMPAD9: id = WXK_NUMPAD9; break; - case VK_MULTIPLY: id = WXK_MULTIPLY; break; - case 0xBB: // VK_OEM_PLUS - case VK_ADD: id = WXK_ADD; break; - case 0xBD: // VK_OEM_MINUS - case VK_SUBTRACT: id = WXK_SUBTRACT; break; - case 0xBE: // VK_OEM_PERIOD - case VK_DECIMAL: id = WXK_DECIMAL; break; - case VK_DIVIDE: id = WXK_DIVIDE; break; + case VK_MULTIPLY: id = WXK_NUMPAD_MULTIPLY; break; + case VK_ADD: id = WXK_NUMPAD_ADD; break; + case VK_SUBTRACT: id = WXK_NUMPAD_SUBTRACT; break; + case VK_DECIMAL: id = WXK_NUMPAD_DECIMAL; break; + case VK_DIVIDE: id = WXK_NUMPAD_DIVIDE; break; case VK_F1: id = WXK_F1; break; case VK_F2: id = WXK_F2; break; case VK_F3: id = WXK_F3; break; @@ -3853,11 +4296,11 @@ int wxCharCodeWXToMSW(int id, bool *isVirtual) case WXK_NUMPAD7: keySym = VK_NUMPAD7; break; case WXK_NUMPAD8: keySym = VK_NUMPAD8; break; case WXK_NUMPAD9: keySym = VK_NUMPAD9; break; - case WXK_MULTIPLY: keySym = VK_MULTIPLY; break; - case WXK_ADD: keySym = VK_ADD; break; - case WXK_SUBTRACT: keySym = VK_SUBTRACT; break; - case WXK_DECIMAL: keySym = VK_DECIMAL; break; - case WXK_DIVIDE: keySym = VK_DIVIDE; break; + case WXK_NUMPAD_MULTIPLY: keySym = VK_MULTIPLY; break; + case WXK_NUMPAD_ADD: keySym = VK_ADD; break; + case WXK_NUMPAD_SUBTRACT: keySym = VK_SUBTRACT; break; + case WXK_NUMPAD_DECIMAL: keySym = VK_DECIMAL; break; + case WXK_NUMPAD_DIVIDE: keySym = VK_DIVIDE; break; case WXK_F1: keySym = VK_F1; break; case WXK_F2: keySym = VK_F2; break; case WXK_F3: keySym = VK_F3; break; @@ -3917,35 +4360,58 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) win = wxFindWinFromHandle((WXHWND)hwnd); if ( !win ) { - // the radiobox pointer is stored in GWL_USERDATA only under Win32 + // all these hacks only work under Win32 anyhow #ifdef __WIN32__ + +#if wxUSE_RADIOBOX // native radiobuttons return DLGC_RADIOBUTTON here and for any // wxWindow class which overrides WM_GETDLGCODE processing to // do it as well, win would be already non NULL - if ( ::SendMessage((HWND)hwnd, WM_GETDLGCODE, - 0, 0) & DLGC_RADIOBUTTON ) + if ( ::SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON ) { win = (wxWindow *)::GetWindowLong(hwnd, GWL_USERDATA); } - else -#endif // Win32 + //else: it's a wxRadioButton, not a radiobutton from wxRadioBox +#endif // wxUSE_RADIOBOX + + // spin control text buddy window should be mapped to spin ctrl + // itself so try it too +#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__) + if ( !win ) { - // hwnd is not a wxWindow, try its parent next below - hwnd = ::GetParent(hwnd); + win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd); } +#endif // wxUSE_SPINCTRL + +#endif // Win32 } - //else: it's a wxRadioButton, not a radiobutton from wxRadioBox } while ( hwnd && !win ) { - win = wxFindWinFromHandle((WXHWND)hwnd); + // this is a really ugly hack needed to avoid mistakenly returning the + // parent frame wxWindow for the find/replace modeless dialog HWND - + // this, in turn, is needed to call IsDialogMessage() from + // wxApp::ProcessMessage() as for this we must return NULL from here + // + // FIXME: this is clearly not the best way to do it but I think we'll + // need to change HWND <-> wxWindow code more heavily than I can + // do it now to fix it + if ( ::GetWindow(hwnd, GW_OWNER) ) + { + // it's a dialog box, don't go upwards + break; + } + hwnd = ::GetParent(hwnd); + win = wxFindWinFromHandle((WXHWND)hwnd); } return win; } +#ifndef __WXMICROWIN__ + // 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; @@ -3971,8 +4437,9 @@ void wxSetKeyboardHook(bool doIt) else { UnhookWindowsHookEx(wxTheKeyboardHook); - // avoids warning about statement with no effect (FreeProcInstance - // doesn't do anything under Win32) + + // avoids warning about statement with no effect (FreeProcInstance + // doesn't do anything under Win32) #if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(__NT__) && !defined(__GNUWIN32__) FreeProcInstance(wxTheKeyboardHookProc); #endif @@ -4022,6 +4489,8 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam); } +#endif // !__WXMICROWIN__ + #ifdef __WXDEBUG__ const char *wxGetMessageName(int message) { @@ -4442,7 +4911,8 @@ const char *wxGetMessageName(int message) } #endif //__WXDEBUG__ -static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags) +static void TranslateKbdEventToMouse(wxWindowMSW *win, + int *x, int *y, WPARAM *flags) { // construct the key mask WPARAM& fwKeys = *flags; @@ -4461,7 +4931,7 @@ static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flag win->ScreenToClient(x, y); } -static TEXTMETRIC wxGetTextMetrics(const wxWindow *win) +static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win) { // prepare the DC TEXTMETRIC tm;