+// old-style file manager drag&drop support: we retain the old-style
+// DragAcceptFiles in parallel with SetDropTarget.
+void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept))
+{
+#ifndef __WXWINCE__
+ HWND hWnd = GetHwnd();
+ if ( hWnd )
+ {
+ AdjustStaticBoxZOrder(GetParent());
+ ::DragAcceptFiles(hWnd, (BOOL)accept);
+ }
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// tooltips
+// ----------------------------------------------------------------------------
+
+#if wxUSE_TOOLTIPS
+
+void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
+{
+ wxWindowBase::DoSetToolTip(tooltip);
+
+ if ( m_tooltip )
+ m_tooltip->SetWindow((wxWindow *)this);
+}
+
+#endif // wxUSE_TOOLTIPS
+
+// ---------------------------------------------------------------------------
+// moving and resizing
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::IsSizeDeferred() const
+{
+#if USE_DEFERRED_SIZING
+ if ( m_pendingPosition != wxDefaultPosition ||
+ m_pendingSize != wxDefaultSize )
+ return true;
+#endif // USE_DEFERRED_SIZING
+
+ return false;
+}
+
+// Get total size
+void wxWindowMSW::DoGetSize(int *x, int *y) const
+{
+#if USE_DEFERRED_SIZING
+ // if SetSize() had been called at wx level but not realized at Windows
+ // level yet (i.e. EndDeferWindowPos() not called), we still should return
+ // the new and not the old position to the other wx code
+ if ( m_pendingSize != wxDefaultSize )
+ {
+ if ( x )
+ *x = m_pendingSize.x;
+ if ( y )
+ *y = m_pendingSize.y;
+ }
+ else // use current size
+#endif // USE_DEFERRED_SIZING
+ {
+ RECT rect = wxGetWindowRect(GetHwnd());
+
+ if ( x )
+ *x = rect.right - rect.left;
+ if ( y )
+ *y = rect.bottom - rect.top;
+ }
+}
+
+// Get size *available for subwindows* i.e. excluding menu bar etc.
+void wxWindowMSW::DoGetClientSize(int *x, int *y) const
+{
+#if USE_DEFERRED_SIZING
+ if ( m_pendingSize != wxDefaultSize )
+ {
+ // we need to calculate the client size corresponding to pending size
+ RECT rect;
+ rect.left = m_pendingPosition.x;
+ rect.top = m_pendingPosition.y;
+ rect.right = rect.left + m_pendingSize.x;
+ rect.bottom = rect.top + m_pendingSize.y;
+
+ ::SendMessage(GetHwnd(), WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
+
+ if ( x )
+ *x = rect.right - rect.left;
+ if ( y )
+ *y = rect.bottom - rect.top;
+ }
+ else
+#endif // USE_DEFERRED_SIZING
+ {
+ RECT rect = wxGetClientRect(GetHwnd());
+
+ if ( x )
+ *x = rect.right;
+ if ( y )
+ *y = rect.bottom;
+ }
+}
+
+void wxWindowMSW::DoGetPosition(int *x, int *y) const
+{
+ wxWindow * const parent = GetParent();
+
+ wxPoint pos;
+ if ( m_pendingPosition != wxDefaultPosition )
+ {
+ pos = m_pendingPosition;
+ }
+ else // use current position
+ {
+ RECT rect = wxGetWindowRect(GetHwnd());
+
+ POINT point;
+ point.x = rect.left;
+ point.y = rect.top;
+
+ // we do the adjustments with respect to the parent only for the "real"
+ // children, not for the dialogs/frames
+ if ( !IsTopLevel() )
+ {
+ if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
+ {
+ // In RTL mode, we want the logical left x-coordinate,
+ // which would be the physical right x-coordinate.
+ point.x = rect.right;
+ }
+
+ // Since we now have the absolute screen coords, if there's a
+ // parent we must subtract its top left corner
+ if ( parent )
+ {
+ ::ScreenToClient(GetHwndOf(parent), &point);
+ }
+ }
+
+ pos.x = point.x;
+ pos.y = point.y;
+ }
+
+ // we also must adjust by the client area offset: a control which is just
+ // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
+ if ( parent && !IsTopLevel() )
+ {
+ const wxPoint pt(parent->GetClientAreaOrigin());
+ pos.x -= pt.x;
+ pos.y -= pt.y;
+ }
+
+ if ( x )
+ *x = pos.x;
+ if ( y )
+ *y = pos.y;
+}
+
+void wxWindowMSW::DoScreenToClient(int *x, int *y) const
+{
+ POINT pt;
+ if ( x )
+ pt.x = *x;
+ if ( y )
+ pt.y = *y;
+
+ ::ScreenToClient(GetHwnd(), &pt);
+
+ if ( x )
+ *x = pt.x;
+ if ( y )
+ *y = pt.y;
+}
+
+void wxWindowMSW::DoClientToScreen(int *x, int *y) const
+{
+ POINT pt;
+ if ( x )
+ pt.x = *x;
+ if ( y )
+ pt.y = *y;
+
+ ::ClientToScreen(GetHwnd(), &pt);
+
+ if ( x )
+ *x = pt.x;
+ if ( y )
+ *y = pt.y;
+}
+
+bool
+wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
+{
+#if USE_DEFERRED_SIZING
+ // if our parent had prepared a defer window handle for us, use it (unless
+ // we are a top level window)
+ wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
+
+ HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
+ if ( hdwp )
+ {
+ hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height,
+ SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
+ if ( !hdwp )
+ {
+ wxLogLastError(_T("DeferWindowPos"));
+ }
+ }
+
+ if ( parent )
+ {
+ // hdwp must be updated as it may have been changed
+ parent->m_hDWP = (WXHANDLE)hdwp;
+ }
+
+ if ( hdwp )
+ {
+ // did deferred move, remember new coordinates of the window as they're
+ // different from what Windows would return for it
+ return true;
+ }
+
+ // otherwise (or if deferring failed) move the window in place immediately
+#endif // USE_DEFERRED_SIZING
+ if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) )
+ {
+ wxLogLastError(wxT("MoveWindow"));
+ }
+
+ // if USE_DEFERRED_SIZING, indicates that we didn't use deferred move,
+ // ignored otherwise
+ return false;
+}
+
+void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
+{
+ // 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 ( DoMoveSibling(m_hWnd, x, y, width, height) )
+ {
+#if USE_DEFERRED_SIZING
+ m_pendingPosition = wxPoint(x, y);
+ m_pendingSize = wxSize(width, height);
+#endif // USE_DEFERRED_SIZING
+ }
+}
+
+// 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;
+ int currentW, currentH;
+
+ GetPosition(¤tX, ¤tY);
+ GetSize(¤tW, ¤tH);
+
+ // ... and don't do anything (avoiding flicker) if it's already ok unless
+ // we're forced to resize the window
+ if ( x == currentX && y == currentY &&
+ width == currentW && height == currentH &&
+ !(sizeFlags & wxSIZE_FORCE) )
+ {
+ return;
+ }
+
+ if ( x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
+ x = currentX;
+ if ( y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
+ y = currentY;
+
+ AdjustForParentClientOrigin(x, y, sizeFlags);
+
+ wxSize size = wxDefaultSize;
+ if ( width == wxDefaultCoord )
+ {
+ if ( sizeFlags & wxSIZE_AUTO_WIDTH )
+ {
+ size = DoGetBestSize();
+ width = size.x;
+ }
+ else
+ {
+ // just take the current one
+ width = currentW;
+ }
+ }
+
+ if ( height == wxDefaultCoord )
+ {
+ if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
+ {
+ if ( size.x == wxDefaultCoord )
+ {
+ size = DoGetBestSize();
+ }
+ //else: already called DoGetBestSize() above
+
+ height = size.y;
+ }
+ else
+ {
+ // just take the current one
+ height = currentH;
+ }
+ }
+
+ DoMoveWindow(x, y, width, height);
+}
+
+void wxWindowMSW::DoSetClientSize(int width, int height)
+{
+ // setting the client size is less obvious than 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 AdjustWindowRect()
+ // doesn't take neither into account) 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);
+
+ // if the size is already ok, stop here (NB: rectClient.left = top = 0)
+ if ( (rectClient.right == width || width == wxDefaultCoord) &&
+ (rectClient.bottom == height || height == wxDefaultCoord) )
+ {
+ break;
+ }
+
+ // 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);
+
+ const int widthWin = rectWin.right - rectWin.left,
+ heightWin = rectWin.bottom - 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 *)&rectWin);
+ }
+ }
+
+ // don't call DoMoveWindow() because we want to move window immediately
+ // and not defer it here as otherwise the value returned by
+ // GetClient/WindowRect() wouldn't change as the window wouldn't be
+ // really resized
+ if ( !::MoveWindow(GetHwnd(),
+ rectWin.left,
+ rectWin.top,
+ width + widthWin - rectClient.right,
+ height + heightWin - rectClient.bottom,
+ TRUE) )
+ {
+ wxLogLastError(_T("MoveWindow"));
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// text metrics
+// ---------------------------------------------------------------------------
+
+int wxWindowMSW::GetCharHeight() const
+{
+ return wxGetTextMetrics(this).tmHeight;
+}
+
+int wxWindowMSW::GetCharWidth() const
+{
+ // +1 is needed because Windows apparently adds it when calculating the
+ // dialog units size in pixels
+#if wxDIALOG_UNIT_COMPATIBILITY
+ return wxGetTextMetrics(this).tmAveCharWidth;
+#else
+ return wxGetTextMetrics(this).tmAveCharWidth + 1;
+#endif
+}
+
+void wxWindowMSW::GetTextExtent(const wxString& string,
+ int *x, int *y,
+ int *descent, int *externalLeading,
+ const wxFont *theFont) const
+{
+ wxASSERT_MSG( !theFont || theFont->Ok(),
+ _T("invalid font in GetTextExtent()") );
+
+ wxFont fontToUse;
+ if (theFont)
+ fontToUse = *theFont;
+ else
+ fontToUse = GetFont();
+
+ WindowHDC hdc(GetHwnd());
+ SelectInHDC selectFont(hdc, GetHfontOf(fontToUse));
+
+ SIZE sizeRect;
+ TEXTMETRIC tm;
+ ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
+ GetTextMetrics(hdc, &tm);
+
+ if ( x )
+ *x = sizeRect.cx;
+ if ( y )
+ *y = sizeRect.cy;
+ if ( descent )
+ *descent = tm.tmDescent;
+ if ( externalLeading )
+ *externalLeading = tm.tmExternalLeading;
+}
+
+// ---------------------------------------------------------------------------
+// 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) )
+ {
+ if ( msg.message == WM_QUIT )
+ {
+ // if we retrieved a WM_QUIT, insert back into the message queue.
+ ::PostQuitMessage(0);
+ break;
+ }
+
+ // luckily (as we don't have access to wxEventLoopImpl method from here
+ // anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
+ // immediately
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+}
+
+bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
+{
+ menu->SetInvokingWindow(this);
+ menu->UpdateUI();
+
+ if ( x == wxDefaultCoord && y == wxDefaultCoord )
+ {
+ wxPoint mouse = ScreenToClient(wxGetMousePosition());
+ x = mouse.x; y = mouse.y;
+ }
+
+ HWND hWnd = GetHwnd();
+ HMENU hMenu = GetHmenuOf(menu);
+ POINT point;
+ point.x = x;
+ point.y = y;
+ ::ClientToScreen(hWnd, &point);
+ wxCurrentPopupMenu = menu;
+#if defined(__WXWINCE__)
+ UINT flags = 0;
+#else
+ UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE;
+#endif
+ ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
+
+ // we need to do it right 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
+// ===========================================================================
+
+WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
+{
+ if ( m_oldWndProc )
+ return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
+ else
+ return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
+}
+
+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 ( msg->message == WM_KEYDOWN )
+ {
+ 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
+ // combinations which are always processed)
+ LONG lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
+
+ // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
+ // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
+ // it, of course, implies them
+ if ( lDlgCode & DLGC_WANTALLKEYS )
+ {
+ lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
+ }
+
+ bool bForward = true,
+ bWindowChange = false,
+ bFromTab = false;
+
+ // should we process this message specially?
+ bool bProcess = true;
+ switch ( msg->wParam )
+ {
+ case VK_TAB:
+ if ( lDlgCode & DLGC_WANTTAB ) {
+ bProcess = false;
+ }
+ else {
+ // Ctrl-Tab cycles thru notebook pages
+ bWindowChange = bCtrlDown;
+ bForward = !bShiftDown;
+ bFromTab = true;
+ }
+ break;
+
+ case VK_UP:
+ case VK_LEFT:
+ if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
+ bProcess = false;
+ else
+ bForward = false;
+ break;
+
+ case VK_DOWN:
+ case VK_RIGHT:
+ if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
+ bProcess = false;
+ break;
+
+ case VK_PRIOR:
+ bForward = false;
+ // fall through
+
+ case VK_NEXT:
+ // we treat PageUp/Dn as arrows because chances are that
+ // a control which needs arrows also needs them for
+ // navigation (e.g. wxTextCtrl, wxListCtrl, ...)
+ if ( (lDlgCode & DLGC_WANTARROWS) || !bCtrlDown )
+ bProcess = false;
+ else
+ bWindowChange = true;
+ break;
+
+ case VK_RETURN:
+ {
+ if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
+ {
+ // control wants to process Enter itself, don't
+ // call IsDialogMessage() which would consume it
+ return false;
+ }
+
+#if wxUSE_BUTTON
+ // currently active button should get enter press even
+ // if there is a default button elsewhere so check if
+ // this window is a button first
+ wxWindow *btn = NULL;
+ if ( lDlgCode & DLGC_DEFPUSHBUTTON )
+ {
+ // 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
+ btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
+ }
+
+ bProcess = false;
+ }
+ else // not a button itself, do we have default button?
+ {
+ wxTopLevelWindow *
+ tlw = wxDynamicCast(wxGetTopLevelParent(this),
+ wxTopLevelWindow);
+ if ( tlw )
+ {
+ btn = wxDynamicCast(tlw->GetDefaultItem(),
+ wxButton);
+ }
+ }
+
+ if ( btn && btn->IsEnabled() )
+ {
+ btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+ return true;
+ }
+
+#endif // wxUSE_BUTTON
+
+#ifdef __WXWINCE__
+ // map Enter presses into button presses on PDAs
+ wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN);
+ event.SetEventObject(this);
+ if ( GetEventHandler()->ProcessEvent(event) )
+ return true;
+#endif // __WXWINCE__
+ }
+ break;
+
+ default:
+ bProcess = false;
+ }
+
+ if ( bProcess )
+ {
+ wxNavigationKeyEvent event;
+ event.SetDirection(bForward);
+ event.SetWindowChange(bWindowChange);
+ event.SetFromTab(bFromTab);
+ event.SetEventObject(this);
+
+ if ( GetEventHandler()->ProcessEvent(event) )
+ {
+ // as we don't call IsDialogMessage(), which would take of
+ // this by default, we need to manually send this message
+ // so that controls can change their UI state if needed
+ MSWUpdateUIState(UIS_CLEAR, UISF_HIDEFOCUS);
+
+ return true;
+ }
+ }
+ }
+
+ if ( ::IsDialogMessage(GetHwnd(), msg) )
+ {
+ // IsDialogMessage() did something...
+ return true;
+ }
+ }
+#endif // __WXUNIVERSAL__
+
+#if wxUSE_TOOLTIPS
+ if ( m_tooltip )
+ {
+ // relay mouse move events to the tooltip control
+ MSG *msg = (MSG *)pMsg;
+ if ( msg->message == WM_MOUSEMOVE )
+ wxToolTip::RelayEvent(pMsg);
+ }
+#endif // wxUSE_TOOLTIPS
+
+ return false;
+}
+
+bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg)
+{
+#if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
+ return m_acceleratorTable.Translate(this, pMsg);
+#else
+ (void) pMsg;
+ return false;
+#endif // wxUSE_ACCEL
+}
+
+bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
+{
+ // all tests below have to deal with various bugs/misfeatures of
+ // IsDialogMessage(): we have to prevent it from being called from our
+ // MSWProcessMessage() in some situations
+
+ // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
+ // message even when there is no cancel button and when the message is
+ // needed by the control itself: in particular, it prevents the tree in
+ // place edit control from being closed with Escape in a dialog
+ if ( msg->message == WM_KEYDOWN && msg->wParam == VK_ESCAPE )
+ {
+ return false;
+ }
+
+ // ::IsDialogMessage() is broken and may sometimes hang the application by
+ // going into an infinite loop when it tries to find the control to give
+ // focus to when Alt-<key> is pressed, so we try to detect [some of] the
+ // situations when this may happen and not call it then
+ if ( msg->message != WM_SYSCHAR )
+ return true;
+
+ // assume we can call it by default
+ bool canSafelyCallIsDlgMsg = true;
+
+ HWND hwndFocus = ::GetFocus();
+
+ // if the currently focused window itself has WS_EX_CONTROLPARENT style,
+ // ::IsDialogMessage() will also enter an infinite loop, because it will
+ // recursively check the child windows but not the window itself and so if
+ // none of the children accepts focus it loops forever (as it only stops
+ // when it gets back to the window it started from)
+ //
+ // while it is very unusual that a window with WS_EX_CONTROLPARENT
+ // style has the focus, it can happen. One such possibility is if
+ // all windows are either toplevel, wxDialog, wxPanel or static
+ // controls and no window can actually accept keyboard input.
+#if !defined(__WXWINCE__)
+ if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
+ {
+ // pessimistic by default
+ canSafelyCallIsDlgMsg = false;
+ for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxWindow * const win = node->GetData();
+ if ( win->AcceptsFocus() &&
+ !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) &
+ WS_EX_CONTROLPARENT) )
+ {
+ // it shouldn't hang...
+ canSafelyCallIsDlgMsg = true;
+
+ break;
+ }
+ }
+ }
+#endif // !__WXWINCE__
+
+ if ( canSafelyCallIsDlgMsg )
+ {
+ // ::IsDialogMessage() can enter in an infinite loop when the
+ // currently focused window is disabled or hidden and its
+ // parent has WS_EX_CONTROLPARENT style, so don't call it in
+ // this case
+ while ( hwndFocus )
+ {
+ if ( !::IsWindowEnabled(hwndFocus) ||
+ !::IsWindowVisible(hwndFocus) )
+ {
+ // it would enter an infinite loop if we do this!
+ canSafelyCallIsDlgMsg = false;
+
+ break;
+ }
+
+ if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
+ {
+ // it's a top level window, don't go further -- e.g. even
+ // if the parent of a dialog is disabled, this doesn't
+ // break navigation inside the dialog
+ break;
+ }
+
+ hwndFocus = ::GetParent(hwndFocus);
+ }
+ }
+
+ return canSafelyCallIsDlgMsg;
+}
+
+// ---------------------------------------------------------------------------
+// message params unpackers
+// ---------------------------------------------------------------------------
+
+void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam,
+ WORD *id, WXHWND *hwnd, WORD *cmd)
+{
+ *id = LOWORD(wParam);
+ *hwnd = (WXHWND)lParam;
+ *cmd = HIWORD(wParam);
+}
+
+void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam,
+ WXWORD *state, WXWORD *minimized, WXHWND *hwnd)
+{
+ *state = LOWORD(wParam);
+ *minimized = HIWORD(wParam);
+ *hwnd = (WXHWND)lParam;
+}
+
+void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam,
+ WXWORD *code, WXWORD *pos, WXHWND *hwnd)
+{
+ *code = LOWORD(wParam);
+ *pos = HIWORD(wParam);
+ *hwnd = (WXHWND)lParam;
+}
+
+void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam,
+ WXHDC *hdc, WXHWND *hwnd)
+{
+ *hwnd = (WXHWND)lParam;
+ *hdc = (WXHDC)wParam;
+}
+
+void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam,
+ WXWORD *item, WXWORD *flags, WXHMENU *hmenu)
+{
+ *item = (WXWORD)wParam;
+ *flags = HIWORD(wParam);
+ *hmenu = (WXHMENU)lParam;
+}
+
+// ---------------------------------------------------------------------------
+// Main wxWidgets window proc and the window proc for wxWindow
+// ---------------------------------------------------------------------------
+
+// Hook for new window just as it's being created, when the window isn't yet
+// associated with the handle
+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 WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ // trace all messages - useful for the debugging
+#ifdef __WXDEBUG__
+ wxLogTrace(wxTraceMessages,
+ wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"),
+ wxGetMessageName(message), (long)hWnd, (long)wParam, lParam);
+#endif // __WXDEBUG__
+
+ wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
+
+ // when we get the first message for the HWND we just created, we associate
+ // it with wxWindow stored in gs_winBeingCreated
+ if ( !wnd && gs_winBeingCreated )
+ {
+ wxAssociateWinWithHandle(hWnd, gs_winBeingCreated);
+ wnd = gs_winBeingCreated;
+ gs_winBeingCreated = NULL;
+ wnd->SetHWND((WXHWND)hWnd);
+ }
+
+ LRESULT rc;
+
+ if ( wnd && wxEventLoop::AllowProcessing(wnd) )
+ rc = wnd->MSWWindowProc(message, wParam, lParam);
+ else
+ rc = ::DefWindowProc(hWnd, message, wParam, lParam);
+
+ return rc;
+}
+
+WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
+{
+ // did we process the message?
+ bool processed = false;
+
+ // the return value
+ union
+ {
+ bool allow;
+ WXLRESULT result;
+ WXHBRUSH hBrush;
+ } rc;
+
+ // for most messages we should return 0 when we do process the message
+ rc.result = 0;
+
+ switch ( message )
+ {
+ case WM_CREATE:
+ {
+ bool mayCreate;
+ processed = HandleCreate((WXLPCREATESTRUCT)lParam, &mayCreate);
+ if ( processed )
+ {
+ // return 0 to allow window creation
+ rc.result = mayCreate ? 0 : -1;
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ // 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_SIZE:
+ processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
+ break;
+
+ case WM_MOVE:
+ processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ break;
+
+#if !defined(__WXWINCE__)
+ case WM_MOVING:
+ {
+ LPRECT pRect = (LPRECT)lParam;
+ wxRect rc;
+ rc.SetLeft(pRect->left);
+ rc.SetTop(pRect->top);
+ rc.SetRight(pRect->right);
+ rc.SetBottom(pRect->bottom);
+ processed = HandleMoving(rc);
+ if (processed) {
+ pRect->left = rc.GetLeft();
+ pRect->top = rc.GetTop();
+ pRect->right = rc.GetRight();
+ pRect->bottom = rc.GetBottom();
+ }
+ }
+ break;
+
+ case WM_SIZING:
+ {
+ LPRECT pRect = (LPRECT)lParam;
+ wxRect rc;
+ rc.SetLeft(pRect->left);
+ rc.SetTop(pRect->top);
+ rc.SetRight(pRect->right);
+ rc.SetBottom(pRect->bottom);
+ processed = HandleSizing(rc);
+ if (processed) {
+ pRect->left = rc.GetLeft();
+ pRect->top = rc.GetTop();
+ pRect->right = rc.GetRight();
+ pRect->bottom = rc.GetBottom();
+ }
+ }
+ break;
+#endif // !__WXWINCE__
+
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
+ case WM_ACTIVATEAPP:
+ // This implicitly sends a wxEVT_ACTIVATE_APP event
+ wxTheApp->SetActive(wParam != 0, FindFocus());
+ break;
+#endif
+
+ case WM_ACTIVATE:
+ {
+ WXWORD state, minimized;
+ WXHWND hwnd;
+ UnpackActivate(wParam, lParam, &state, &minimized, &hwnd);
+
+ processed = HandleActivate(state, minimized != 0, (WXHWND)hwnd);
+ }
+ break;
+
+ case WM_SETFOCUS:
+ processed = HandleSetFocus((WXHWND)(HWND)wParam);
+ break;
+
+ case WM_KILLFOCUS:
+ processed = HandleKillFocus((WXHWND)(HWND)wParam);
+ break;
+
+ case WM_PRINTCLIENT:
+ processed = HandlePrintClient((WXHDC)wParam);
+ break;
+
+ case WM_PAINT:
+ if ( wParam )
+ {
+ wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam);
+
+ processed = HandlePaint();
+ }
+ else // no DC given
+ {
+ processed = HandlePaint();
+ }
+ break;
+
+ case WM_CLOSE:
+#ifdef __WXUNIVERSAL__
+ // Universal uses its own wxFrame/wxDialog, so we don't receive
+ // close events unless we have this.
+ Close();
+#endif // __WXUNIVERSAL__
+
+ // don't let the DefWindowProc() destroy our window - we'll do it
+ // ourselves in ~wxWindow
+ processed = true;
+ rc.result = TRUE;
+ break;
+
+ case WM_SHOWWINDOW:
+ processed = HandleShow(wParam != 0, (int)lParam);
+ break;
+
+ case WM_MOUSEMOVE:
+ processed = HandleMouseMove(GET_X_LPARAM(lParam),
+ GET_Y_LPARAM(lParam),
+ wParam);
+ break;
+
+#ifdef HAVE_TRACKMOUSEEVENT
+ case WM_MOUSELEAVE:
+ // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
+ // (on XP at least)
+ if ( m_mouseInWindow )
+ {
+ GenerateMouseLeave();
+ }
+
+ // always pass processed back as false, this allows the window
+ // manager to process the message too. This is needed to
+ // ensure windows XP themes work properly as the mouse moves
+ // over widgets like buttons. So don't set processed to true here.
+ break;
+#endif // HAVE_TRACKMOUSEEVENT
+
+#if wxUSE_MOUSEWHEEL
+ case WM_MOUSEWHEEL:
+ processed = HandleMouseWheel(wParam, lParam);
+ break;
+#endif
+
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_RBUTTONDBLCLK:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_MBUTTONDBLCLK:
+ {
+#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;
+ for ( ;; )
+ {
+ if (!win->IsEnabled())
+ {
+ processed = true;
+ break;
+ }
+
+ win = win->GetParent();
+ if ( !win || win->IsTopLevel() )
+ break;
+ }
+
+ if ( processed )
+ break;
+
+#endif // __WXMICROWIN__
+ int x = GET_X_LPARAM(lParam),
+ y = GET_Y_LPARAM(lParam);
+
+#ifdef __WXWINCE__
+ // redirect the event to a static control if necessary by
+ // finding one under mouse because under CE the static controls
+ // don't generate mouse events (even with SS_NOTIFY)
+ wxWindowMSW *win;
+ if ( GetCapture() == this )
+ {
+ // but don't do it if the mouse is captured by this window
+ // because then it should really get this event itself
+ win = this;
+ }
+ else
+ {
+ win = FindWindowForMouseEvent(this, &x, &y);
+
+ // this should never happen
+ wxCHECK_MSG( win, 0,
+ _T("FindWindowForMouseEvent() returned NULL") );
+ }
+#ifdef __POCKETPC__
+ if (IsContextMenuEnabled() && message == WM_LBUTTONDOWN)
+ {
+ SHRGINFO shrgi = {0};
+
+ shrgi.cbSize = sizeof(SHRGINFO);
+ shrgi.hwndClient = (HWND) GetHWND();
+ shrgi.ptDown.x = x;
+ shrgi.ptDown.y = y;
+
+ shrgi.dwFlags = SHRG_RETURNCMD;
+ // shrgi.dwFlags = SHRG_NOTIFYPARENT;
+
+ if (GN_CONTEXTMENU == ::SHRecognizeGesture(&shrgi))
+ {
+ wxPoint pt(x, y);
+ pt = ClientToScreen(pt);
+
+ wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
+
+ evtCtx.SetEventObject(this);
+ if (GetEventHandler()->ProcessEvent(evtCtx))
+ {
+ processed = true;
+ return true;
+ }
+ }
+ }
+#endif
+
+#else // !__WXWINCE__
+ wxWindowMSW *win = this;
+#endif // __WXWINCE__/!__WXWINCE__
+
+ processed = win->HandleMouseEvent(message, x, y, wParam);
+
+ // if the app didn't eat the event, handle it in the default
+ // way, that is by giving this window the focus
+ if ( !processed )
+ {
+ // for the standard classes their WndProc sets the focus to
+ // them anyhow and doing it from here results in some weird
+ // problems, so don't do it for them (unnecessary anyhow)
+ if ( !win->IsOfStandardClass() )
+ {
+ if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
+ win->SetFocus();
+ }
+ }
+ }
+ break;
+
+#ifdef MM_JOY1MOVE
+ case MM_JOY1MOVE:
+ case MM_JOY2MOVE:
+ case MM_JOY1ZMOVE:
+ case MM_JOY2ZMOVE:
+ case MM_JOY1BUTTONDOWN:
+ case MM_JOY2BUTTONDOWN:
+ case MM_JOY1BUTTONUP:
+ case MM_JOY2BUTTONUP:
+ processed = HandleJoystickEvent(message,
+ GET_X_LPARAM(lParam),
+ GET_Y_LPARAM(lParam),
+ wParam);
+ break;
+#endif // __WXMICROWIN__
+
+ case WM_COMMAND:
+ {
+ WORD id, cmd;
+ WXHWND hwnd;
+ UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
+
+ processed = HandleCommand(id, cmd, hwnd);
+ }
+ break;
+
+ case WM_NOTIFY:
+ processed = HandleNotify((int)wParam, lParam, &rc.result);
+ break;
+
+ // we only need to reply to WM_NOTIFYFORMAT manually when using MSLU,
+ // otherwise DefWindowProc() does it perfectly fine for us, but MSLU
+ // apparently doesn't always behave properly and needs some help
+#if wxUSE_UNICODE_MSLU && defined(NF_QUERY)
+ case WM_NOTIFYFORMAT:
+ if ( lParam == NF_QUERY )
+ {
+ processed = true;
+ rc.result = NFR_UNICODE;
+ }
+ break;
+#endif // wxUSE_UNICODE_MSLU
+
+ // for these messages we must return true if process the message
+#ifdef WM_DRAWITEM
+ case WM_DRAWITEM:
+ case WM_MEASUREITEM:
+ {
+ int idCtrl = (UINT)wParam;
+ if ( message == WM_DRAWITEM )
+ {
+ processed = MSWOnDrawItem(idCtrl,
+ (WXDRAWITEMSTRUCT *)lParam);
+ }
+ else
+ {
+ processed = MSWOnMeasureItem(idCtrl,
+ (WXMEASUREITEMSTRUCT *)lParam);
+ }
+
+ if ( processed )
+ rc.result = TRUE;
+ }
+ break;
+#endif // defined(WM_DRAWITEM)
+
+ case WM_GETDLGCODE:
+ if ( !IsOfStandardClass() )
+ {
+ // we always want to get the char events
+ rc.result = DLGC_WANTCHARS;
+
+ if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+ {
+ // in fact, we want everything
+ rc.result |= DLGC_WANTARROWS |
+ DLGC_WANTTAB |
+ DLGC_WANTALLKEYS;
+ }
+
+ processed = true;
+ }
+ //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).
+ m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
+ if ( m_lastKeydownProcessed )
+ {
+ processed = true;
+ }
+
+ if ( !processed )
+ {
+ switch ( wParam )
+ {
+ // we consider these messages "not interesting" to OnChar, so
+ // just don't do anything more with them
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ case VK_CAPITAL:
+ case VK_NUMLOCK:
+ case VK_SCROLL:
+ processed = true;
+ break;
+
+ // avoid duplicate messages to OnChar for these ASCII keys:
+ // they will be translated by TranslateMessage() and received
+ // in WM_CHAR
+ case VK_ESCAPE:
+ case VK_SPACE:
+ case VK_RETURN:
+ case VK_BACK:
+ case VK_TAB:
+ case VK_ADD:
+ case VK_SUBTRACT:
+ case VK_MULTIPLY:
+ case VK_DIVIDE:
+ case VK_NUMPAD0:
+ case VK_NUMPAD1:
+ case VK_NUMPAD2:
+ case VK_NUMPAD3:
+ case VK_NUMPAD4:
+ case VK_NUMPAD5:
+ case VK_NUMPAD6:
+ case VK_NUMPAD7:
+ case VK_NUMPAD8:
+ case VK_NUMPAD9:
+ case VK_OEM_1:
+ case VK_OEM_2:
+ case VK_OEM_3:
+ case VK_OEM_4:
+ case VK_OEM_5:
+ case VK_OEM_6:
+ case VK_OEM_7:
+ case VK_OEM_PLUS:
+ case VK_OEM_COMMA:
+ case VK_OEM_MINUS:
+ case VK_OEM_PERIOD:
+ // 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
+ processed = false;
+ break;
+
+#ifdef VK_APPS
+ // special case of VK_APPS: treat it the same as right mouse
+ // click because both usually pop up a context menu
+ case VK_APPS:
+ processed = HandleMouseEvent(WM_RBUTTONDOWN, -1, -1, 0);
+ break;
+#endif // VK_APPS
+
+ default:
+ // do generate a CHAR event
+ processed = HandleChar((WORD)wParam, lParam);
+ }
+ }
+ if (message == WM_SYSKEYDOWN) // Let Windows still handle the SYSKEYs
+ processed = false;
+ break;
+
+ case WM_SYSKEYUP:
+ case WM_KEYUP:
+#ifdef VK_APPS
+ // special case of VK_APPS: treat it the same as right mouse button
+ if ( wParam == VK_APPS )
+ {
+ processed = HandleMouseEvent(WM_RBUTTONUP, -1, -1, 0);
+ }
+ else
+#endif // VK_APPS
+ {
+ processed = HandleKeyUp((WORD) wParam, lParam);
+ }
+ break;
+
+ case WM_SYSCHAR:
+ case WM_CHAR: // Always an ASCII character
+ if ( m_lastKeydownProcessed )
+ {
+ // The key was handled in the EVT_KEY_DOWN and handling
+ // a key in an EVT_KEY_DOWN handler is meant, by
+ // design, to prevent EVT_CHARs from happening
+ m_lastKeydownProcessed = false;
+ processed = true;
+ }
+ else
+ {
+ processed = HandleChar((WORD)wParam, lParam, true);
+ }
+ break;
+
+#if wxUSE_HOTKEY
+ case WM_HOTKEY:
+ processed = HandleHotKey((WORD)wParam, lParam);
+ break;
+#endif // wxUSE_HOTKEY
+
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ {
+ WXWORD code, pos;
+ WXHWND hwnd;
+ UnpackScroll(wParam, lParam, &code, &pos, &hwnd);
+
+ processed = MSWOnScroll(message == WM_HSCROLL ? wxHORIZONTAL
+ : wxVERTICAL,
+ code, pos, hwnd);
+ }
+ break;
+
+ // CTLCOLOR messages are sent by children to query the parent for their
+ // colors
+#ifndef __WXMICROWIN__
+ case WM_CTLCOLORMSGBOX:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORSTATIC:
+ {
+ WXHDC hdc;
+ WXHWND hwnd;
+ UnpackCtlColor(wParam, lParam, &hdc, &hwnd);
+
+ processed = HandleCtlColor(&rc.hBrush, (WXHDC)hdc, (WXHWND)hwnd);
+ }
+ break;
+#endif // !__WXMICROWIN__
+
+ case WM_SYSCOLORCHANGE:
+ // the return value for this message is ignored
+ processed = HandleSysColorChange();
+ break;
+
+#if !defined(__WXWINCE__)
+ case WM_DISPLAYCHANGE:
+ processed = HandleDisplayChange();
+ break;
+#endif
+
+ case WM_PALETTECHANGED:
+ processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
+ break;
+
+ case WM_CAPTURECHANGED:
+ processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
+ break;
+
+ case WM_SETTINGCHANGE:
+ processed = HandleSettingChange(wParam, lParam);
+ break;
+
+ case WM_QUERYNEWPALETTE:
+ processed = HandleQueryNewPalette();
+ break;
+
+ case WM_ERASEBKGND:
+ processed = HandleEraseBkgnd((WXHDC)(HDC)wParam);
+ if ( processed )
+ {
+ // we processed the message, i.e. erased the background
+ rc.result = TRUE;
+ }
+ break;
+
+#if !defined(__WXWINCE__)
+ case WM_DROPFILES:
+ processed = HandleDropFiles(wParam);
+ break;
+#endif
+
+ case WM_INITDIALOG:
+ processed = HandleInitDialog((WXHWND)(HWND)wParam);
+
+ if ( processed )
+ {
+ // we never set focus from here
+ rc.result = FALSE;
+ }
+ break;
+
+#if !defined(__WXWINCE__)
+ case WM_QUERYENDSESSION:
+ processed = HandleQueryEndSession(lParam, &rc.allow);
+ break;
+
+ case WM_ENDSESSION:
+ processed = HandleEndSession(wParam != 0, lParam);
+ break;
+
+ case WM_GETMINMAXINFO:
+ processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam);
+ break;
+#endif
+
+ case WM_SETCURSOR:
+ processed = HandleSetCursor((WXHWND)(HWND)wParam,
+ LOWORD(lParam), // hit test
+ HIWORD(lParam)); // mouse msg
+
+ if ( processed )
+ {
+ // returning TRUE stops the DefWindowProc() from further
+ // processing this message - exactly what we need because we've
+ // just set the cursor.
+ rc.result = TRUE;
+ }
+ break;
+
+#if wxUSE_ACCESSIBILITY
+ case WM_GETOBJECT:
+ {
+ //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
+ LPARAM dwObjId = (LPARAM) (DWORD) lParam;
+
+ if (dwObjId == (LPARAM)OBJID_CLIENT && GetOrCreateAccessible())
+ {
+ return LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible());
+ }
+ break;
+ }
+#endif
+
+#if defined(WM_HELP)
+ case WM_HELP:
+ {
+ // by default, WM_HELP is propagated by DefWindowProc() upwards
+ // to the window parent but as we do it ourselves already
+ // (wxHelpEvent is derived from wxCommandEvent), we don't want
+ // to get the other events if we process this message at all
+ processed = true;
+
+ // WM_HELP doesn't use lParam under CE
+#ifndef __WXWINCE__
+ HELPINFO* info = (HELPINFO*) lParam;
+ if ( info->iContextType == HELPINFO_WINDOW )
+ {
+#endif // !__WXWINCE__
+ wxHelpEvent helpEvent
+ (
+ wxEVT_HELP,
+ GetId(),
+#ifdef __WXWINCE__
+ wxGetMousePosition() // what else?
+#else
+ wxPoint(info->MousePos.x, info->MousePos.y)
+#endif
+ );
+
+ helpEvent.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(helpEvent);
+#ifndef __WXWINCE__
+ }
+ else if ( info->iContextType == HELPINFO_MENUITEM )
+ {
+ wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
+ helpEvent.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(helpEvent);
+
+ }
+ else // unknown help event?
+ {
+ processed = false;
+ }
+#endif // !__WXWINCE__
+ }
+ break;
+#endif // WM_HELP
+
+#if !defined(__WXWINCE__)
+ 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);
+
+ // we could have got an event from our child, reflect it back
+ // to it if this is the case
+ wxWindowMSW *win = NULL;
+ if ( (WXHWND)wParam != m_hWnd )
+ {
+ win = FindItemByHWND((WXHWND)wParam);
+ }
+
+ if ( !win )
+ win = this;
+
+ evtCtx.SetEventObject(win);
+ processed = win->GetEventHandler()->ProcessEvent(evtCtx);
+ }
+ break;
+#endif
+
+ case WM_MENUCHAR:
+ // we're only interested in our own menus, not MF_SYSMENU
+ if ( HIWORD(wParam) == MF_POPUP )
+ {
+ // handle menu chars for ownerdrawn menu items
+ int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam);
+ if ( i != wxNOT_FOUND )
+ {
+ rc.result = MAKELRESULT(i, MNC_EXECUTE);
+ processed = true;
+ }
+ }
+ break;
+
+#ifndef __WXWINCE__
+ case WM_POWERBROADCAST:
+ {
+ bool vetoed;
+ processed = HandlePower(wParam, lParam, &vetoed);
+ rc.result = processed && vetoed ? BROADCAST_QUERY_DENY : TRUE;
+ }
+ break;
+#endif // __WXWINCE__
+ }
+
+ if ( !processed )
+ {
+#ifdef __WXDEBUG__
+ wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
+ wxGetMessageName(message));
+#endif // __WXDEBUG__
+ rc.result = MSWDefWindowProc(message, wParam, lParam);
+ }
+
+ return rc.result;
+}
+
+// ----------------------------------------------------------------------------
+// wxWindow <-> HWND map
+// ----------------------------------------------------------------------------
+
+wxWinHashTable *wxWinHandleHash = NULL;
+
+wxWindow *wxFindWinFromHandle(WXHWND hWnd)
+{
+ return (wxWindow*)wxWinHandleHash->Get((long)hWnd);
+}
+
+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,
+ wxT("attempt to add a NULL hWnd to window list ignored") );
+
+ wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd);
+#ifdef __WXDEBUG__
+ if ( oldWin && (oldWin != win) )
+ {
+ wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
+ (int) hWnd, win->GetClassInfo()->GetClassName());
+ }
+ else
+#endif // __WXDEBUG__
+ if (!oldWin)
+ {
+ wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
+ }
+}
+
+void wxRemoveHandleAssociation(wxWindowMSW *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 wxWindowMSW::MSWDestroyWindow()
+{
+}
+
+bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
+ const wxSize& size,
+ int& x, int& y,
+ int& w, int& h) const
+{
+ // yes, those are just some arbitrary hardcoded numbers
+ static const int DEFAULT_Y = 200;
+
+ bool nonDefault = false;
+
+ if ( pos.x == wxDefaultCoord )
+ {
+ // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
+ // can just as well set it to CW_USEDEFAULT as well
+ x =
+ y = CW_USEDEFAULT;
+ }
+ else
+ {
+ // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
+ // neither because it is not handled as a special value by Windows then
+ // and so we have to choose some default value for it
+ x = pos.x;
+ y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y;
+
+ nonDefault = true;
+ }
+
+ /*
+ 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 wxWidgets programs often assume
+ that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
+ it. To see why, you should understand that Windows sends WM_SIZE from
+ inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
+ 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 wxWidgets and Windows check for
+ this and ignore any attempts to change the window size to the size it
+ already has - so no WM_SIZE would be sent.
+ */
+
+
+ // we don't use CW_USEDEFAULT here for several reasons:
+ //
+ // 1. it results in huge frames on modern screens (1000*800 is not
+ // uncommon on my 1280*1024 screen) which is way too big for a half
+ // empty frame of most of wxWidgets samples for example)
+ //
+ // 2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which
+ // the default is for whatever reason 8*8 which breaks client <->
+ // window size calculations (it would be nice if it didn't, but it
+ // does and the simplest way to fix it seemed to change the broken
+ // default size anyhow)
+ //
+ // 3. there is just no advantage in doing it: with x and y it is
+ // possible that [future versions of] Windows position the new top
+ // level window in some smart way which we can't do, but we can
+ // guess a reasonably good size for a new window just as well
+ // ourselves
+
+ // However, on PocketPC devices, we must use the default
+ // size if possible.
+#ifdef _WIN32_WCE
+ if (size.x == wxDefaultCoord)
+ w = CW_USEDEFAULT;
+ else
+ w = size.x;
+ if (size.y == wxDefaultCoord)
+ h = CW_USEDEFAULT;
+ else
+ h = size.y;
+#else
+ if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord)
+ {
+ nonDefault = true;
+ }
+ w = WidthDefault(size.x);
+ h = HeightDefault(size.y);
+#endif
+
+ AdjustForParentClientOrigin(x, y);
+
+ return nonDefault;
+}
+
+WXHWND wxWindowMSW::MSWGetParent() const
+{
+ return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
+}
+
+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);
+
+ // controlId is menu handle for the top level windows, so set it to 0
+ // unless we're creating a child window
+ int controlId = style & WS_CHILD ? GetId() : 0;
+
+ // 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 ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
+ {
+ className += wxT("NR");
+ }
+
+ // do create the window
+ wxWindowCreationHook hook(this);
+
+ m_hWnd = (WXHWND)::CreateWindowEx
+ (
+ extendedStyle,
+ className,
+ title ? title : m_windowName.c_str(),
+ style,
+ x, y, w, h,
+ (HWND)MSWGetParent(),
+ (HMENU)controlId,
+ wxGetInstance(),
+ NULL // no extra data
+ );
+
+ if ( !m_hWnd )
+ {
+ wxLogSysError(_("Can't create window of class %s"), className.c_str());
+
+ return false;
+ }
+
+ SubclassWin(m_hWnd);
+
+ return true;
+}
+
+// ===========================================================================
+// MSW message handlers
+// ===========================================================================
+
+// ---------------------------------------------------------------------------
+// WM_NOTIFY
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
+{
+#ifndef __WXMICROWIN__
+ LPNMHDR hdr = (LPNMHDR)lParam;
+ HWND hWnd = hdr->hwndFrom;
+ wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
+
+ // if the control is one of our windows, let it handle the message itself
+ if ( win )
+ {
+ return win->MSWOnNotify(idCtrl, lParam, result);
+ }
+
+ // VZ: why did we do it? normally this is unnecessary and, besides, it
+ // breaks the message processing for the toolbars because the tooltip
+ // notifications were being forwarded to the toolbar child controls
+ // (if it had any) before being passed to the toolbar itself, so in my
+ // example the tooltip for the combobox was always shown instead of the
+ // correct button tooltips
+#if 0
+ // try all our children
+ wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ while ( node )
+ {
+ wxWindow *child = node->GetData();
+ if ( child->MSWOnNotify(idCtrl, lParam, result) )
+ {
+ return true;
+ }
+
+ node = node->GetNext();
+ }
+#endif // 0
+
+ // by default, handle it ourselves
+ return MSWOnNotify(idCtrl, lParam, result);
+#else // __WXMICROWIN__
+ return false;
+#endif
+}
+
+#if wxUSE_TOOLTIPS
+
+bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
+ WXLPARAM lParam,
+ const wxString& ttip)
+{
+ // I don't know why it happens, but the versions of comctl32.dll starting
+ // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
+ // this message is supposed to be sent to Unicode programs only) -- hence
+ // we need to handle it as well, otherwise no tooltips will be shown in
+ // this case
+#ifndef __WXWINCE__
+ if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW)
+ || ttip.empty() )
+ {
+ // not a tooltip message or no tooltip to show anyhow
+ return false;
+ }
+#endif
+
+ LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
+
+ // We don't want to use the szText buffer because it has a limit of 80
+ // bytes and this is not enough, especially for Unicode build where it
+ // limits the tooltip string length to only 40 characters
+ //
+ // The best would be, of course, to not impose any length limitations at
+ // all but then the buffer would have to be dynamic and someone would have
+ // to free it and we don't have the tooltip owner object here any more, so
+ // for now use our own static buffer with a higher fixed max length.
+ //
+ // Note that using a static buffer should not be a problem as only a single
+ // tooltip can be shown at the same time anyhow.
+#if !wxUSE_UNICODE
+ if ( code == (WXUINT) TTN_NEEDTEXTW )
+ {
+ // We need to convert tooltip from multi byte to Unicode on the fly.
+ static wchar_t buf[513];
+
+ // Truncate tooltip length if needed as otherwise we might not have
+ // enough space for it in the buffer and MultiByteToWideChar() would
+ // return an error
+ size_t tipLength = wxMin(ttip.length(), WXSIZEOF(buf) - 1);
+
+ // Convert to WideChar without adding the NULL character. The NULL
+ // character is added afterwards (this is more efficient).
+ int len = ::MultiByteToWideChar
+ (
+ CP_ACP,
+ 0, // no flags
+ ttip,
+ tipLength,
+ buf,
+ WXSIZEOF(buf) - 1
+ );
+
+ if ( !len )
+ {
+ wxLogLastError(_T("MultiByteToWideChar()"));
+ }
+
+ buf[len] = L'\0';
+ ttText->lpszText = (LPSTR) buf;
+ }
+ else // TTN_NEEDTEXTA
+#endif // !wxUSE_UNICODE
+ {
+ // we get here if we got TTN_NEEDTEXTA (only happens in ANSI build) or
+ // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have
+ // to copy the string we have into the buffer
+ static wxChar buf[513];
+ wxStrncpy(buf, ttip.c_str(), WXSIZEOF(buf) - 1);
+ buf[WXSIZEOF(buf) - 1] = _T('\0');
+ ttText->lpszText = buf;
+ }
+
+ return true;
+}
+
+#endif // wxUSE_TOOLTIPS
+
+bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
+ WXLPARAM lParam,
+ WXLPARAM* WXUNUSED(result))
+{
+#if wxUSE_TOOLTIPS
+ if ( m_tooltip )
+ {
+ NMHDR* hdr = (NMHDR *)lParam;
+ if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip()))
+ {
+ // processed
+ return true;
+ }
+ }
+#else
+ wxUnusedVar(lParam);
+#endif // wxUSE_TOOLTIPS
+
+ return false;
+}
+
+// ---------------------------------------------------------------------------
+// end session messages
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
+{
+#ifdef ENDSESSION_LOGOFF
+ wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY);
+ event.SetEventObject(wxTheApp);
+ event.SetCanVeto(true);
+ event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF);
+
+ bool rc = wxTheApp->ProcessEvent(event);
+
+ if ( rc )
+ {
+ // we may end only if the app didn't veto session closing (double
+ // negation...)
+ *mayEnd = !event.GetVeto();
+ }
+
+ return rc;
+#else
+ wxUnusedVar(logOff);
+ wxUnusedVar(mayEnd);
+ return false;
+#endif
+}
+
+bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
+{
+#ifdef ENDSESSION_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, wxID_ANY);
+ event.SetEventObject(wxTheApp);
+ event.SetCanVeto(false);
+ event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) );
+
+ return wxTheApp->ProcessEvent(event);
+#else
+ wxUnusedVar(endSession);
+ wxUnusedVar(logOff);
+ return false;
+#endif
+}
+
+// ---------------------------------------------------------------------------
+// window creation/destruction
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED_IN_WINCE(cs),
+ bool *mayCreate)
+{
+ // VZ: why is this commented out for WinCE? If it doesn't support
+ // WS_EX_CONTROLPARENT at all it should be somehow handled globally,
+ // not with multiple #ifdef's!
+#ifndef __WXWINCE__
+ if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT )
+ EnsureParentHasControlParentStyle(GetParent());
+#endif // !__WXWINCE__
+
+ *mayCreate = true;
+
+ return true;
+}
+
+bool wxWindowMSW::HandleDestroy()
+{
+ SendDestroyEvent();
+
+ // delete our drop target if we've got one
+#if wxUSE_DRAG_AND_DROP
+ if ( m_dropTarget != NULL )
+ {
+ m_dropTarget->Revoke(m_hWnd);
+
+ delete m_dropTarget;
+ m_dropTarget = NULL;
+ }
+#endif // wxUSE_DRAG_AND_DROP
+
+ // WM_DESTROY handled
+ return true;
+}
+
+// ---------------------------------------------------------------------------
+// activation/focus
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::HandleActivate(int state,
+ bool WXUNUSED(minimized),
+ WXHWND WXUNUSED(activate))
+{
+ wxActivateEvent event(wxEVT_ACTIVATE,
+ (state == WA_ACTIVE) || (state == WA_CLICKACTIVE),
+ m_windowId);
+ event.SetEventObject(this);
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
+{
+ // Strangly enough, some controls get set focus events when they are being
+ // deleted, even if they already had focus before.
+ if ( m_isBeingDeleted )
+ {
+ return false;
+ }
+
+ // notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it
+ wxChildFocusEvent eventFocus((wxWindow *)this);
+ (void)GetEventHandler()->ProcessEvent(eventFocus);
+
+#if wxUSE_CARET
+ // Deal with caret
+ if ( m_caret )
+ {
+ m_caret->OnSetFocus();
+ }
+#endif // wxUSE_CARET
+
+#if wxUSE_TEXTCTRL
+ // If it's a wxTextCtrl don't send the event as it will be done
+ // after the control gets to process it from EN_FOCUS handler
+ if ( wxDynamicCastThis(wxTextCtrl) )
+ {
+ return false;
+ }
+#endif // wxUSE_TEXTCTRL
+
+ wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
+ event.SetEventObject(this);
+
+ // wxFindWinFromHandle() may return NULL, it is ok
+ event.SetWindow(wxFindWinFromHandle(hwnd));
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
+{
+#if wxUSE_CARET
+ // Deal with caret
+ if ( m_caret )
+ {
+ m_caret->OnKillFocus();
+ }
+#endif // wxUSE_CARET
+
+#if wxUSE_TEXTCTRL
+ // If it's a wxTextCtrl don't send the event as it will be done
+ // after the control gets to process it.
+ wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl);
+ if ( ctrl )
+ {
+ return false;
+ }
+#endif
+
+ // Don't send the event when in the process of being deleted. This can
+ // only cause problems if the event handler tries to access the object.
+ if ( m_isBeingDeleted )
+ {
+ return false;
+ }
+
+ 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);
+}
+
+// ---------------------------------------------------------------------------
+// labels
+// ---------------------------------------------------------------------------
+
+void wxWindowMSW::SetLabel( const wxString& label)
+{
+ SetWindowText(GetHwnd(), label.c_str());
+}
+
+wxString wxWindowMSW::GetLabel() const
+{
+ return wxGetWindowText(GetHWND());
+}
+
+// ---------------------------------------------------------------------------
+// miscellaneous
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status))
+{
+ wxShowEvent event(GetId(), show);
+ event.SetEventObject(this);
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus))
+{
+ wxInitDialogEvent event(GetId());
+ event.SetEventObject(this);
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
+{
+#if defined (__WXMICROWIN__) || defined(__WXWINCE__)
+ wxUnusedVar(wParam);
+ return false;
+#else // __WXMICROWIN__
+ HDROP hFilesInfo = (HDROP) wParam;
+
+ // Get the total number of files dropped
+ UINT gwFilesDropped = ::DragQueryFile
+ (
+ (HDROP)hFilesInfo,
+ (UINT)-1,
+ (LPTSTR)0,
+ (UINT)0
+ );
+
+ wxString *files = new wxString[gwFilesDropped];
+ for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
+ {
+ // 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,
+ wxStringBuffer(files[wIndex], len), len);
+ }
+ DragFinish (hFilesInfo);
+
+ wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
+ event.SetEventObject(this);
+
+ POINT dropPoint;
+ DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
+ event.m_pos.x = dropPoint.x;
+ event.m_pos.y = dropPoint.y;
+
+ return GetEventHandler()->ProcessEvent(event);
+#endif
+}
+
+
+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 __WXWINCE__
+ if ( !::GetCursorPosWinCE(&pt))
+#else
+ if ( !::GetCursorPos(&pt) )
+#endif
+ {
+ wxLogLastError(wxT("GetCursorPos"));
+ }
+
+ int x = pt.x,
+ y = pt.y;
+ ScreenToClient(&x, &y);
+ wxSetCursorEvent event(x, y);
+
+ bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
+ if ( processedEvtSetCursor && event.HasCursor() )
+ {
+ hcursor = GetHcursorOf(event.GetCursor());
+ }
+
+ 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() )
+ {
+ if ( isBusy )
+ {
+ hcursor = wxGetCurrentBusyCursor();
+ }
+ else if ( !hcursor )
+ {
+ const wxCursor *cursor = wxGetGlobalCursor();
+ if ( cursor && cursor->Ok() )
+ {
+ hcursor = GetHcursorOf(*cursor);
+ }
+ }
+ }