X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3f7bc32b539472f7aa577ffa140e287b0dc4c90d..eaac8805cd0fc233aeb0fc40a31bf8d8e03bf59c:/src/msw/window.cpp?ds=sidebyside diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 99ebca9e65..fb93646628 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -46,11 +46,12 @@ #include "wx/listbox.h" #include "wx/button.h" #include "wx/msgdlg.h" + #include "wx/settings.h" #include #endif -#if wxUSE_OWNER_DRAWN +#if wxUSE_OWNER_DRAWN #include "wx/ownerdrw.h" #endif @@ -71,6 +72,10 @@ #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" @@ -79,7 +84,7 @@ #include -#ifndef __GNUWIN32_OLD__ +#if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__) #include #include #endif @@ -88,7 +93,7 @@ #include #endif -#if !defined(__GNUWIN32_OLD__) && !defined(__TWIN32__) +#if (!defined(__GNUWIN32_OLD__) && !defined(__TWIN32__)) || defined(__CYGWIN10__) #ifdef __WIN95__ #include #endif @@ -98,6 +103,24 @@ #endif #endif +// This didn't appear in mingw until 2.95.2 +#ifndef SIF_TRACKPOS +#define SIF_TRACKPOS 16 +#endif + +#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 // --------------------------------------------------------------------------- @@ -129,9 +152,8 @@ wxWindow *wxFindWinFromHandle(WXHWND hWnd); // mouse clicks static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags); -// get the current state of SHIFT/CTRL keys -extern inline bool wxIsShiftDown() { return (GetKeyState(VK_SHIFT) & 0x100) != 0; } -extern inline bool wxIsCtrlDown() { return (GetKeyState(VK_CONTROL) & 0x100) != 0; } +// get the text metrics for the current font +static TEXTMETRIC wxGetTextMetrics(const wxWindow *win); // --------------------------------------------------------------------------- // event tables @@ -158,7 +180,7 @@ END_EVENT_TABLE() // Find an item given the MS Windows id wxWindow *wxWindow::FindItem(long id) const { - wxControl *item = wxDynamicCast(this, wxControl); + wxControl *item = wxDynamicThisCast(this, wxControl); if ( item ) { // i it we or one of our "internal" children? @@ -267,18 +289,33 @@ wxWindow::~wxWindow() MSWDetachWindowMenu(); - if ( m_parent ) - m_parent->RemoveChild(this); + // VS: make sure there's no wxFrame with last focus set to us: + for (wxWindow *win = GetParent(); win; win = win->GetParent()) + { + wxFrame *frame = wxDynamicCast(win, wxFrame); + if ( frame ) + { + if ( frame->GetLastFocus() == this ) + frame->SetLastFocus((wxWindow*)NULL); + break; + } + } + // VS: destroy children first and _then_ detach *this from its parent. + // If we'd do it the other way around, children wouldn't be able + // find their parent frame (see above). DestroyChildren(); + if ( m_parent ) + m_parent->RemoveChild(this); + if ( m_hWnd ) { // VZ: test temp removed to understand what really happens here //if (::IsWindow(GetHwnd())) { if ( !::DestroyWindow(GetHwnd()) ) - wxLogLastError("DestroyWindow"); + wxLogLastError(wxT("DestroyWindow")); } // remove hWnd <-> wxWindow association @@ -303,12 +340,17 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, DWORD msflags = 0; if ( style & wxBORDER ) msflags |= WS_BORDER; +/* Not appropriate for non-frame/dialog windows, and + may clash with other window styles. if ( style & wxTHICK_FRAME ) msflags |= WS_THICKFRAME; - +*/ + //msflags |= WS_CHILD /* | WS_CLIPSIBLINGS */ | WS_VISIBLE; msflags |= WS_CHILD | WS_VISIBLE; if ( style & wxCLIP_CHILDREN ) msflags |= WS_CLIPCHILDREN; + if ( style & wxCLIP_SIBLINGS ) + msflags |= WS_CLIPSIBLINGS; bool want3D; WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D); @@ -329,12 +371,10 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, DLGC_WANTTAB | DLGC_WANTMESSAGE; } - MSWCreate(m_windowId, parent, wxCanvasClassName, this, NULL, - pos.x, pos.y, - WidthDefault(size.x), HeightDefault(size.y), - msflags, NULL, exStyle); - - return TRUE; + return MSWCreate(m_windowId, parent, wxCanvasClassName, this, NULL, + pos.x, pos.y, + WidthDefault(size.x), HeightDefault(size.y), + msflags, NULL, exStyle); } // --------------------------------------------------------------------------- @@ -354,7 +394,7 @@ wxWindow *wxWindowBase::FindFocus() HWND hWnd = ::GetFocus(); if ( hWnd ) { - return wxFindWinFromHandle((WXHWND) hWnd); + return wxGetWindowFromHWND((WXHWND)hWnd); } return NULL; @@ -369,6 +409,10 @@ 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 ) { @@ -377,6 +421,7 @@ bool wxWindow::Enable(bool enable) node = node->GetNext(); } +#endif // 0 return TRUE; } @@ -401,7 +446,11 @@ bool wxWindow::Show(bool show) // Raise the window to the top of the Z order void wxWindow::Raise() { +#ifdef __WIN16__ ::BringWindowToTop(GetHwnd()); +#else // Win32 + ::SetForegroundWindow(GetHwnd()); +#endif } // Lower the window to the bottom of the Z order @@ -468,20 +517,20 @@ bool wxWindow::SetCursor(const wxCursor& cursor) return FALSE; } - wxASSERT_MSG( m_cursor.Ok(), - wxT("cursor must be valid after call to the base version")); + if ( m_cursor.Ok() ) + { + HWND hWnd = GetHwnd(); - 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; - ::GetWindowRect(hWnd, &rect); - - if ( ::PtInRect(&rect, point) && !wxIsBusy() ) - ::SetCursor(GetHcursorOf(m_cursor)); + if ( ::PtInRect(&rect, point) && !wxIsBusy() ) + ::SetCursor(GetHcursorOf(m_cursor)); + } return TRUE; } @@ -853,7 +902,8 @@ 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 @@ -958,7 +1008,7 @@ void wxWindow::SetupColours() SetBackgroundColour(GetParent()->GetBackgroundColour()); } -void wxWindow::OnIdle(wxIdleEvent& event) +void wxWindow::OnIdle(wxIdleEvent& WXUNUSED(event)) { // Check if we need to send a LEAVE event if ( m_mouseInWindow ) @@ -978,6 +1028,12 @@ void wxWindow::OnIdle(wxIdleEvent& event) state |= MK_SHIFT; if ( wxIsCtrlDown() ) state |= MK_CONTROL; + if ( GetKeyState( VK_LBUTTON ) ) + state |= MK_LBUTTON; + if ( GetKeyState( VK_MBUTTON ) ) + state |= MK_MBUTTON; + if ( GetKeyState( VK_RBUTTON ) ) + state |= MK_RBUTTON; wxMouseEvent event(wxEVT_LEAVE_WINDOW); InitMouseEvent(event, pt.x, pt.y, state); @@ -990,7 +1046,7 @@ void wxWindow::OnIdle(wxIdleEvent& event) } // Set this window to be the child of 'parent'. -bool wxWindow::Reparent(wxWindow *parent) +bool wxWindow::Reparent(wxWindowBase *parent) { if ( !wxWindowBase::Reparent(parent) ) return FALSE; @@ -1085,8 +1141,14 @@ void wxWindow::DoGetSize(int *x, int *y) const { HWND hWnd = GetHwnd(); RECT rect; - GetWindowRect(hWnd, &rect); - +#ifdef __WIN16__ + ::GetWindowRect(hWnd, &rect); +#else + if ( !::GetWindowRect(hWnd, &rect) ) + { + wxLogLastError(_T("GetWindowRect")); + } +#endif if ( x ) *x = rect.right - rect.left; if ( y ) @@ -1120,11 +1182,14 @@ void wxWindow::DoGetPosition(int *x, int *y) const ::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). - wxPoint pt(parent->GetClientAreaOrigin()); - point.x -= pt.x; - point.y -= pt.y; + 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 ) @@ -1183,7 +1248,7 @@ void wxWindow::DoMoveWindow(int x, int y, int width, int height) { if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) ) { - wxLogLastError("MoveWindow"); + wxLogLastError(wxT("MoveWindow")); } } @@ -1322,26 +1387,18 @@ void wxWindow::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) int wxWindow::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 { - 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, @@ -1431,6 +1488,23 @@ void wxWindow::GetCaretPos(int *x, int *y) const // popup menu // --------------------------------------------------------------------------- +// 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 wxWindow::DoPopupMenu(wxMenu *menu, int x, int y) { menu->SetInvokingWindow(this); @@ -1444,7 +1518,16 @@ bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y) ::ClientToScreen(hWnd, &point); wxCurrentPopupMenu = menu; ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL); - wxYield(); + + // 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); @@ -1539,12 +1622,23 @@ 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 { - wxPanel *panel = wxDynamicCast(this, wxPanel); + wxPanel *panel = wxDynamicThisCast(this, wxPanel); wxButton *btn = NULL; if ( panel ) { @@ -1622,7 +1716,10 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) #endif // 0 if ( ::IsDialogMessage(GetHwnd(), msg) ) + { + // IsDialogMessage() did something... return TRUE; + } } #if wxUSE_TOOLTIPS @@ -1825,7 +1922,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) break; case WM_MOVE: - processed = HandleMove(LOWORD(lParam), HIWORD(lParam)); + processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; case WM_SIZE: @@ -1866,17 +1963,21 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) break; case WM_MOUSEMOVE: - { - short x = LOWORD(lParam); - short y = HIWORD(lParam); + processed = HandleMouseMove(GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + wParam); + break; - processed = HandleMouseMove(x, y, wParam); - } - break; +#if wxUSE_MOUSEWHEEL + case WM_MOUSEWHEEL: + processed = HandleMouseWheel(wParam, lParam); + break; +#endif case WM_LBUTTONDOWN: // set focus to this window - SetFocus(); + if (AcceptsFocus()) + SetFocus(); // fall through @@ -1888,12 +1989,10 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDBLCLK: - { - short x = LOWORD(lParam); - short y = HIWORD(lParam); - - processed = HandleMouseEvent(message, x, y, wParam); - } + processed = HandleMouseEvent(message, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), + wParam); break; case MM_JOY1MOVE: @@ -1904,12 +2003,10 @@ 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; case WM_SYSCOMMAND: @@ -2149,6 +2246,55 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) rc.result = TRUE; } break; + +#ifdef __WIN32__ + case WM_HELP: + { + HELPINFO* info = (HELPINFO*) lParam; + // Don't yet process menu help events, just windows + if (info->iContextType == HELPINFO_WINDOW) + { + wxWindow* subjectOfHelp = this; + bool eventProcessed = FALSE; + while (subjectOfHelp && !eventProcessed) + { + 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__ } if ( !processed ) @@ -2165,7 +2311,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) // Dialog window proc LONG APIENTRY _EXPORT -wxDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +wxDlgProc(HWND WXUNUSED(hWnd), UINT message, WPARAM WXUNUSED(wParam), LPARAM WXUNUSED(lParam)) { if ( message == WM_INITDIALOG ) { @@ -2241,24 +2387,25 @@ void wxWindow::MSWDetachWindowMenu() { 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(wxT("GetMenuString")); continue; } - if ( wxStrcmp(buf, wxT("&Window")) == 0 ) + if ( wxStrcmp(buf, _("&Window")) == 0 ) { - RemoveMenu(hMenu, i, MF_BYPOSITION); + if ( !::RemoveMenu(hMenu, i, MF_BYPOSITION) ) + { + wxLogLastError(wxT("RemoveMenu")); + } break; } @@ -2269,7 +2416,7 @@ void wxWindow::MSWDetachWindowMenu() bool wxWindow::MSWCreate(int id, wxWindow *parent, const wxChar *wclass, - wxWindow *wx_win, + wxWindow *WXUNUSED(wx_win), const wxChar *title, int x, int y, @@ -2295,30 +2442,45 @@ bool wxWindow::MSWCreate(int id, height1 = parent_rect.bottom - parent_rect.top; } - if ( x > -1 ) x1 = x; - if ( y > -1 ) y1 = y; - if ( width > -1 ) width1 = width; - if ( height > -1 ) height1 = height; - - // Unfortunately this won't work in WIN16. Unless perhaps - // we define WS_EX_CONTROLPARENT ourselves? -#ifndef __WIN16__ + if ( x != -1 ) + x1 = x; + if ( y != -1 ) + y1 = y; + if ( width != -1 ) + width1 = width; + if ( height != -1 ) + height1 = height; + + // unfortunately, setting WS_EX_CONTROLPARENT only for some windows in the + // hierarchy with several embedded panels (and not all of them) causes the + // program to hang during the next call to IsDialogMessage() due to the bug + // in this function (at least in Windows NT 4.0, it seems to work ok in + // Win2K) +#if 0 // if we have wxTAB_TRAVERSAL style, we want WS_EX_CONTROLPARENT or // IsDialogMessage() won't work for us if ( GetWindowStyleFlag() & wxTAB_TRAVERSAL ) { extendedStyle |= WS_EX_CONTROLPARENT; } -#endif +#endif // 0 - HWND hParent = (HWND)NULL; - if ( parent ) - hParent = (HWND) parent->GetHWND(); + HWND hParent = parent ? GetHwndOf(parent) : NULL; wxWndHook = this; if ( dialog_template ) { + // for the dialogs without wxDIALOG_NO_PARENT style, use the top level + // app window as parent - this avoids creating modal dialogs without + // parent + if ( !hParent && !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT) ) + { + wxWindow *winTop = wxTheApp->GetTopWindow(); + if ( winTop ) + hParent = GetHwndOf(winTop); + } + m_hWnd = (WXHWND)::CreateDialog(wxGetInstance(), dialog_template, hParent, @@ -2326,12 +2488,44 @@ bool wxWindow::MSWCreate(int id, if ( m_hWnd == 0 ) { - wxLogError(_("Can't find dummy dialog template!\n" - "Check resource include path for finding wx.rc.")); + wxLogError(_("Can't find dialog template '%s'!\nCheck resource include path for finding wx.rc."), + dialog_template); return FALSE; } + if ( extendedStyle != 0 ) + { + ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, extendedStyle); + ::SetWindowPos(GetHwnd(), NULL, 0, 0, 0, 0, + SWP_NOSIZE | + SWP_NOMOVE | + SWP_NOZORDER | + SWP_NOACTIVATE); + } + +#if defined(__WIN95__) + // For some reason, the system menu is activated when we use the + // WS_EX_CONTEXTHELP style, so let's set a reasonable icon + if (extendedStyle & WS_EX_CONTEXTHELP) + { + wxFrame *winTop = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame); + if ( winTop ) + { + wxIcon icon = winTop->GetIcon(); + if ( icon.Ok() ) + { + ::SendMessage(GetHwnd(), WM_SETICON, + (WPARAM)TRUE, + (LPARAM)GetHiconOf(icon)); + } + } + } +#endif // __WIN95__ + + + // JACS: is the following still necessary? The above seems to work. + // ::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 ) @@ -2349,12 +2543,15 @@ bool wxWindow::MSWCreate(int id, wxLogLastError(wxT("MoveWindow")); } } - else + else // creating a normal window, not a dialog { int controlId = 0; if ( style & WS_CHILD ) controlId = id; + if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS ) + style |= WS_CLIPSIBLINGS; + wxString className(wclass); if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE ) { @@ -2373,8 +2570,7 @@ bool wxWindow::MSWCreate(int id, if ( !m_hWnd ) { - wxLogError(_("Can't create window of class %s!\n" - "Possible Windows 3.x compatibility problem?"), + wxLogError(_("Can't create window of class %s!\nPossible Windows 3.x compatibility problem?"), wclass); return FALSE; @@ -2382,6 +2578,7 @@ bool wxWindow::MSWCreate(int id, } wxWndHook = NULL; + #ifdef __WXDEBUG__ wxNode* node = wxWinHandleList->Member(this); if (node) @@ -2392,9 +2589,12 @@ bool wxWindow::MSWCreate(int id, wxLogError(wxT("A second HWND association is being added for the same window!")); } } -#endif +#endif // Debug + wxAssociateWinWithHandle((HWND) m_hWnd, this); + SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT)); + return TRUE; } @@ -2428,8 +2628,6 @@ bool wxWindow::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) if ( child->MSWOnNotify(idCtrl, lParam, result) ) { return TRUE; - - break; } node = node->GetNext(); @@ -2503,7 +2701,7 @@ bool wxWindow::HandleEndSession(bool endSession, long logOff) // window creation/destruction // --------------------------------------------------------------------------- -bool wxWindow::HandleCreate(WXLPCREATESTRUCT cs, bool *mayCreate) +bool wxWindow::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate) { // TODO: should generate this event from WM_NCCREATE wxWindowCreateEvent event(this); @@ -2613,7 +2811,7 @@ bool wxWindow::HandleKillFocus(WXHWND WXUNUSED(hwnd)) // miscellaneous // --------------------------------------------------------------------------- -bool wxWindow::HandleShow(bool show, int status) +bool wxWindow::HandleShow(bool show, int WXUNUSED(status)) { wxShowEvent event(GetId(), show); event.m_eventObject = this; @@ -2636,10 +2834,13 @@ bool wxWindow::HandleDropFiles(WXWPARAM wParam) DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint); // Get the total number of files dropped - WORD gwFilesDropped = (WORD)DragQueryFile ((HDROP)hFilesInfo, - (UINT)-1, - (LPSTR)0, - (UINT)0); + WORD gwFilesDropped = (WORD)::DragQueryFile + ( + (HDROP)hFilesInfo, + (UINT)-1, + (LPTSTR)0, + (UINT)0 + ); wxString *files = new wxString[gwFilesDropped]; int wIndex; @@ -2661,34 +2862,75 @@ bool wxWindow::HandleDropFiles(WXWPARAM wParam) return rc; } -bool wxWindow::HandleSetCursor(WXHWND hWnd, +bool wxWindow::HandleSetCursor(WXHWND WXUNUSED(hWnd), short nHitTest, int WXUNUSED(mouseMsg)) { // 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; - bool isBusy = wxIsBusy(); - if ( m_cursor.Ok() ) + + // 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(m_cursor); + hcursor = GetHcursorOf(event.GetCursor()); } - if ( !GetParent() ) + if ( !hcursor ) { - if ( isBusy ) + 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 = wxGetCurrentBusyCursor(); + hcursor = GetHcursorOf(m_cursor); } - else if ( !hcursor ) + + if ( !GetParent() ) { - const wxCursor *cursor = wxGetGlobalCursor(); - if ( cursor && cursor->Ok() ) + if ( isBusy ) + { + hcursor = wxGetCurrentBusyCursor(); + } + else if ( !hcursor ) { - hcursor = GetHcursorOf(*cursor); + const wxCursor *cursor = wxGetGlobalCursor(); + if ( cursor && cursor->Ok() ) + { + hcursor = GetHcursorOf(*cursor); + } } } } @@ -2700,11 +2942,9 @@ bool wxWindow::HandleSetCursor(WXHWND hWnd, // cursor set, stop here return TRUE; } - else - { - // pass up the window chain - return FALSE; - } + + // pass up the window chain + return FALSE; } // --------------------------------------------------------------------------- @@ -2722,19 +2962,20 @@ bool wxWindow::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); - // prepare to call OnDrawItem() - wxDC dc; - dc.SetHDC((WXHDC)pDrawStruct->hDC, FALSE); + // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent + // the DC from being released + wxDCTemp dc((WXHDC)pDrawStruct->hDC); wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top, pDrawStruct->rcItem.right - pDrawStruct->rcItem.left, pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top); return pMenuItem->OnDrawItem - ( - dc, rect, - (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction, - (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState - ); + ( + dc, + rect, + (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction, + (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState + ); } wxWindow *item = FindItem(id); @@ -2811,12 +3052,12 @@ bool wxWindow::HandleCtlColor(WXHBRUSH *brush, } // Define for each class of dialog and control -WXHBRUSH wxWindow::OnCtlColor(WXHDC hDC, - WXHWND hWnd, - WXUINT nCtlColor, - WXUINT message, - WXWPARAM wParam, - WXLPARAM lParam) +WXHBRUSH wxWindow::OnCtlColor(WXHDC WXUNUSED(hDC), + WXHWND WXUNUSED(hWnd), + WXUINT WXUNUSED(nCtlColor), + WXUINT WXUNUSED(message), + WXWPARAM WXUNUSED(wParam), + WXLPARAM WXUNUSED(lParam)) { return (WXHBRUSH)0; } @@ -2866,9 +3107,9 @@ bool wxWindow::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 @@ -2886,15 +3127,24 @@ bool wxWindow::HandlePaint() return GetEventHandler()->ProcessEvent(event); } +// Can be called from an application's OnPaint handler +void wxWindow::OnPaint(wxPaintEvent& event) +{ + HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject()); + if (hDC != 0) + { + MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0); + } +} + bool wxWindow::HandleEraseBkgnd(WXHDC hdc) { // Prevents flicker when dragging if ( ::IsIconic(GetHwnd()) ) return TRUE; - wxDC dc; + wxDCTemp dc(hdc); - dc.SetHDC(hdc); dc.SetWindow(this); dc.BeginDrawing(); @@ -2903,8 +3153,9 @@ 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; } @@ -2919,7 +3170,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(); @@ -2999,6 +3250,25 @@ bool wxWindow::HandleGetMinMaxInfo(void *mmInfo) return rc; } +// generate an artificial resize event +/* FUNCTION IS NOW A MEMBER OF wxFrame - gt +void wxWindow::SendSizeEvent() +{ + RECT r; +#ifdef __WIN16__ + ::GetWindowRect(GetHwnd(), &r); +#else + if ( !::GetWindowRect(GetHwnd(), &r) ) + { + wxLogLastError(_T("GetWindowRect")); + } +#endif + + (void)::PostMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED, + MAKELPARAM(r.right - r.left, r.bottom - r.top)); +} +*/ + // --------------------------------------------------------------------------- // command messages // --------------------------------------------------------------------------- @@ -3048,11 +3318,22 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) return GetEventHandler()->ProcessEvent(event); } +#if wxUSE_SPINCTRL + 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 wxWindow::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam)) { // 4 bits are reserved switch ( wParam & 0xFFFFFFF0 ) @@ -3080,6 +3361,7 @@ void wxWindow::InitMouseEvent(wxMouseEvent& event, int x, int y, WXUINT flags) 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; @@ -3137,7 +3419,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; @@ -3148,6 +3430,49 @@ bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags) return HandleMouseEvent(WM_MOUSEMOVE, x, y, flags); } + +bool wxWindow::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 // --------------------------------------------------------------------------- @@ -3184,7 +3509,7 @@ wxKeyEvent wxWindow::CreateKeyEvent(wxEventType evType, // isASCII is TRUE only when we're called from WM_CHAR handler and not from // WM_KEYDOWN one -bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII) +bool wxWindow::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) { bool ctrlDown = FALSE; @@ -3237,7 +3562,7 @@ bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII) return FALSE; } -bool wxWindow::HandleKeyDown(WXWORD wParam, WXLPARAM lParam) +bool wxWindow::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam) { int id = wxCharCodeMSWToWX(wParam); @@ -3259,7 +3584,7 @@ bool wxWindow::HandleKeyDown(WXWORD wParam, WXLPARAM lParam) return FALSE; } -bool wxWindow::HandleKeyUp(WXWORD wParam, WXLPARAM lParam) +bool wxWindow::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam) { int id = wxCharCodeMSWToWX(wParam); @@ -3409,11 +3734,34 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam, break; case SB_THUMBPOSITION: - event.m_eventType = wxEVT_SCROLLWIN_THUMBRELEASE; - break; - case SB_THUMBTRACK: - event.m_eventType = wxEVT_SCROLLWIN_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: @@ -3461,80 +3809,82 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y, const 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_MULTIPLY; break; + case 0xBB: // VK_OEM_PLUS + case VK_ADD: id = WXK_ADD; break; + case 0xBD: // VK_OEM_MINUS + case VK_SUBTRACT: id = WXK_SUBTRACT; break; + case 0xBE: // VK_OEM_PERIOD + case VK_DECIMAL: id = WXK_DECIMAL; break; + case VK_DIVIDE: id = WXK_DIVIDE; break; + case VK_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; } @@ -3638,24 +3988,37 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) win = wxFindWinFromHandle((WXHWND)hwnd); if ( !win ) { - // the radiobox pointer is stored in GWL_USERDATA only under Win32 + // all these hacks only work under Win32 anyhow #ifdef __WIN32__ + +#if wxUSE_RADIOBOX // native radiobuttons return DLGC_RADIOBUTTON here and for any // wxWindow class which overrides WM_GETDLGCODE processing to // do it as well, win would be already non NULL - if ( ::SendMessage((HWND)hwnd, WM_GETDLGCODE, - 0, 0) & DLGC_RADIOBUTTON ) + if ( ::SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON ) { win = (wxWindow *)::GetWindowLong(hwnd, GWL_USERDATA); } - else + //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 + if ( !win ) + { + win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd); + } +#endif // wxUSE_SPINCTRL + #endif // Win32 + + if ( !win ) { // hwnd is not a wxWindow, try its parent next below hwnd = ::GetParent(hwnd); } } - //else: it's a wxRadioButton, not a radiobutton from wxRadioBox } while ( hwnd && !win ) @@ -3692,9 +4055,10 @@ void wxSetKeyboardHook(bool doIt) else { UnhookWindowsHookEx(wxTheKeyboardHook); - // avoids mingw warning about statement with no effect (FreeProcInstance + + // avoids warning about statement with no effect (FreeProcInstance // doesn't do anything under Win32) -#ifndef __GNUC__ +#if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(__NT__) && !defined(__GNUWIN32__) FreeProcInstance(wxTheKeyboardHookProc); #endif } @@ -3874,6 +4238,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"; @@ -4180,3 +4545,70 @@ static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flag win->ScreenToClient(x, y); } + +static TEXTMETRIC wxGetTextMetrics(const wxWindow *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); +} +