X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9c7df356f9cdbf99bf09f276d67f0fd65c4ca8ea..3317223b08943c74ee4c7956b6aa9a3e72f87d77:/src/msw/window.cpp?ds=sidebyside diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 8808c8e64f..ebd05bfd52 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -178,6 +178,9 @@ static void TranslateKbdEventToMouse(wxWindowMSW *win, // get the text metrics for the current font static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win); +// find the window for the mouse event at the specified position +static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y); //TW:REQ:Univ + // wrapper around BringWindowToTop() API static inline void wxBringWindowToTop(HWND hwnd) { @@ -405,25 +408,29 @@ bool wxWindowMSW::Create(wxWindow *parent, parent->AddChild(this); - // note that all windows are created visible by default WXDWORD exstyle; - DWORD msflags = WS_VISIBLE | MSWGetCreateWindowFlags(&exstyle); + DWORD msflags = MSWGetCreateWindowFlags(&exstyle); #ifdef __WXUNIVERSAL__ // no borders, we draw them ourselves - exstyle = 0; + exstyle &= ~(WS_EX_DLGMODALFRAME | + WS_EX_STATICEDGE | + WS_EX_CLIENTEDGE | + WS_EX_WINDOWEDGE); msflags &= ~WS_BORDER; #endif // wxUniversal + // all windows are created visible by default except popup ones (which are + // like the wxTopLevelWindows in this aspect) if ( style & wxPOPUP_WINDOW ) { - // a popup window floats on top of everything - exstyle |= WS_EX_TOPMOST | WS_EX_TOOLWINDOW; - - // it is also created hidden as other top level windows msflags &= ~WS_VISIBLE; m_isShown = FALSE; } + else + { + msflags |= WS_VISIBLE; + } return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle); } @@ -458,6 +465,20 @@ void wxWindowMSW::SetFocus() } } +void wxWindowMSW::SetFocusFromKbd() +{ + wxWindowBase::SetFocusFromKbd(); + + // when the focus is given to the control with DLGC_HASSETSEL style from + // keyboard its contents should be entirely selected: this is what + // ::IsDialogMessage() does and so we should do it as well to provide the + // same LNF as the native programs + if ( ::SendMessage(GetHwnd(), WM_GETDLGCODE, 0, 0) & DLGC_HASSETSEL ) + { + ::SendMessage(GetHwnd(), EM_SETSEL, 0, -1); + } +} + // Get the window with the focus wxWindow *wxWindowBase::FindFocus() { @@ -1978,12 +1999,21 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) return TRUE; } else // no default button -#endif // wxUSE_BUTTON { - // no special function for enter and don't even - // let IsDialogMessage() have it: it seems to - // do something really strange with it - return FALSE; +#endif // wxUSE_BUTTON + // this is a quick and dirty test for a text + // control + if ( !(lDlgCode & DLGC_HASSETSEL) ) + { + // don't process Enter, the control might + // need it for itself and don't let + // ::IsDialogMessage() have it as it can + // eat the Enter events sometimes + return FALSE; + } + //else: treat Enter as TAB: pass to the next + // control as this is the best thing to do + // if the text doesn't handle Enter itself } } } @@ -2036,10 +2066,18 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) } #endif // 1/0 - if ( ::IsDialogMessage(GetHwnd(), msg) ) + // we handle VK_ESCAPE ourselves in wxDialog::OnCharHook() and we + // shouldn't let IsDialogMessage() get it 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 ) { - // IsDialogMessage() did something... - return TRUE; + if ( ::IsDialogMessage(GetHwnd(), msg) ) + { + // IsDialogMessage() did something... + return TRUE; + } } } #endif // __WXUNIVERSAL__ @@ -2316,10 +2354,18 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam break; case WM_CLOSE: +#ifdef __WXUNIVERSAL__ + // Universal uses its own wxFrame/wxDialog, so we don't receive + // close events unless we have this. + Close(); + processed = TRUE; + rc.result = TRUE; +#else // don't let the DefWindowProc() destroy our window - we'll do it // ourselves in ~wxWindow processed = TRUE; rc.result = TRUE; +#endif break; case WM_SHOWWINDOW: @@ -2347,68 +2393,49 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDBLCLK: - { - processed = FALSE; + { #ifdef __WXMICROWIN__ // MicroWindows seems to ignore the fact that a window is // disabled. So catch mouse events and throw them away if // necessary. wxWindowMSW* win = this; - while (win) + for ( ;; ) { if (!win->IsEnabled()) { processed = TRUE; break; } + win = win->GetParent(); - if (win && win->IsTopLevel()) + if ( !win || win->IsTopLevel() ) break; } -#endif // __WXMICROWIN__ + if (!processed) +#endif // __WXMICROWIN__ { - if (message == WM_LBUTTONDOWN && AcceptsFocus()) + // VZ: why do we need it here? DefWindowProc() is supposed + // to do this for us anyhow + if ( message == WM_LBUTTONDOWN && AcceptsFocus() ) SetFocus(); - processed = HandleMouseEvent(message, - GET_X_LPARAM(lParam), - GET_Y_LPARAM(lParam), - wParam); - } - break; - } -#ifdef __WXMICROWIN__ - case WM_NCLBUTTONDOWN: - case WM_NCLBUTTONUP: - case WM_NCLBUTTONDBLCLK: - case WM_NCRBUTTONDOWN: - case WM_NCRBUTTONUP: - case WM_NCRBUTTONDBLCLK: -#if 0 - case WM_NCMBUTTONDOWN: - case WM_NCMBUTTONUP: - case WM_NCMBUTTONDBLCLK: -#endif - { - // MicroWindows seems to ignore the fact that a window - // is disabled. So catch mouse events and throw them away if necessary. - processed = FALSE; - wxWindowMSW* win = this; - while (win) - { - if (!win->IsEnabled()) + int x = GET_X_LPARAM(lParam), + y = GET_Y_LPARAM(lParam); + + // redirect the event to a static control if necessary + if (this == GetCapture()) { - processed = TRUE; - break; + processed = HandleMouseEvent(message, x, y, wParam); + } + else + { + wxWindowMSW *win = FindWindowForMouseEvent(this, &x, &y); //TW:REQ:Univ + processed = win->HandleMouseEvent(message, x, y, wParam); } - win = win->GetParent(); - if (win && win->IsTopLevel()) - break; } - break; } -#endif // __WXMICROWIN__ + break; #ifdef MM_JOY1MOVE case MM_JOY1MOVE: @@ -2491,15 +2518,19 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam break; } - // we consider these message "not interesting" to OnChar - if ( wParam == VK_SHIFT || wParam == VK_CONTROL ) - { - processed = TRUE; - break; - } - switch ( wParam ) { + // we consider these message "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 @@ -2544,23 +2575,9 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam break; #endif // VK_APPS - case VK_LEFT: - case VK_RIGHT: - case VK_DOWN: - case VK_UP: default: - 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 // do generate a CHAR event - { - processed = HandleChar((WORD)wParam, lParam); - } + // do generate a CHAR event + processed = HandleChar((WORD)wParam, lParam); } break; @@ -2586,7 +2603,18 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam case WM_SYSCHAR: case WM_CHAR: // Always an ASCII character - processed = HandleChar((WORD)wParam, lParam, TRUE); + 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; case WM_HSCROLL: @@ -2646,6 +2674,10 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam processed = HandlePaletteChanged((WXHWND) (HWND) wParam); break; + case WM_CAPTURECHANGED: + processed = HandleCaptureChanged((WXHWND) (HWND) lParam); + break; + case WM_QUERYNEWPALETTE: processed = HandleQueryNewPalette(); break; @@ -2814,6 +2846,9 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, int& x, int& y, int& w, int& h) const { + static const int DEFAULT_Y = 200; + static const int DEFAULT_H = 250; + bool nonDefault = FALSE; if ( pos.x == -1 ) @@ -2825,8 +2860,11 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, } 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 == -1 ? CW_USEDEFAULT : pos.y; + y = pos.y == -1 ? DEFAULT_Y : pos.y; nonDefault = TRUE; } @@ -2849,14 +2887,15 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, */ if ( size.x == -1 ) { - // as abobe, h is not used at all in this case anyhow + // as above, h is not used at all in this case anyhow w = h = CW_USEDEFAULT; } else { + // and, again as above, we can't set the height to CW_USEDEFAULT here w = size.x; - h = size.y == -1 ? CW_USEDEFAULT : size.y; + h = size.y == -1 ? DEFAULT_H : size.y; nonDefault = TRUE; } @@ -2879,31 +2918,19 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, wxWindow *parent = GetParent(); bool isChild = (style & WS_CHILD) != 0; HWND hParent; - if ( GetWindowStyleFlag() & wxPOPUP_WINDOW ) + if ( (isChild || HasFlag(wxPOPUP_WINDOW) || HasFlag(wxFRAME_TOOL_WINDOW)) ) { - // popup windows should have desktop as parent because they shouldn't - // be limited to the parents client area as child windows usually are - hParent = ::GetDesktopWindow(); + // this is either a normal child window, a popup window or a top level + // window with wxFRAME_TOOL_WINDOW style (see below) + hParent = parent ? GetHwndOf(parent) : NULL; } - else // !popup + else { - if ( (isChild || HasFlag(wxFRAME_TOOL_WINDOW)) && parent ) - { - // this is either a normal child window or a top level window with - // wxFRAME_TOOL_WINDOW style (see below) - hParent = GetHwndOf(parent); - } - else - { - // this is either a window for which no parent was specified (not - // much we can do then) or a frame without wxFRAME_TOOL_WINDOW - // style: we should use NULL parent HWND for it or it would be - // always on top of its parent which is not what we usually want - // (in fact, we only want it for frames with the special - // wxFRAME_TOOL_WINDOW as above) - hParent = NULL; - } - + // this is a frame without wxFRAME_TOOL_WINDOW style: we should use + // NULL parent HWND for it or it would be always on top of its parent + // which is not what we usually want (in fact, we only want it for + // frames with the special wxFRAME_TOOL_WINDOW as above) + hParent = NULL; } // controlId is menu handle for the top level windows, so set it to 0 @@ -3510,6 +3537,14 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange) return GetEventHandler()->ProcessEvent(event); } +bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture) +{ + wxMouseCaptureChangedEvent event(GetId(), wxFindWinFromHandle(hWndGainedCapture)); + event.SetEventObject(this); + + return GetEventHandler()->ProcessEvent(event); +} + bool wxWindowMSW::HandleQueryNewPalette() { @@ -3775,9 +3810,13 @@ bool wxWindowMSW::HandleMove(int x, int y) return GetEventHandler()->ProcessEvent(event); } -bool wxWindowMSW::HandleSize(int w, int h, WXUINT WXUNUSED(flag)) +bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), + WXUINT WXUNUSED(flag)) { - wxSizeEvent event(wxSize(w, h), m_windowId); + // don't use w and h parameters as they specify the client size while + // according to the docs EVT_SIZE handler is supposed to receive the total + // size + wxSizeEvent event(GetSize(), m_windowId); event.SetEventObject(this); return GetEventHandler()->ProcessEvent(event); @@ -3934,6 +3973,64 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event, #endif // wxUSE_MOUSEEVENT_HACK } +// Windows doesn't send the mouse events to the static controls (which are +// transparent in the sense that their WM_NCHITTEST handler returns +// HTTRANSPARENT) at all but we want all controls to receive the mouse events +// and so we manually check if we don't have a child window under mouse and if +// we do, send the event to it instead of the window Windows had sent WM_XXX +// to. +// +// Notice that this is not done for the mouse move events because this could +// (would?) be too slow, but only for clicks which means that the static texts +// still don't get move, enter nor leave events. +static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) //TW:REQ:Univ +{ + wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") ); + + // first try to find a non transparent child: this allows us to send events + // to a static text which is inside a static box, for example + POINT pt = { *x, *y }; + HWND hwnd = GetHwndOf(win), + hwndUnderMouse; + +#ifdef __WIN32__ + hwndUnderMouse = ::ChildWindowFromPointEx + ( + hwnd, + pt, + CWP_SKIPINVISIBLE | + CWP_SKIPDISABLED | + CWP_SKIPTRANSPARENT + ); + + if ( !hwndUnderMouse || hwndUnderMouse == hwnd ) +#endif // __WIN32__ + { + // now try any child window at all + hwndUnderMouse = ::ChildWindowFromPoint(hwnd, pt); + } + + // check that we have a child window which is susceptible to receive mouse + // events: for this it must be shown and enabled + if ( hwndUnderMouse && + hwndUnderMouse != hwnd && + ::IsWindowVisible(hwndUnderMouse) && + ::IsWindowEnabled(hwndUnderMouse) ) + { + wxWindow *winUnderMouse = wxFindWinFromHandle((WXHWND)hwndUnderMouse); + if ( winUnderMouse ) + { + // translate the mouse coords to the other window coords + win->ClientToScreen(x, y); + winUnderMouse->ScreenToClient(x, y); + + win = winUnderMouse; + } + } + + return win; +} + bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags) { // the mouse events take consecutive IDs from WM_MOUSEFIRST to @@ -4266,7 +4363,7 @@ bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) // --------------------------------------------------------------------------- bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam, - WXWORD pos, WXHWND control) + WXWORD pos, WXHWND control) { if ( control ) {