X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/57c0af52bffc66b12b7e7b49b3a2dfdcf2d2e352..cf31a1d7b60feddf23cc30259c6d909d4736ca56:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 9e27c1d6aa..5f4c38e7fe 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 @@ -31,6 +31,7 @@ #ifndef WX_PRECOMP #include #include "wx/msw/winundef.h" + #include "wx/window.h" #include "wx/accel.h" #include "wx/setup.h" #include "wx/menu.h" @@ -38,24 +39,22 @@ #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" #include "wx/listbox.h" #include "wx/button.h" #include "wx/msgdlg.h" - - #include + #include "wx/settings.h" + #include "wx/statbox.h" #endif -#if wxUSE_OWNER_DRAWN +#if wxUSE_OWNER_DRAWN #include "wx/ownerdrw.h" #endif -#if wxUSE_DRAG_AND_DROP - #include "wx/dataobj.h" - #include "wx/msw/ole/droptgt.h" +#if wxUSE_DRAG_AND_DROP + #include "wx/dnd.h" #endif #include "wx/menuitem.h" @@ -71,15 +70,19 @@ #include "wx/caret.h" #endif // wxUSE_CARET +#if wxUSE_SPINCTRL + #include "wx/spinctrl.h" +#endif // wxUSE_SPINCTRL + #include "wx/intl.h" #include "wx/log.h" - #include "wx/textctrl.h" +#include "wx/notebook.h" #include -#ifndef __GNUWIN32__ +#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__)) || defined(__CYGWIN10__) #include #include #endif @@ -88,25 +91,32 @@ #include #endif -#if ( defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__ ) - #include -#endif - -#ifndef __TWIN32__ - #ifdef __GNUWIN32__ - #include +#if (!defined(__GNUWIN32_OLD__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__)) || defined(__CYGWIN10__) + #ifdef __WIN95__ + #include + #endif +#elif !defined(__WXMICROWIN__) // broken compiler + #ifndef __TWIN32__ + #include "wx/msw/gnuwin32/extra.h" #endif #endif -// --------------------------------------------------------------------------- -// macros -// --------------------------------------------------------------------------- +// This didn't appear in mingw until 2.95.2 +#ifndef SIF_TRACKPOS +#define SIF_TRACKPOS 16 +#endif -// standard macros missing from some compilers headers -#ifndef GET_X_LPARAM - #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) - #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) -#endif // GET_X_LPARAM +#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 // --------------------------------------------------------------------------- // global variables @@ -115,39 +125,73 @@ // the last Windows message we got (MT-UNSAFE) extern MSG s_currentMsg; +#if wxUSE_MENUS_NATIVE wxMenu *wxCurrentPopupMenu = NULL; -extern wxList WXDLLEXPORT wxPendingDelete; -extern wxChar wxCanvasClassName[]; +#endif // wxUSE_MENUS_NATIVE + +extern const wxChar *wxCanvasClassName; // --------------------------------------------------------------------------- // private functions // --------------------------------------------------------------------------- // the window proc for all our windows -LRESULT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #ifdef __WXDEBUG__ 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(wxWindowMSW *win, + int *x, int *y, WPARAM *flags); + +// get the text metrics for the current font +static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win); + +// wrapper around BringWindowToTop() API +static inline void wxBringWindowToTop(HWND hwnd) +{ +#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 // !__WXMICROWIN__ + if ( !::BringWindowToTop(hwnd) ) + { + wxLogLastError(_T("BringWindowToTop")); + } +#endif // __WXMICROWIN__/!__WXMICROWIN__ +} + // --------------------------------------------------------------------------- // event tables // --------------------------------------------------------------------------- -#if !USE_SHARED_LIBRARY +// 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 +#endif // __WXUNIVERSAL__/__WXMSW__ -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) +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() // =========================================================================== @@ -159,8 +203,24 @@ END_EVENT_TABLE() // --------------------------------------------------------------------------- // Find an item given the MS Windows id -wxWindow *wxWindow::FindItem(int id) const +wxWindow *wxWindowMSW::FindItem(long id) const { +#if wxUSE_CONTROLS + wxControl *item = wxDynamicCastThis(wxControl); + if ( item ) + { + // 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) { @@ -170,19 +230,6 @@ wxWindow *wxWindow::FindItem(int id) const if ( wnd ) return wnd; - if ( childWin->IsKindOf(CLASSINFO(wxControl)) ) - { - wxControl *item = (wxControl *)childWin; - if ( item->GetId() == id ) - return item; - else - { - // In case it's a 'virtual' control (e.g. radiobox) - if ( item->GetSubcontrols().Member((wxObject *)id) ) - return item; - } - } - current = current->GetNext(); } @@ -190,7 +237,7 @@ wxWindow *wxWindow::FindItem(int 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) @@ -202,7 +249,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 ) @@ -220,7 +271,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; } @@ -229,14 +280,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; @@ -266,58 +316,99 @@ void wxWindow::Init() } // Destructor -wxWindow::~wxWindow() +wxWindowMSW::~wxWindowMSW() { m_isBeingDeleted = TRUE; MSWDetachWindowMenu(); - if ( m_parent ) - m_parent->RemoveChild(this); +#ifndef __WXUNIVERSAL__ + // 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; + } + } +#endif // __WXUNIVERSAL__ + // 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 ) { - if ( !::DestroyWindow(GetHwnd()) ) - wxLogLastError("DestroyWindow"); - } + // VZ: test temp removed to understand what really happens here + //if (::IsWindow(GetHwnd())) + { + if ( !::DestroyWindow(GetHwnd()) ) + wxLogLastError(wxT("DestroyWindow")); + } - // Restore old Window proc, if required and remove hWnd <-> wxWindow - // association - UnsubclassWin(); + // remove hWnd <-> wxWindow association + wxRemoveHandleAssociation(this); + } } // 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) -{ - wxCHECK_MSG( parent, FALSE, _T("can't create wxWindow without parent") ); - - CreateBase(parent, id, pos, size, style, 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( !wxDynamicCast(parent, 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; - if ( style & wxTHICK_FRAME ) - msflags |= WS_THICKFRAME; + // all windows are created visible + DWORD msflags = WS_CHILD | WS_VISIBLE; - 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 ) + msflags |= WS_CLIPSIBLINGS; bool want3D; WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D); // 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; } @@ -328,26 +419,50 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, // want everything: i.e. all keys and WM_CHAR message m_lDlgCode = DLGC_WANTARROWS | DLGC_WANTCHARS | DLGC_WANTTAB | DLGC_WANTMESSAGE; - } +#endif // wxUniversal/!wxUniversal - MSWCreate(m_windowId, parent, wxCanvasClassName, this, NULL, - pos.x, pos.y, - WidthDefault(size.x), HeightDefault(size.y), - msflags, NULL, exStyle); + if ( style & wxPOPUP_WINDOW ) + { + // a popup window floats on top of everything + exStyle |= WS_EX_TOPMOST | WS_EX_TOOLWINDOW; - return TRUE; + // it is also created hidden as other top level windows + msflags &= ~WS_VISIBLE; + m_isShown = FALSE; + } + + return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exStyle); } // --------------------------------------------------------------------------- // 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) ) + { +#if defined(__WXDEBUG__) && !defined(__WXMICROWIN__) + // was there really an error? + DWORD dwRes = ::GetLastError(); + if ( dwRes ) + { + HWND hwndFocus = ::GetFocus(); + if ( hwndFocus != hWnd ) + { + wxLogApiError(_T("SetFocus"), dwRes); + } + } +#endif // Debug + } } // Get the window with the focus @@ -356,13 +471,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; @@ -371,10 +486,24 @@ bool wxWindow::Enable(bool enable) if ( hWnd ) ::EnableWindow(hWnd, (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 be reenabled too when you reenable the dialog! +#if 0 + wxWindowList::Node *node = GetChildren().GetFirst(); + while ( node ) + { + wxWindow *child = node->GetData(); + child->Enable(enable); + + node = node->GetNext(); + } +#endif // 0 + return TRUE; } -bool wxWindow::Show(bool show) +bool wxWindowMSW::Show(bool show) { if ( !wxWindowBase::Show(show) ) return FALSE; @@ -385,55 +514,59 @@ bool wxWindow::Show(bool show) if ( show ) { - BringWindowToTop(hWnd); + wxBringWindowToTop(hWnd); } return TRUE; } // Raise the window to the top of the Z order -void wxWindow::Raise() +void wxWindowMSW::Raise() { - ::BringWindowToTop(GetHwnd()); + wxBringWindowToTop(GetHwnd()); } // 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) ) { @@ -446,14 +579,14 @@ bool wxWindow::SetFont(const wxFont& font) { WXHANDLE hFont = m_font.GetResourceHandle(); - wxASSERT_MSG( hFont, _T("should have valid font") ); + wxASSERT_MSG( hFont, wxT("should have valid font") ); - ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, TRUE); + ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); } return TRUE; } -bool wxWindow::SetCursor(const wxCursor& cursor) +bool wxWindowMSW::SetCursor(const wxCursor& cursor) { if ( !wxWindowBase::SetCursor(cursor) ) { @@ -461,42 +594,35 @@ bool wxWindow::SetCursor(const wxCursor& cursor) return FALSE; } - wxASSERT_MSG( m_cursor.Ok(), - _T("cursor must be valid after call to the base version")); - - HWND hWnd = GetHwnd(); + if ( m_cursor.Ok() ) + { + HWND hWnd = GetHwnd(); - // Change the cursor NOW if we're within the correct window - POINT point; - ::GetCursorPos(&point); + // Change the cursor NOW if we're within the correct window + POINT point; + ::GetCursorPos(&point); - RECT rect; - ::GetWindowRect(hWnd, &rect); + RECT rect = wxGetWindowRect(hWnd); - if ( ::PtInRect(&rect, point) && !wxIsBusy() ) - ::SetCursor((HCURSOR)m_cursor.GetHCURSOR()); + if ( ::PtInRect(&rect, point) && !wxIsBusy() ) + ::SetCursor(GetHcursorOf(m_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 @@ -506,7 +632,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__) @@ -552,7 +678,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; @@ -582,7 +708,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 ) @@ -614,7 +740,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; @@ -624,25 +750,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 ) @@ -677,7 +810,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; @@ -685,42 +818,29 @@ 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; - int dir; + HWND hWnd = GetHwnd(); + wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") ); - if ( orient == wxHORIZONTAL ) { - dir = SB_HORZ; - } else { - dir = SB_VERT; - } + int dir = orient == wxHORIZONTAL ? SB_HORZ : SB_VERT; +#if defined(__WIN95__) + SCROLLINFO info; info.cbSize = sizeof(SCROLLINFO); info.nPage = 0; info.nMin = 0; info.nPos = pos; info.fMask = SIF_POS; - HWND hWnd = GetHwnd(); - if ( hWnd ) - ::SetScrollInfo(hWnd, dir, &info, refresh); -#else - int wOrient; - if ( orient == wxHORIZONTAL ) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; - - HWND hWnd = GetHwnd(); - if ( hWnd ) - ::SetScrollPos(hWnd, wOrient, pos, refresh); -#endif + ::SetScrollInfo(hWnd, dir, &info, refresh); +#else // !__WIN95__ + ::SetScrollPos(hWnd, dir, pos, refresh); +#endif // __WIN95__/!__WIN95__ } // 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__) @@ -776,57 +896,143 @@ 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, _T("subclassing window twice?") ); + wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") ); + + HWND hwnd = (HWND)hWnd; + wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") ); - wxAssociateWinWithHandle((HWND)hWnd, this); + wxAssociateWinWithHandle(hwnd, this); - m_oldWndProc = (WXFARPROC) GetWindowLong((HWND) hWnd, GWL_WNDPROC); - SetWindowLong((HWND) hWnd, GWL_WNDPROC, (LONG) wxWndProc); + m_oldWndProc = (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC); + + // we don't need to subclass the window of our own class (in the Windows + // sense of the word) + if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) ) + { + ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc); + } + else + { + // don't bother restoring it neither + m_oldWndProc = NULL; + } } -void wxWindow::UnsubclassWin() +void wxWindowMSW::UnsubclassWin() { wxRemoveHandleAssociation(this); // Restore old Window proc - if ( GetHwnd() ) + HWND hwnd = GetHwnd(); + if ( hwnd ) { - FARPROC farProc = (FARPROC) GetWindowLong(GetHwnd(), GWL_WNDPROC); - if ( (m_oldWndProc != 0) && (farProc != (FARPROC) m_oldWndProc) ) + m_hWnd = 0; + + wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") ); + + if ( m_oldWndProc ) { - SetWindowLong(GetHwnd(), GWL_WNDPROC, (LONG) m_oldWndProc); - m_oldWndProc = 0; - } + if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) ) + { + ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc); + } - m_hWnd = 0; + m_oldWndProc = NULL; + } } } +bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC wndProc) +{ +#if wxUSE_UNICODE_MSLU + // VS: We can't use GetWindowLong(hwnd, GWL_WNDPROC) together with unicows.dll + // because it doesn't return pointer to the real wnd proc but rather a handle + // of a fake proc that does Unicode<->ANSI translation. + // + // The hack bellow works, because WNDCLASS contains original window handler + // rather that the unicows fake one. This may not be on purpose, though; if + // it stops working with future versions of unicows.dll, we can override + // unicows hooks by setting Unicows_{Set,Get}WindowLong and + // Unicows_RegisterClass to our own versions that keep track of + // fake<->real wnd proc mapping. + // + // FIXME: Doesn't handle wnd procs set by SetWindowLong, only these set + // with RegisterClass!! + + static wxChar buffer[512]; + WNDCLASS cls; + + ::GetClassName((HWND)hWnd, buffer, 512); + ::GetClassInfo(wxGetInstance(), buffer, &cls); + return wndProc == (WXFARPROC)cls.lpfnWndProc; +#else + return wndProc == (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC); +#endif +} + + // 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 ) @@ -840,25 +1046,32 @@ WXDWORD wxWindow::MakeExtendedStyle(long style, bool eliminateBorders) exStyle |= WS_EX_DLGMODALFRAME; #if defined(__WIN95__) if ( style & wxRAISED_BORDER ) - exStyle |= WS_EX_WINDOWEDGE; + // It seems that WS_EX_WINDOWEDGE doesn't work, but WS_EX_DLGMODALFRAME does + exStyle |= WS_EX_DLGMODALFRAME; /* WS_EX_WINDOWEDGE */; if ( style & wxSTATIC_BORDER ) exStyle |= WS_EX_STATICEDGE; #endif } + return exStyle; } // 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, bool *want3D) +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); + return MakeExtendedStyle(m_windowStyle); } // Determine whether we should be using 3D effects or not. @@ -910,7 +1123,7 @@ WXDWORD wxWindow::Determine3DEffects(WXDWORD defaultBorderStyle, bool *want3D) // 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; @@ -920,7 +1133,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(); @@ -938,37 +1151,68 @@ 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& 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 ( ::GetKeyState(VK_SHIFT) != 0 ) + if ( wxIsShiftDown() ) state |= MK_SHIFT; - if ( ::GetKeyState(VK_CONTROL) != 0 ) + 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")); + } - wxMouseEvent event(wxEVT_LEAVE_WINDOW); - InitMouseEvent(event, pt.x, pt.y, state); + // 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; - (void)GetEventHandler()->ProcessEvent(event); + wxMouseEvent event2(wxEVT_LEAVE_WINDOW); + InitMouseEvent(event2, pt.x, pt.y, state); + + (void)GetEventHandler()->ProcessEvent(event2); } } @@ -976,7 +1220,7 @@ void wxWindow::OnIdle(wxIdleEvent& event) } // Set this window to be the child of 'parent'. -bool wxWindow::Reparent(wxWindow *parent) +bool wxWindowMSW::Reparent(wxWindowBase *parent) { if ( !wxWindowBase::Reparent(parent) ) return FALSE; @@ -989,15 +1233,36 @@ bool wxWindow::Reparent(wxWindow *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) +{ +#ifndef __WXMICROWIN__ + ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0); +#endif +} + +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 ) @@ -1017,13 +1282,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); @@ -1039,7 +1318,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 ) @@ -1052,7 +1331,7 @@ void wxWindow::DragAcceptFiles(bool accept) #if wxUSE_TOOLTIPS -void wxWindow::DoSetToolTip(wxToolTip *tooltip) +void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip) { wxWindowBase::DoSetToolTip(tooltip); @@ -1067,11 +1346,9 @@ 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; - GetWindowRect(hWnd, &rect); + RECT rect = wxGetWindowRect(GetHwnd()); if ( x ) *x = rect.right - rect.left; @@ -1079,33 +1356,49 @@ void wxWindow::DoGetSize(int *x, int *y) const *y = rect.bottom - rect.top; } -void wxWindow::DoGetPosition(int *x, int *y) const +// Get size *available for subwindows* i.e. excluding menu bar etc. +void wxWindowMSW::DoGetClientSize(int *x, int *y) const { - HWND hWnd = GetHwnd(); - HWND hParentWnd = 0; - if ( GetParent() ) - hParentWnd = (HWND) GetParent()->GetHWND(); + RECT rect = wxGetClientRect(GetHwnd()); - RECT rect; - GetWindowRect(hWnd, &rect); + if ( x ) + *x = rect.right; + if ( y ) + *y = rect.bottom; +} + +void wxWindowMSW::DoGetPosition(int *x, int *y) const +{ + RECT rect = wxGetWindowRect(GetHwnd()); - // Since we now have the absolute screen coords, if there's a parent we - // must subtract its top left corner POINT point; point.x = rect.left; point.y = rect.top; - if ( hParentWnd ) - { - ::ScreenToClient(hParentWnd, &point); - } - // We may be faking the client origin. So a window that's really at (0, - // 30) may appear (to wxWin apps) to be at (0, 0). - if ( GetParent() ) + // we do the adjustments with respect to the parent only for the "real" + // children, not for the dialogs/frames + if ( !IsTopLevel() ) { - wxPoint pt(GetParent()->GetClientAreaOrigin()); - point.x -= pt.x; - point.y -= pt.y; + HWND hParentWnd = 0; + wxWindow *parent = GetParent(); + if ( parent ) + hParentWnd = GetWinHwnd(parent); + + // Since we now have the absolute screen coords, if there's a parent we + // must subtract its top left corner + if ( hParentWnd ) + { + ::ScreenToClient(hParentWnd, &point); + } + + if ( parent ) + { + // We may be faking the client origin. So a window that's really at (0, + // 30) may appear (to wxWin apps) to be at (0, 0). + wxPoint pt(parent->GetClientAreaOrigin()); + point.x -= pt.x; + point.y -= pt.y; + } } if ( x ) @@ -1114,7 +1407,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 ) @@ -1122,8 +1415,7 @@ void wxWindow::DoScreenToClient(int *x, int *y) const if ( y ) pt.y = *y; - HWND hWnd = GetHwnd(); - ::ScreenToClient(hWnd, &pt); + ::ScreenToClient(GetHwnd(), &pt); if ( x ) *x = pt.x; @@ -1131,7 +1423,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 ) @@ -1139,8 +1431,7 @@ void wxWindow::DoClientToScreen(int *x, int *y) const if ( y ) pt.y = *y; - HWND hWnd = GetHwnd(); - ::ClientToScreen(hWnd, &pt); + ::ClientToScreen(GetHwnd(), &pt); if ( x ) *x = pt.x; @@ -1148,134 +1439,180 @@ void wxWindow::DoClientToScreen(int *x, int *y) const *y = pt.y; } -// Get size *available for subwindows* i.e. excluding menu bar etc. -void wxWindow::DoGetClientSize(int *x, int *y) const +void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height) { - HWND hWnd = GetHwnd(); - RECT rect; - ::GetClientRect(hWnd, &rect); - if ( x ) - *x = rect.right; - if ( y ) - *y = rect.bottom; + // TODO: is this consistent with other platforms? + // Still, negative width or height shouldn't be allowed + if (width < 0) + width = 0; + if (height < 0) + height = 0; + if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) ) + { + wxLogLastError(wxT("MoveWindow")); + } } -void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags) +// set the size of the window: if the dimensions are positive, just use them, +// but if any of them is equal to -1, it means that we must find the value for +// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in +// which case -1 is a valid value for x and y) +// +// 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 wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) { + // get the current size and position... int currentX, currentY; GetPosition(¤tX, ¤tY); int currentW,currentH; GetSize(¤tW, ¤tH); - if ( x == currentX && y == currentY && width == currentW && height == currentH ) + // ... and don't do anything (avoiding flicker) if it's already ok + if ( x == currentX && y == currentY && + width == currentW && height == currentH ) + { return; + } - int actualWidth = width; - int actualHeight = height; - int actualX = x; - int actualY = y; - if ( x == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) - actualX = currentX; - if ( y == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) - actualY = currentY; + if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + x = currentX; + if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + y = currentY; - AdjustForParentClientOrigin(actualX, actualY, sizeFlags); + AdjustForParentClientOrigin(x, y, sizeFlags); + wxSize size(-1, -1); if ( width == -1 ) - actualWidth = currentW; + { + if ( sizeFlags & wxSIZE_AUTO_WIDTH ) + { + size = DoGetBestSize(); + width = size.x; + } + else + { + // just take the current one + width = currentW; + } + } + if ( height == -1 ) - actualHeight = currentH; + { + if ( sizeFlags & wxSIZE_AUTO_HEIGHT ) + { + if ( size.x == -1 ) + { + size = DoGetBestSize(); + } + //else: already called DoGetBestSize() above - HWND hWnd = GetHwnd(); - if ( hWnd ) - MoveWindow(hWnd, actualX, actualY, actualWidth, actualHeight, (BOOL)TRUE); + height = size.y; + } + else + { + // just take the current one + height = currentH; + } + } + + 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(); - HWND hParentWnd = (HWND) 0; - if ( parent ) - hParentWnd = (HWND) parent->GetHWND(); + // setting the client size is less obvious than it it could have been + // because in the result of changing the total size the window scrollbar + // may [dis]appear and/or its menubar may [un]wrap and so the client size + // will not be correct as the difference between the total and client size + // changes - so we keep changing it until we get it right + // + // normally this loop shouldn't take more than 3 iterations (usually 1 but + // if scrollbars [dis]appear as the result of the first call, then 2 and it + // may become 3 if the window had 0 size originally and so we didn't + // calculate the scrollbar correction correctly during the first iteration) + // but just to be on the safe side we check for it instead of making it an + // "infinite" loop (i.e. leaving break inside as the only way to get out) + for ( int i = 0; i < 4; i++ ) + { + RECT rectClient; + ::GetClientRect(GetHwnd(), &rectClient); - RECT rect; - ::GetClientRect(hWnd, &rect); + // if the size is already ok, stop here (rectClient.left = top = 0) + if ( rectClient.right == width && rectClient.bottom == height ) + { + break; + } - RECT rect2; - GetWindowRect(hWnd, &rect2); + if ( i == 3 ) + { + // how did it happen? maybe OnSize() handler does something really + // strange in this class? + wxFAIL_MSG( _T("logic error in DoSetClientSize") ); - // Find the difference between the entire window (title bar and all) - // and the client area; add this to the new client size to move the - // window - int actual_width = rect2.right - rect2.left - rect.right + width; - int actual_height = rect2.bottom - rect2.top - rect.bottom + height; + break; + } - // If there's a parent, must subtract the parent's top left corner - // since MoveWindow moves relative to the parent + int widthClient = width, + heightClient = height; - POINT point; - point.x = rect2.left; - point.y = rect2.top; - if ( parent ) - { - ::ScreenToClient(hParentWnd, &point); - } + // Find the difference between the entire window (title bar and all) + // and the client area; add this to the new client size to move the + // window + RECT rectWin; + ::GetWindowRect(GetHwnd(), &rectWin); - MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE); + widthClient += rectWin.right - rectWin.left - rectClient.right; + heightClient += rectWin.bottom - rectWin.top - rectClient.bottom; - wxSizeEvent event(wxSize(width, height), m_windowId); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + POINT point; + point.x = rectWin.left; + point.y = rectWin.top; + + // MoveWindow positions the child windows relative to the parent, so + // adjust if necessary + if ( !IsTopLevel() ) + { + wxWindow *parent = GetParent(); + if ( parent ) + { + ::ScreenToClient(GetHwndOf(parent), &point); + } + } + + DoMoveWindow(point.x, point.y, widthClient, heightClient); + } } // 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) -{ - if ( ((sizeFlags & wxSIZE_NO_ADJUSTMENTS) == 0) && GetParent() ) - { - wxPoint pt(GetParent()->GetClientAreaOrigin()); - x += pt.x; y += pt.y; - } -} - // --------------------------------------------------------------------------- // text metrics // --------------------------------------------------------------------------- -int wxWindow::GetCharHeight() const +int wxWindowMSW::GetCharHeight() const { - TEXTMETRIC lpTextMetric; - HWND hWnd = GetHwnd(); - HDC dc = ::GetDC(hWnd); - - GetTextMetrics(dc, &lpTextMetric); - ::ReleaseDC(hWnd, dc); - - return lpTextMetric.tmHeight; + return wxGetTextMetrics(this).tmHeight; } -int wxWindow::GetCharWidth() const +int wxWindowMSW::GetCharWidth() const { - TEXTMETRIC lpTextMetric; - HWND hWnd = GetHwnd(); - HDC dc = ::GetDC(hWnd); - - GetTextMetrics(dc, &lpTextMetric); - ::ReleaseDC(hWnd, dc); - - return lpTextMetric.tmAveCharWidth; + // +1 is needed because Windows apparently adds it when calculating the + // dialog units size in pixels +#if wxDIALOG_UNIT_COMPATIBILITY + 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 @@ -1298,7 +1635,7 @@ void wxWindow::GetTextExtent(const wxString& string, SIZE sizeRect; TEXTMETRIC tm; - GetTextExtentPoint(dc, (const wxChar *)string, (int)string.Length(), &sizeRect); + GetTextExtentPoint(dc, string, (int)string.Length(), &sizeRect); GetTextMetrics(dc, &tm); if ( fontToUse && fnt && hfontOld ) @@ -1306,10 +1643,14 @@ void wxWindow::GetTextExtent(const wxString& string, ReleaseDC(hWnd, dc); - if ( x ) *x = sizeRect.cx; - if ( y ) *y = sizeRect.cy; - if ( descent ) *descent = tm.tmDescent; - if ( externalLeading ) *externalLeading = tm.tmExternalLeading; + if ( x ) + *x = sizeRect.cx; + if ( y ) + *y = sizeRect.cy; + if ( descent ) + *descent = tm.tmDescent; + if ( externalLeading ) + *externalLeading = tm.tmExternalLeading; } #if wxUSE_CARET && WXWIN_COMPATIBILITY @@ -1317,36 +1658,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" ); @@ -1354,11 +1695,66 @@ void wxWindow::GetCaretPos(int *x, int *y) const } #endif // wxUSE_CARET +// --------------------------------------------------------------------------- +// popup menu +// --------------------------------------------------------------------------- + +#if wxUSE_MENUS_NATIVE + +// 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); + } +} + +bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) +{ + menu->SetInvokingWindow(this); + menu->UpdateUI(); + + HWND hWnd = GetHwnd(); + HMENU hMenu = GetHmenuOf(menu); + POINT point; + point.x = x; + point.y = y; + ::ClientToScreen(hWnd, &point); + wxCurrentPopupMenu = menu; + ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL); + + // 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); + + 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); @@ -1366,12 +1762,18 @@ 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 MSG *msg = (MSG *)pMsg; + + // here we try to do all the job which ::IsDialogMessage() usually does + // internally +#if 1 bool bProcess = TRUE; if ( msg->message != WM_KEYDOWN ) bProcess = FALSE; @@ -1381,8 +1783,8 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) if ( bProcess ) { - bool bCtrlDown = (::GetKeyState(VK_CONTROL) & 0x100) != 0; - bool bShiftDown = (::GetKeyState(VK_SHIFT) & 0x100) != 0; + bool bCtrlDown = wxIsCtrlDown(); + bool bShiftDown = wxIsShiftDown(); // WM_GETDLGCODE: ask the control if it wants the key for itself, // don't process it if it's the case (except for Ctrl-Tab/Enter @@ -1437,12 +1839,43 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) } else if ( lDlgCode & DLGC_BUTTON ) { - // buttons want process Enter themselevs + // let IsDialogMessage() handle this for all + // buttons except the owner-drawn ones which it + // just seems to ignore + long style = ::GetWindowLong(msg->hwnd, GWL_STYLE); + if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW ) + { + // emulate the button click + wxWindow *btn = wxFindWinFromHandle((WXHWND)msg->hwnd); + if ( btn ) + btn->MSWCommand(BN_CLICKED, 0 /* unused */); + } + bProcess = FALSE; } - // 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. + // FIXME: this should be handled by + // wxNavigationKeyEvent handler and not here!! + else + { +#if wxUSE_BUTTON + wxButton *btn = wxDynamicCast(GetDefaultItem(), + wxButton); + if ( btn && btn->IsEnabled() ) + { + // if we do have a default button, do press it + btn->MSWCommand(BN_CLICKED, 0 /* unused */); + + return TRUE; + } + 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; @@ -1459,21 +1892,47 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) if ( GetEventHandler()->ProcessEvent(event) ) { - wxButton *btn = wxDynamicCast(FindFocus(), wxButton); - if ( btn ) + return TRUE; + } + } + } +#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 ) { - // the button which has focus should be default - btn->SetDefault(); + nbook = wxDynamicCast(win, wxNotebook); + win = win->GetParent(); } - return TRUE; + if ( nbook ) + { + bool forward = !wxIsShiftDown(); + + nbook->AdvanceSelection(forward); + } } } } +#endif // 1/0 if ( ::IsDialogMessage(GetHwnd(), msg) ) + { + // IsDialogMessage() did something... return TRUE; + } } +#endif // __WXUNIVERSAL__ #if wxUSE_TOOLTIPS if ( m_tooltip ) @@ -1488,12 +1947,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) { - return m_acceleratorTable.Ok() && - ::TranslateAccelerator(GetHwnd(), - GetTableHaccel(m_acceleratorTable), - (MSG *)pMsg); + // preprocess all messages by default + return TRUE; } // --------------------------------------------------------------------------- @@ -1502,7 +1968,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); @@ -1510,7 +1976,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); @@ -1518,7 +1984,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); @@ -1526,15 +1992,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; @@ -1544,7 +2012,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; @@ -1552,7 +2020,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; @@ -1560,7 +2028,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; @@ -1568,7 +2036,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); @@ -1576,7 +2044,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; @@ -1592,51 +2060,52 @@ 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; +static wxWindowMSW *gs_winBeingCreated = NULL; + +// implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the +// window being created and insures that it's always unset back later +wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated) +{ + gs_winBeingCreated = winBeingCreated; +} + +wxWindowCreationHook::~wxWindowCreationHook() +{ + gs_winBeingCreated = NULL; +} // Main window proc -LRESULT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { // trace all messages - useful for the debugging #ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, _T("Processing %s(wParam=%8lx, lParam=%8lx)"), + wxLogTrace(wxTraceMessages, wxT("Processing %s(wParam=%8lx, lParam=%8lx)"), 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 - if ( !wnd && wxWndHook ) + // it with wxWindow stored in gs_winBeingCreated + if ( !wnd && gs_winBeingCreated ) { - wxAssociateWinWithHandle(hWnd, wxWndHook); - wnd = wxWndHook; - wxWndHook = NULL; + wxAssociateWinWithHandle(hWnd, gs_winBeingCreated); + wnd = gs_winBeingCreated; + gs_winBeingCreated = NULL; wnd->SetHWND((WXHWND)hWnd); } LRESULT rc; - // Stop right here if we don't have a valid handle in our wxWindow object. - if ( wnd && !wnd->GetHWND() ) - { - // FIXME: why do we do this? - wnd->SetHWND((WXHWND) hWnd); - rc = wnd->MSWDefWindowProc(message, wParam, lParam ); - wnd->SetHWND(0); - } + if ( wnd ) + rc = wnd->MSWWindowProc(message, wParam, lParam); else - { - if ( wnd ) - rc = wnd->MSWWindowProc(message, wParam, lParam); - else - rc = DefWindowProc( hWnd, message, wParam, lParam ); - } + rc = ::DefWindowProc(hWnd, message, wParam, lParam); 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; @@ -1668,16 +2137,50 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) break; case WM_DESTROY: - processed = HandleDestroy(); + // never set processed to TRUE and *always* pass WM_DESTROY to + // DefWindowProc() as Windows may do some internal cleanup when + // processing it and failing to pass the message along may cause + // memory and resource leaks! + (void)HandleDestroy(); break; case WM_MOVE: - processed = HandleMove(LOWORD(lParam), HIWORD(lParam)); + processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(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: { @@ -1713,6 +2216,17 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) break; case WM_MOUSEMOVE: + processed = HandleMouseMove(GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + wParam); + break; + +#if wxUSE_MOUSEWHEEL + case WM_MOUSEWHEEL: + processed = HandleMouseWheel(wParam, lParam); + break; +#endif + case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_LBUTTONDBLCLK: @@ -1722,14 +2236,70 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDBLCLK: + { + 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; + } + +#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 { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - - processed = HandleMouseEvent(message, x, y, wParam); + // 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; } - break; +#endif // __WXMICROWIN__ +#ifdef MM_JOY1MOVE case MM_JOY1MOVE: case MM_JOY2MOVE: case MM_JOY1ZMOVE: @@ -1738,13 +2308,12 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) case MM_JOY2BUTTONDOWN: case MM_JOY1BUTTONUP: case MM_JOY2BUTTONUP: - { - int x = LOWORD(lParam); - int y = HIWORD(lParam); - - processed = HandleJoystickEvent(message, x, y, wParam); - } + processed = HandleJoystickEvent(message, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + wParam); break; +#endif // __WXMICROWIN__ case WM_SYSCOMMAND: processed = HandleSysCommand(wParam, lParam); @@ -1767,6 +2336,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: { @@ -1786,6 +2356,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) rc.result = TRUE; } break; +#endif // defined(WM_DRAWITEM) case WM_GETDLGCODE: if ( m_lDlgCode ) @@ -1796,6 +2367,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) //else: get the dlg code from the DefWindowProc() break; + case WM_SYSKEYDOWN: case WM_KEYDOWN: // If this has been processed by an event handler, // return 0 now (we've handled it). @@ -1823,6 +2395,8 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) case VK_RETURN: case VK_BACK: case VK_TAB: + case VK_ADD: + case VK_SUBTRACT: // but set processed to FALSE, not TRUE to still pass them to // the control's default window proc - otherwise built-in // keyboard handling won't work @@ -1835,20 +2409,11 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) // click because both usually pop up a context menu case VK_APPS: { - // construct the key mask - WPARAM fwKeys = MK_RBUTTON; - if ( (::GetKeyState(VK_CONTROL) & 0x100) != 0 ) - fwKeys |= MK_CONTROL; - if ( (::GetKeyState(VK_SHIFT) & 0x100) != 0 ) - fwKeys |= MK_SHIFT; - - // simulate right mouse button click - DWORD dwPos = ::GetMessagePos(); - int x = GET_X_LPARAM(dwPos), - y = GET_Y_LPARAM(dwPos); - - ScreenToClient(&x, &y); - processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, fwKeys); + WPARAM flags; + int x, y; + + TranslateKbdEventToMouse(this, &x, &y, &flags); + processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags); } break; #endif // VK_APPS @@ -1862,10 +2427,26 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) } break; + case WM_SYSKEYUP: case WM_KEYUP: - processed = HandleKeyUp((WORD) wParam, lParam); +#ifdef VK_APPS + // 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); + } + else +#endif // VK_APPS + { + processed = HandleKeyUp((WORD) wParam, lParam); + } break; + case WM_SYSCHAR: case WM_CHAR: // Always an ASCII character processed = HandleChar((WORD)wParam, lParam, TRUE); break; @@ -1884,7 +2465,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: @@ -1911,6 +2493,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: @@ -1973,12 +2556,76 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) rc.result = TRUE; } break; + +#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) + { + 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, info->iCtrlId); + helpEvent.SetEventObject(this); + processed = GetEventHandler()->ProcessEvent(helpEvent); + + } + //else: processed is already FALSE + } + break; + + case WM_CONTEXTMENU: + { + // 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); + } + break; +#endif // __WIN32__ + + // unfortunately this doesn't really work as then window which + // doesn't accept focus doesn't get any mouse events neither which + // means it can't get any input at all +#if 0 //def __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 ) { #ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, _T("Forwarding %s to DefWindowProc."), + wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."), wxGetMessageName(message)); #endif // __WXDEBUG__ rc.result = MSWDefWindowProc(message, wParam, lParam); @@ -1987,188 +2634,235 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) return rc.result; } -// Dialog window proc -LONG APIENTRY _EXPORT -wxDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - if ( message == WM_INITDIALOG ) - { - // for this message, returning TRUE tells system to set focus to the - // first control in the dialog box - return TRUE; - } - else - { - // for all the other ones, FALSE means that we didn't process the - // message - return 0; - } -} +// ---------------------------------------------------------------------------- +// wxWindow <-> HWND map +// ---------------------------------------------------------------------------- + +wxWinHashTable *wxWinHandleHash = NULL; -wxList *wxWinHandleList = NULL; wxWindow *wxFindWinFromHandle(WXHWND hWnd) { - wxNode *node = wxWinHandleList->Find((long)hWnd); - if ( !node ) - return NULL; - return (wxWindow *)node->Data(); + return wxWinHandleHash->Get((long)hWnd); } -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 wxCHECK_RET( hWnd != (HWND)NULL, - _T("attempt to add a NULL hWnd to window list ignored") ); + wxT("attempt to add a NULL hWnd to window list ignored") ); - if ( !wxWinHandleList->Find((long)hWnd) ) - wxWinHandleList->Append((long)hWnd, win); + wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd); +#ifdef __WXDEBUG__ + if ( oldWin && (oldWin != win) ) + { + wxLogDebug(wxT("HWND %X already associated with another window (%s)"), + hWnd, win->GetClassInfo()->GetClassName()); + } + else +#endif // __WXDEBUG__ + if (!oldWin) + { + wxWinHandleHash->Put((long)hWnd, (wxWindow *)win); + } } -void wxRemoveHandleAssociation(wxWindow *win) +void wxRemoveHandleAssociation(wxWindowMSW *win) { - wxWinHandleList->DeleteObject(win); + wxWinHandleHash->Delete((long)win->GetHWND()); } +// ---------------------------------------------------------------------------- +// various MSW speciic class dependent functions +// ---------------------------------------------------------------------------- + // 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]; HMENU hMenu = (HMENU)m_hMenu; int N = ::GetMenuItemCount(hMenu); - int i; - for (i = 0; i < N; i++) + for ( int i = 0; i < N; i++ ) { - wxChar buf[100]; - int chars = GetMenuString(hMenu, i, buf, 100, MF_BYPOSITION); - if ( !chars ) + if ( !::GetMenuString(hMenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION) ) { - wxLogLastError(_T("GetMenuString")); + wxLogLastError(wxT("GetMenuString")); continue; } - if ( wxStrcmp(buf, _T("&Window")) == 0 ) + if ( wxStrcmp(buf, _("&Window")) == 0 ) { - RemoveMenu(hMenu, i, MF_BYPOSITION); + if ( !::RemoveMenu(hMenu, i, MF_BYPOSITION) ) + { + wxLogLastError(wxT("RemoveMenu")); + } break; } } } +#endif // __WXUNIVERSAL__ } -bool wxWindow::MSWCreate(int id, - wxWindow *parent, - const wxChar *wclass, - wxWindow *wx_win, - const wxChar *title, - int x, - int y, - int width, - int height, - WXDWORD style, - const wxChar *dialog_template, - WXDWORD extendedStyle) +bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, + const wxSize& size, + int& x, int& y, + int& w, int& h) const { - int x1 = CW_USEDEFAULT; - int y1 = 0; - int width1 = CW_USEDEFAULT; - int height1 = 100; + bool nonDefault = FALSE; - // Find parent's size, if it exists, to set up a possible default - // panel size the size of the parent window - RECT parent_rect; - if ( parent ) + if ( pos.x == -1 ) { - ::GetClientRect((HWND) parent->GetHWND(), &parent_rect); + // if set x to CW_USEDEFAULT, y parameter is ignored anyhow so we can + // just as well set it to CW_USEDEFAULT as well + x = + y = CW_USEDEFAULT; + } + else + { + x = pos.x; + y = pos.y == -1 ? CW_USEDEFAULT : pos.y; - width1 = parent_rect.right - parent_rect.left; - height1 = parent_rect.bottom - parent_rect.top; + nonDefault = TRUE; } - if ( x > -1 ) x1 = x; - if ( y > -1 ) y1 = y; - if ( width > -1 ) width1 = width; - if ( height > -1 ) height1 = height; + /* + 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 + 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 + from some base class ctor and so this WM_SIZE is not processed in the + real class' OnSize() (because it's not fully constructed yet and the + 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 + this and ignore any attempts to change the window size to the size it + already has - so no WM_SIZE would be sent. + */ + if ( size.x == -1 ) + { + // as abobe, h is not used at all in this case anyhow + w = + h = CW_USEDEFAULT; + } + else + { + w = size.x; + h = size.y == -1 ? CW_USEDEFAULT : size.y; -#ifdef __WXWINE__ - HWND hParent = (HWND)NULL; -#else - HWND hParent = NULL; -#endif - if ( parent ) - hParent = (HWND) parent->GetHWND(); + nonDefault = TRUE; + } - wxWndHook = this; + return nonDefault; +} - if ( dialog_template ) - { - m_hWnd = (WXHWND)::CreateDialog(wxGetInstance(), - dialog_template, - hParent, - (DLGPROC)wxDlgProc); +bool wxWindowMSW::MSWCreate(const wxChar *wclass, + const wxChar *title, + const wxPoint& pos, + const wxSize& size, + WXDWORD style, + WXDWORD extendedStyle) +{ + // choose the position/size for the new window + int x, y, w, h; + (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h); - if ( m_hWnd == 0 ) + // find the correct parent HWND + wxWindow *parent = GetParent(); + bool isChild = (style & WS_CHILD) != 0; + 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 // !popup + { + if ( (isChild || HasFlag(wxFRAME_TOOL_WINDOW)) && parent ) { - wxLogError(_("Can't find dummy dialog template!\n" - "Check resource include path for finding wx.rc.")); - - return FALSE; + // this is either a normal child window or a top level window with + // wxFRAME_TOOL_WINDOW style (see below) + hParent = GetHwndOf(parent); } - - // ::SetWindowLong(GWL_EXSTYLE) doesn't work for the dialogs, so try - // to take care of (at least some) extended style flags ourselves - if ( extendedStyle & WS_EX_TOPMOST ) + else { - if ( !::SetWindowPos(GetHwnd(), HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE) ) - { - wxLogLastError(_T("SetWindowPos")); - } + // this is either a window for which no parent was specified (not + // much we can do then) or a frame without wxFRAME_TOOL_WINDOW + // style: we should use NULL parent HWND for it or it would be + // always on top of its parent which is not what we usually want + // (in fact, we only want it for frames with the special + // wxFRAME_TOOL_WINDOW as above) + hParent = NULL; } - // move the dialog to its initial position without forcing repainting - if ( !::MoveWindow(GetHwnd(), x1, y1, width1, height1, FALSE) ) + } + + // controlId is menu handle for the top level windows, so set it to 0 + // unless we're creating a child window + int controlId; + if ( isChild ) + { + controlId = GetId(); + + if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS ) { - wxLogLastError(_T("MoveWindow")); + style |= WS_CLIPSIBLINGS; } } - else + else // !child { - int controlId = 0; - if ( style & WS_CHILD ) - controlId = id; - - m_hWnd = (WXHWND)CreateWindowEx(extendedStyle, - wclass, - title ? title : _T(""), - style, - x1, y1, - width1, height1, - hParent, (HMENU)controlId, - wxGetInstance(), - NULL); - - if ( !m_hWnd ) - { - wxLogError(_("Can't create window of class %s!\n" - "Possible Windows 3.x compatibility problem?"), - wclass); + controlId = 0; + } - return FALSE; - } + // for each class "Foo" we have we also have "FooNR" ("no repaint") class + // which is the same but without CS_[HV]REDRAW class styles so using it + // ensures that the window is not fully repainted on each resize + wxString className(wclass); + if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE ) + { + className += wxT("NR"); + } + + // do create the window + wxWindowCreationHook hook(this); + + m_hWnd = (WXHWND)::CreateWindowEx + ( + extendedStyle, + className, + title ? title : wxT(""), + style, + x, y, w, h, + hParent, + (HMENU)controlId, + wxGetInstance(), + NULL // no extra data + ); + + if ( !m_hWnd ) + { + wxLogSysError(_("Can't create window of class %s"), wclass); + + return FALSE; } - wxWndHook = NULL; - wxWinHandleList->Append((long)m_hWnd, this); + SubclassWin(m_hWnd); + + SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT)); return TRUE; } @@ -2183,8 +2877,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); @@ -2203,8 +2898,6 @@ bool wxWindow::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) if ( child->MSWOnNotify(idCtrl, lParam, result) ) { return TRUE; - - break; } node = node->GetNext(); @@ -2212,15 +2905,18 @@ 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)) { #if wxUSE_TOOLTIPS NMHDR* hdr = (NMHDR *)lParam; - if ( hdr->code == TTN_NEEDTEXT && m_tooltip ) + if ( (int)hdr->code == TTN_NEEDTEXT && m_tooltip ) { TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam; ttt->lpszText = (wxChar *)m_tooltip->GetTip().c_str(); @@ -2238,12 +2934,12 @@ 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); event.SetCanVeto(TRUE); - event.SetLoggingOff(logOff == ENDSESSION_LOGOFF); + event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF); bool rc = wxTheApp->ProcessEvent(event); @@ -2257,31 +2953,32 @@ 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 ) return FALSE; + // only send once + if ( (this != wxTheApp->GetTopWindow()) ) + return FALSE; + wxCloseEvent event(wxEVT_END_SESSION, -1); event.SetEventObject(wxTheApp); event.SetCanVeto(FALSE); - event.SetLoggingOff( (logOff == ENDSESSION_LOGOFF) ); - if ( (this == wxTheApp->GetTopWindow()) && // Only send once - wxTheApp->ProcessEvent(event)) - { - } - return TRUE; + event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) ); + + return wxTheApp->ProcessEvent(event); } // --------------------------------------------------------------------------- // window creation/destruction // --------------------------------------------------------------------------- -bool wxWindow::HandleCreate(WXLPCREATESTRUCT 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; @@ -2289,9 +2986,9 @@ bool wxWindow::HandleCreate(WXLPCREATESTRUCT 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 @@ -2313,7 +3010,7 @@ bool wxWindow::HandleDestroy() // activation/focus // --------------------------------------------------------------------------- -bool wxWindow::HandleActivate(int state, +bool wxWindowMSW::HandleActivate(int state, bool WXUNUSED(minimized), WXHWND WXUNUSED(activate)) { @@ -2325,8 +3022,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((wxWindow *)this); + (void)GetEventHandler()->ProcessEvent(eventFocus); + #if wxUSE_CARET // Deal with caret if ( m_caret ) @@ -2335,20 +3037,25 @@ bool wxWindow::HandleSetFocus(WXHWND WXUNUSED(hwnd)) } #endif // wxUSE_CARET - // panel wants to track the window which was the last to have focus in it - wxPanel *panel = wxDynamicCast(GetParent(), wxPanel); - if ( panel ) +#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) ) { - panel->SetLastFocus(this); + 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 @@ -2358,9 +3065,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); } @@ -2368,7 +3088,7 @@ bool wxWindow::HandleKillFocus(WXHWND WXUNUSED(hwnd)) // miscellaneous // --------------------------------------------------------------------------- -bool wxWindow::HandleShow(bool show, int status) +bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status)) { wxShowEvent event(GetId(), show); event.m_eventObject = this; @@ -2376,7 +3096,7 @@ bool wxWindow::HandleShow(bool show, int status) return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) +bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus)) { wxInitDialogEvent event(GetId()); event.m_eventObject = this; @@ -2384,89 +3104,132 @@ 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); // Get the total number of files dropped - WORD gwFilesDropped = (WORD)DragQueryFile ((HDROP)hFilesInfo, - (UINT)-1, - (LPSTR)0, - (UINT)0); + UINT gwFilesDropped = ::DragQueryFile + ( + (HDROP)hFilesInfo, + (UINT)-1, + (LPTSTR)0, + (UINT)0 + ); wxString *files = new wxString[gwFilesDropped]; - int wIndex; - for (wIndex=0; wIndex < (int)gwFilesDropped; wIndex++) + for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ ) { - DragQueryFile (hFilesInfo, wIndex, (LPTSTR) wxBuffer, 1000); - files[wIndex] = wxBuffer; + // first get the needed buffer length (+1 for terminating NUL) + size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1; + + // and now get the file name + ::DragQueryFile(hFilesInfo, wIndex, + files[wIndex].GetWriteBuf(len), len); + + files[wIndex].UngetWriteBuf(); } DragFinish (hFilesInfo); wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files); event.m_eventObject = this; - event.m_pos.x = dropPoint.x; event.m_pos.x = dropPoint.y; - - bool rc = GetEventHandler()->ProcessEvent(event); - delete[] files; + POINT dropPoint; + DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint); + event.m_pos.x = dropPoint.x; + event.m_pos.y = dropPoint.y; - return rc; + return GetEventHandler()->ProcessEvent(event); +#else // __WXMICROWIN__ + return FALSE; +#endif } -bool wxWindow::HandleSetCursor(WXHWND hWnd, - short nHitTest, - int WXUNUSED(mouseMsg)) -{ - // don't set cursor for other windows, only for this one: this prevents - // children of this window from getting the same cursor as the parent has - // (don't forget that this message is propagated by default up the window - // parent-child hierarchy) - if ( GetHWND() == hWnd ) - { - // don't set cursor when the mouse is not in the client part - if ( nHitTest == HTCLIENT || nHitTest == HTERROR ) +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 + // 0. allow the user to override default behaviour by using EVT_SET_CURSOR + // 1. if we have the cursor set it unless wxIsBusy() + // 2. if we're a top level window, set some cursor anyhow + // 3. if wxIsBusy(), set the busy cursor, otherwise the global one + + if ( nHitTest != HTCLIENT ) + { + return FALSE; + } + + HCURSOR hcursor = 0; + + // first ask the user code - it may wish to set the cursor in some very + // specific way (for example, depending on the current position) + POINT pt; +#ifdef __WIN32__ + if ( !::GetCursorPos(&pt) ) + { + wxLogLastError(wxT("GetCursorPos")); + } +#else + // In WIN16 it doesn't return a value. + ::GetCursorPos(&pt); +#endif + + int x = pt.x, + y = pt.y; + ScreenToClient(&x, &y); + wxSetCursorEvent event(x, y); + + bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event); + if ( processedEvtSetCursor && event.HasCursor() ) + { + hcursor = GetHcursorOf(event.GetCursor()); + } + + if ( !hcursor ) + { + bool isBusy = wxIsBusy(); + + // the test for processedEvtSetCursor is here to prevent using m_cursor + // if the user code caught EVT_SET_CURSOR() and returned nothing from + // it - this is a way to say that our cursor shouldn't be used for this + // point + if ( !processedEvtSetCursor && m_cursor.Ok() ) + { + hcursor = GetHcursorOf(m_cursor); + } + + if ( !GetParent() ) { - HCURSOR hcursor = 0; - if ( wxIsBusy() ) + if ( isBusy ) { - // from msw\utils.cpp - extern HCURSOR gs_wxBusyCursor; - - hcursor = gs_wxBusyCursor; + hcursor = wxGetCurrentBusyCursor(); } - else + else if ( !hcursor ) { - wxCursor *cursor = NULL; - - if ( m_cursor.Ok() ) - { - cursor = &m_cursor; - } - else + const wxCursor *cursor = wxGetGlobalCursor(); + if ( cursor && cursor->Ok() ) { - // from msw\data.cpp - extern wxCursor *g_globalCursor; - - if ( g_globalCursor && g_globalCursor->Ok() ) - cursor = g_globalCursor; + hcursor = GetHcursorOf(*cursor); } - - if ( cursor ) - hcursor = (HCURSOR)cursor->GetHCURSOR(); } + } + } - if ( hcursor ) - { - ::SetCursor(hcursor); + if ( hcursor ) + { + ::SetCursor(hcursor); - return TRUE; - } - } + // cursor set, stop here + return TRUE; } +#endif // __WXMICROWIN__ + // pass up the window chain return FALSE; } @@ -2474,50 +3237,56 @@ bool wxWindow::HandleSetCursor(WXHWND 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 ) + DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct; + if ( id == 0 && pDrawStruct->CtlType == ODT_MENU ) { - DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct; wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData); 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); } - else -#endif - return FALSE; +#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? - if ( id == 0 ) + MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct; + if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU ) { - MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct; wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData); wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); @@ -2539,15 +3308,19 @@ bool wxWindow::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) // colours and palettes // --------------------------------------------------------------------------- -bool wxWindow::HandleSysColorChange() +bool wxWindowMSW::HandleSysColorChange() { wxSysColourChangedEvent event; event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + (void)GetEventHandler()->ProcessEvent(event); + + // always let the system carry on the default processing to allow the + // native controls to react to the colours update + return FALSE; } -bool wxWindow::HandleCtlColor(WXHBRUSH *brush, +bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor, @@ -2555,37 +3328,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 hDC, - WXHWND hWnd, - WXUINT nCtlColor, - WXUINT message, - WXWPARAM wParam, - WXLPARAM 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); @@ -2594,7 +3373,7 @@ bool wxWindow::HandlePaletteChanged(WXHWND hWndPalChange) return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleQueryNewPalette() +bool wxWindowMSW::HandleQueryNewPalette() { wxQueryNewPaletteEvent event(GetId()); event.SetEventObject(this); @@ -2603,21 +3382,37 @@ 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(); + wxWindowList::Node *node = GetChildren().GetFirst(); while ( node ) { - // Only propagate to non-top-level windows - wxWindow *win = (wxWindow *)node->Data(); - if ( win->GetParent() ) + // Only propagate to non-top-level windows because Windows already + // sends this event to all top-level ones + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() ) { - wxSysColourChangedEvent event2; - event.m_eventObject = win; - win->GetEventHandler()->ProcessEvent(event2); + // we need to send the real WM_SYSCOLORCHANGE and not just trigger + // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for + // the standard controls + ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0); } - node = node->Next(); + 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); } } @@ -2625,41 +3420,64 @@ 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 if ( !hRegion ) - wxLogLastError("CreateRectRgn"); + wxLogLastError(wxT("CreateRectRgn")); if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR ) - wxLogLastError("GetUpdateRgn"); + 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 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); @@ -2667,13 +3485,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); @@ -2683,7 +3502,7 @@ void wxWindow::OnEraseBackground(wxEraseEvent& event) m_backgroundColour.Blue()); HBRUSH hBrush = ::CreateSolidBrush(ref); if ( !hBrush ) - wxLogLastError("CreateSolidBrush"); + wxLogLastError(wxT("CreateSolidBrush")); HDC hdc = (HDC)event.GetDC()->GetHDC(); @@ -2698,7 +3517,7 @@ void wxWindow::OnEraseBackground(wxEraseEvent& event) // moving and resizing // --------------------------------------------------------------------------- -bool wxWindow::HandleMinimize() +bool wxWindowMSW::HandleMinimize() { wxIconizeEvent event(m_windowId); event.SetEventObject(this); @@ -2706,7 +3525,7 @@ bool wxWindow::HandleMinimize() return GetEventHandler()->ProcessEvent(event); } -bool wxWindow::HandleMaximize() +bool wxWindowMSW::HandleMaximize() { wxMaximizeEvent event(m_windowId); event.SetEventObject(this); @@ -2714,7 +3533,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); @@ -2722,7 +3541,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); @@ -2730,7 +3549,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; @@ -2767,29 +3586,71 @@ bool wxWindow::HandleGetMinMaxInfo(void *mmInfo) // command messages // --------------------------------------------------------------------------- -bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) +bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) { - if ( wxCurrentPopupMenu ) +#if wxUSE_MENUS_NATIVE + if ( !cmd && wxCurrentPopupMenu ) { wxMenu *popupMenu = wxCurrentPopupMenu; wxCurrentPopupMenu = NULL; return popupMenu->MSWCommand(cmd, id); } +#endif // wxUSE_MENUS_NATIVE - wxWindow *win = FindItem(id); - if ( !win ) + wxWindow *win = NULL; + + // first try to find it from HWND - this works even with the broken + // programs using the same ids for different controls + if ( control ) { win = wxFindWinFromHandle(control); } + // try the id + if ( !win ) + { + // must cast to a signed type before comparing with other ids! + win = FindItem((signed short)id); + } + if ( win ) + { return win->MSWCommand(cmd, id); + } + + // the messages sent from the in-place edit control used by the treectrl + // for label editing have id == 0, but they should _not_ be treated as menu + // messages (they are EN_XXX ones, in fact) so don't translate anything + // coming from a control to wxEVT_COMMAND_MENU_SELECTED + if ( !control ) + { + // If no child window, it may be an accelerator, e.g. for a popup menu + // command + + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED); + event.SetEventObject(this); + event.SetId(id); + event.SetInt(id); + + return GetEventHandler()->ProcessEvent(event); + } +#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__) + else + { + // 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 wxWindow::HandleSysCommand(WXWPARAM wParam, WXLPARAM lParam) +bool wxWindowMSW::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam)) { // 4 bits are reserved switch ( wParam & 0xFFFFFFF0 ) @@ -2808,15 +3669,22 @@ bool wxWindow::HandleSysCommand(WXWPARAM wParam, WXLPARAM 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; @@ -2825,10 +3693,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 @@ -2854,17 +3721,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 @@ -2874,7 +3748,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; @@ -2885,16 +3759,90 @@ bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags) return HandleMouseEvent(WM_MOUSEMOVE, x, y, flags); } + +bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) +{ +#if wxUSE_MOUSEWHEEL + wxMouseEvent event(wxEVT_MOUSEWHEEL); + InitMouseEvent(event, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + LOWORD(wParam)); + event.m_wheelRotation = (short)HIWORD(wParam); + event.m_wheelDelta = WHEEL_DELTA; + +#ifdef __WIN32__ + static int s_linesPerRotation = -1; + if ( s_linesPerRotation == -1 ) + { + if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, + &s_linesPerRotation, 0)) + { + // this is not supposed to happen + wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)")); + + // the default is 3, so use it if SystemParametersInfo() failed + s_linesPerRotation = 3; + } + } +#else // Win16 + // no SystemParametersInfo() under Win16 + static const int s_linesPerRotation = 3; +#endif + + event.m_linesPerAction = s_linesPerRotation; + return GetEventHandler()->ProcessEvent(event); + +#else + (void) wParam; + (void) lParam; + + return FALSE; +#endif +} + + // --------------------------------------------------------------------------- // keyboard handling // --------------------------------------------------------------------------- +// create the key event of the given type for the given key - used by +// HandleChar and HandleKeyDown/Up +wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType, + int id, + WXLPARAM lParam) const +{ + wxKeyEvent event(evType); + event.SetId(GetId()); + event.m_shiftDown = wxIsShiftDown(); + event.m_controlDown = wxIsCtrlDown(); + event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN; + + event.m_eventObject = (wxWindow *)this; // const_cast + event.m_keyCode = id; + event.SetTimestamp(s_currentMsg.time); + + // translate the position to client coords + POINT pt; + GetCursorPos(&pt); + RECT rect; + GetWindowRect(GetHwnd(),&rect); + pt.x -= rect.left; + pt.y -= rect.top; + + event.m_x = pt.x; + event.m_y = pt.y; + + return event; +} + // isASCII is TRUE only when we're called from WM_CHAR handler and not from // WM_KEYDOWN one -bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII) +bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) { + bool ctrlDown = FALSE; + int id; - bool tempControlDown = FALSE; if ( isASCII ) { // If 1 -> 26, translate to CTRL plus a letter. @@ -2903,150 +3851,95 @@ bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII) { switch (id) { - case 13: - { + case 13: id = WXK_RETURN; break; - } - case 8: - { + + case 8: id = WXK_BACK; break; - } - case 9: - { + + case 9: id = WXK_TAB; break; - } - default: - { - tempControlDown = TRUE; + + default: + ctrlDown = TRUE; id = id + 96; - } } } } - else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) { + else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) + { // it's ASCII and will be processed here only when called from - // WM_CHAR (i.e. when isASCII = TRUE) + // WM_CHAR (i.e. when isASCII = TRUE), don't process it now id = -1; } if ( id != -1 ) { - wxKeyEvent event(wxEVT_CHAR); - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - event.m_altDown = TRUE; - - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(s_currentMsg.time); - - POINT pt; - GetCursorPos(&pt); - RECT rect; - GetWindowRect(GetHwnd(),&rect); - pt.x -= rect.left; - pt.y -= rect.top; - - event.m_x = pt.x; event.m_y = pt.y; + wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam)); + if ( ctrlDown ) + { + event.m_controlDown = TRUE; + } if ( GetEventHandler()->ProcessEvent(event) ) return TRUE; - else - return FALSE; } - else - return FALSE; + + return FALSE; } -bool wxWindow::HandleKeyDown(WXWORD wParam, WXLPARAM lParam) +bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam) { - int id; + int id = wxCharCodeMSWToWX(wParam); - if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) { + if ( !id ) + { + // normal ASCII char id = wParam; } - if ( id != -1 ) + if ( id != -1 ) // VZ: does this ever happen (FIXME)? { - wxKeyEvent event(wxEVT_KEY_DOWN); - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - event.m_altDown = TRUE; - - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(s_currentMsg.time); - - POINT pt; - GetCursorPos(&pt); - RECT rect; - GetWindowRect(GetHwnd(),&rect); - pt.x -= rect.left; - pt.y -= rect.top; - - event.m_x = pt.x; event.m_y = pt.y; - + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam)); if ( GetEventHandler()->ProcessEvent(event) ) { return TRUE; } - else return FALSE; - } - else - { - return FALSE; } + + return FALSE; } -bool wxWindow::HandleKeyUp(WXWORD wParam, WXLPARAM lParam) +bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam) { - int id; + int id = wxCharCodeMSWToWX(wParam); - if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) { + if ( !id ) + { + // normal ASCII char id = wParam; } - if ( id != -1 ) + if ( id != -1 ) // VZ: does this ever happen (FIXME)? { - wxKeyEvent event(wxEVT_KEY_UP); - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - event.m_altDown = TRUE; - - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(s_currentMsg.time); - - POINT pt; - GetCursorPos(&pt); - RECT rect; - GetWindowRect(GetHwnd(),&rect); - pt.x -= rect.left; - pt.y -= rect.top; - - event.m_x = pt.x; event.m_y = pt.y; - + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam)); if ( GetEventHandler()->ProcessEvent(event) ) return TRUE; - else - return FALSE; } - else - return FALSE; + + return FALSE; } // --------------------------------------------------------------------------- // 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; @@ -3113,7 +4006,7 @@ bool wxWindow::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) break; default: - wxFAIL_MSG(_T("no such joystick event")); + wxFAIL_MSG(wxT("no such joystick event")); return FALSE; } @@ -3123,13 +4016,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 ) @@ -3170,9 +4066,35 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam, event.m_eventType = wxEVT_SCROLLWIN_PAGEDOWN; break; - case SB_THUMBTRACK: case SB_THUMBPOSITION: - event.m_eventType = wxEVT_SCROLLWIN_THUMBTRACK; + case SB_THUMBTRACK: +#ifdef __WIN32__ + // under Win32, the scrollbar range and position are 32 bit integers, + // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must + // explicitly query the scrollbar for the correct position (this must + // be done only for these two SB_ events as they are the only one + // carrying the scrollbar position) + { + SCROLLINFO scrollInfo; + wxZeroMemory(scrollInfo); + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_TRACKPOS; + + if ( !::GetScrollInfo(GetHwnd(), + orientation == wxHORIZONTAL ? SB_HORZ + : SB_VERT, + &scrollInfo) ) + { + wxLogLastError(_T("GetScrollInfo")); + } + + event.SetPosition(scrollInfo.nTrackPos); + } +#endif // Win32 + + event.m_eventType = wParam == SB_THUMBPOSITION + ? wxEVT_SCROLLWIN_THUMBRELEASE + : wxEVT_SCROLLWIN_THUMBTRACK; break; default: @@ -3186,7 +4108,7 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam, // global functions // =========================================================================== -void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) +void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font) { TEXTMETRIC tm; HDC dc = ::GetDC((HWND) wnd); @@ -3196,7 +4118,7 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) { // the_font->UseResource(); // the_font->RealizeResource(); - fnt = (HFONT)the_font->GetResourceHandle(); + fnt = (HFONT)((wxFont *)the_font)->GetResourceHandle(); // const_cast if ( fnt ) was = (HFONT) SelectObject(dc,fnt); } @@ -3206,8 +4128,11 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) SelectObject(dc,was); } ReleaseDC((HWND)wnd, dc); - *x = tm.tmAveCharWidth; - *y = tm.tmHeight + tm.tmExternalLeading; + + if ( x ) + *x = tm.tmAveCharWidth; + if ( y ) + *y = tm.tmHeight + tm.tmExternalLeading; // if ( the_font ) // the_font->ReleaseResource(); @@ -3217,80 +4142,79 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) // the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead. int wxCharCodeMSWToWX(int keySym) { - int id = 0; + int id; switch (keySym) { - case VK_CANCEL: id = WXK_CANCEL; break; - case VK_BACK: id = WXK_BACK; break; - case VK_TAB: id = WXK_TAB; break; - case VK_CLEAR: id = WXK_CLEAR; break; - case VK_RETURN: id = WXK_RETURN; break; - case VK_SHIFT: id = WXK_SHIFT; break; - case VK_CONTROL: id = WXK_CONTROL; break; - case VK_MENU : id = WXK_MENU; break; - case VK_PAUSE: id = WXK_PAUSE; break; - case VK_SPACE: id = WXK_SPACE; break; - case VK_ESCAPE: id = WXK_ESCAPE; break; - case VK_PRIOR: id = WXK_PRIOR; break; - case VK_NEXT : id = WXK_NEXT; break; - case VK_END: id = WXK_END; break; - case VK_HOME : id = WXK_HOME; break; - case VK_LEFT : id = WXK_LEFT; break; - case VK_UP: id = WXK_UP; break; - case VK_RIGHT: id = WXK_RIGHT; break; - case VK_DOWN : id = WXK_DOWN; break; - case VK_SELECT: id = WXK_SELECT; break; - case VK_PRINT: id = WXK_PRINT; break; - case VK_EXECUTE: id = WXK_EXECUTE; break; - case VK_INSERT: id = WXK_INSERT; break; - case VK_DELETE: id = WXK_DELETE; break; - case VK_HELP : id = WXK_HELP; break; - case VK_NUMPAD0: id = WXK_NUMPAD0; break; - case VK_NUMPAD1: id = WXK_NUMPAD1; break; - case VK_NUMPAD2: id = WXK_NUMPAD2; break; - case VK_NUMPAD3: id = WXK_NUMPAD3; break; - case VK_NUMPAD4: id = WXK_NUMPAD4; break; - case VK_NUMPAD5: id = WXK_NUMPAD5; break; - case VK_NUMPAD6: id = WXK_NUMPAD6; break; - 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 VK_ADD: id = WXK_ADD; break; - case VK_SUBTRACT: id = WXK_SUBTRACT; break; - case VK_DECIMAL: id = WXK_DECIMAL; break; - case VK_DIVIDE: id = WXK_DIVIDE; break; - case VK_F1: id = WXK_F1; break; - case VK_F2: id = WXK_F2; break; - case VK_F3: id = WXK_F3; break; - case VK_F4: id = WXK_F4; break; - case VK_F5: id = WXK_F5; break; - case VK_F6: id = WXK_F6; break; - case VK_F7: id = WXK_F7; break; - case VK_F8: id = WXK_F8; break; - case VK_F9: id = WXK_F9; break; - case VK_F10: id = WXK_F10; break; - case VK_F11: id = WXK_F11; break; - case VK_F12: id = WXK_F12; break; - case VK_F13: id = WXK_F13; break; - case VK_F14: id = WXK_F14; break; - case VK_F15: id = WXK_F15; break; - case VK_F16: id = WXK_F16; break; - case VK_F17: id = WXK_F17; break; - case VK_F18: id = WXK_F18; break; - case VK_F19: id = WXK_F19; break; - case VK_F20: id = WXK_F20; break; - case VK_F21: id = WXK_F21; break; - case VK_F22: id = WXK_F22; break; - case VK_F23: id = WXK_F23; break; - case VK_F24: id = WXK_F24; break; - case VK_NUMLOCK: id = WXK_NUMLOCK; break; - case VK_SCROLL: id = WXK_SCROLL; break; - default: - { - return 0; - } + case VK_CANCEL: id = WXK_CANCEL; break; + case VK_BACK: id = WXK_BACK; break; + case VK_TAB: id = WXK_TAB; break; + case VK_CLEAR: id = WXK_CLEAR; break; + case VK_RETURN: id = WXK_RETURN; break; + case VK_SHIFT: id = WXK_SHIFT; break; + case VK_CONTROL: id = WXK_CONTROL; break; + case VK_MENU : id = WXK_MENU; break; + case VK_PAUSE: id = WXK_PAUSE; break; + case VK_SPACE: id = WXK_SPACE; break; + case VK_ESCAPE: id = WXK_ESCAPE; break; + case VK_PRIOR: id = WXK_PRIOR; break; + case VK_NEXT : id = WXK_NEXT; break; + case VK_END: id = WXK_END; break; + case VK_HOME : id = WXK_HOME; break; + case VK_LEFT : id = WXK_LEFT; break; + case VK_UP: id = WXK_UP; break; + case VK_RIGHT: id = WXK_RIGHT; break; + case VK_DOWN : id = WXK_DOWN; break; + case VK_SELECT: id = WXK_SELECT; break; + case VK_PRINT: id = WXK_PRINT; break; + case VK_EXECUTE: id = WXK_EXECUTE; break; + case VK_INSERT: id = WXK_INSERT; break; + case VK_DELETE: id = WXK_DELETE; break; + case VK_HELP : id = WXK_HELP; break; + case VK_NUMPAD0: id = WXK_NUMPAD0; break; + case VK_NUMPAD1: id = WXK_NUMPAD1; break; + case VK_NUMPAD2: id = WXK_NUMPAD2; break; + case VK_NUMPAD3: id = WXK_NUMPAD3; break; + case VK_NUMPAD4: id = WXK_NUMPAD4; break; + case VK_NUMPAD5: id = WXK_NUMPAD5; break; + case VK_NUMPAD6: id = WXK_NUMPAD6; break; + 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_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; + case VK_F4: id = WXK_F4; break; + case VK_F5: id = WXK_F5; break; + case VK_F6: id = WXK_F6; break; + case VK_F7: id = WXK_F7; break; + case VK_F8: id = WXK_F8; break; + case VK_F9: id = WXK_F9; break; + case VK_F10: id = WXK_F10; break; + case VK_F11: id = WXK_F11; break; + case VK_F12: id = WXK_F12; break; + case VK_F13: id = WXK_F13; break; + case VK_F14: id = WXK_F14; break; + case VK_F15: id = WXK_F15; break; + case VK_F16: id = WXK_F16; break; + case VK_F17: id = WXK_F17; break; + case VK_F18: id = WXK_F18; break; + case VK_F19: id = WXK_F19; break; + case VK_F20: id = WXK_F20; break; + case VK_F21: id = WXK_F21; break; + case VK_F22: id = WXK_F22; break; + case VK_F23: id = WXK_F23; break; + case VK_F24: id = WXK_F24; break; + case VK_NUMLOCK: id = WXK_NUMLOCK; break; + case VK_SCROLL: id = WXK_SCROLL; break; + default: + id = 0; } + return id; } @@ -3330,11 +4254,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; @@ -3381,6 +4305,73 @@ wxWindow *wxGetActiveWindow() return NULL; } +extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) +{ + HWND hwnd = (HWND)hWnd; + + // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set + // by code in msw/radiobox.cpp), for all the others we just search up the + // window hierarchy + wxWindow *win = (wxWindow *)NULL; + if ( hwnd ) + { + win = wxFindWinFromHandle((WXHWND)hwnd); + if ( !win ) + { + // 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, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON ) + { + win = (wxWindow *)::GetWindowLong(hwnd, GWL_USERDATA); + } + //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 ) + { + win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd); + } +#endif // wxUSE_SPINCTRL + +#endif // Win32 + } + } + + while ( hwnd && !win ) + { + // 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 +#ifndef __WXMICROWIN__ + if ( ::GetWindow(hwnd, GW_OWNER) ) + { + // it's a dialog box, don't go upwards + break; + } +#endif + + 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; @@ -3394,17 +4385,24 @@ void wxSetKeyboardHook(bool doIt) { wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance()); wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(), + #if defined(__WIN32__) && !defined(__TWIN32__) - GetCurrentThreadId()); + GetCurrentThreadId() // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right? #else - GetCurrentTask()); + GetCurrentTask() #endif + ); } else { UnhookWindowsHookEx(wxTheKeyboardHook); + + // 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 } } @@ -3414,8 +4412,8 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) DWORD hiWord = HIWORD(lParam); if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) ) { - int id; - if ( (id = wxCharCodeMSWToWX(wParam)) != 0 ) + int id = wxCharCodeMSWToWX(wParam); + if ( id != 0 ) { wxKeyEvent event(wxEVT_CHAR_HOOK); if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) @@ -3423,28 +4421,36 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) event.m_eventObject = NULL; event.m_keyCode = id; - /* begin Albert's fix for control and shift key 26.5 */ - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - /* end Albert's fix for control and shift key 26.5 */ + event.m_shiftDown = wxIsShiftDown(); + event.m_controlDown = wxIsCtrlDown(); event.SetTimestamp(s_currentMsg.time); wxWindow *win = wxGetActiveWindow(); + wxEvtHandler *handler; if ( win ) { - if ( win->GetEventHandler()->ProcessEvent(event) ) - return 1; + handler = win->GetEventHandler(); + event.SetId(win->GetId()); } else { - if ( wxTheApp && wxTheApp->ProcessEvent(event) ) - return 1; + handler = wxTheApp; + event.SetId(-1); + } + + if ( handler && handler->ProcessEvent(event) ) + { + // processed + return 1; } } } + return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam); } +#endif // !__WXMICROWIN__ + #ifdef __WXDEBUG__ const char *wxGetMessageName(int message) { @@ -3576,6 +4582,7 @@ const char *wxGetMessageName(int message) case 0x0207: return "WM_MBUTTONDOWN"; case 0x0208: return "WM_MBUTTONUP"; case 0x0209: return "WM_MBUTTONDBLCLK"; + case 0x020A: return "WM_MOUSEWHEEL"; case 0x0210: return "WM_PARENTNOTIFY"; case 0x0211: return "WM_ENTERMENULOOP"; case 0x0212: return "WM_EXITMENULOOP"; @@ -3863,3 +4870,90 @@ 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 + TEXTMETRIC tm; + HWND hwnd = GetHwndOf(win); + HDC hdc = ::GetDC(hwnd); + +#if !wxDIALOG_UNIT_COMPATIBILITY + // and select the current font into it + HFONT hfont = GetHfontOf(win->GetFont()); + if ( hfont ) + { + hfont = (HFONT)::SelectObject(hdc, hfont); + } +#endif + + // finally retrieve the text metrics from it + GetTextMetrics(hdc, &tm); + +#if !wxDIALOG_UNIT_COMPATIBILITY + // and clean up + if ( hfont ) + { + (void)::SelectObject(hdc, hfont); + } +#endif + + ::ReleaseDC(hwnd, hdc); + + return tm; +} + +// Find the wxWindow at the current mouse position, returning the mouse +// position. +wxWindow* wxFindWindowAtPointer(wxPoint& WXUNUSED(pt)) +{ + return wxFindWindowAtPoint(wxGetMousePosition()); +} + +wxWindow* wxFindWindowAtPoint(const wxPoint& pt) +{ + POINT pt2; + pt2.x = pt.x; + pt2.y = pt.y; + HWND hWndHit = ::WindowFromPoint(pt2); + + wxWindow* win = wxFindWinFromHandle((WXHWND) hWndHit) ; + HWND hWnd = hWndHit; + + // Try to find a window with a wxWindow associated with it + while (!win && (hWnd != 0)) + { + hWnd = ::GetParent(hWnd); + win = wxFindWinFromHandle((WXHWND) hWnd) ; + } + return win; +} + +// Get the current mouse position. +wxPoint wxGetMousePosition() +{ + POINT pt; + GetCursorPos( & pt ); + return wxPoint(pt.x, pt.y); +} +