X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/61179e28bd7f9e29af93582326919b91549db357..7b35aa40a06a160ae4a8650c5820880a020697e3:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 5dc59b9efb..07d4a17190 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -312,14 +312,14 @@ void wxWindowMSW::Init() InitBase(); // MSW specific - m_doubleClickAllowed = 0; - m_isBeingDeleted = FALSE; - m_oldWndProc = 0; + m_oldWndProc = NULL; m_useCtl3D = FALSE; m_mouseInWindow = FALSE; m_lastKeydownProcessed = FALSE; + m_childrenDisabled = NULL; + // wxWnd m_hMenu = 0; @@ -380,6 +380,8 @@ wxWindowMSW::~wxWindowMSW() // remove hWnd <-> wxWindow association wxRemoveHandleAssociation(this); } + + delete m_childrenDisabled; } // real construction (Init() must have been called before!) @@ -500,19 +502,58 @@ bool wxWindowMSW::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 ) + // the logic below doesn't apply to the top level windows -- otherwise + // showing a modal dialog would result in total greying out (and ungreying + // out later) of everything which would be really ugly + if ( IsTopLevel() ) + return TRUE; + + // when the parent is disabled, all of its children should be disabled as + // well but when it is enabled back, only those of the children which + // hadn't been already disabled in the beginning should be enabled again, + // so we have to keep the list of those children + for ( wxWindowList::Node *node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) { wxWindow *child = node->GetData(); - child->Enable(enable); + if ( child->IsTopLevel() ) + { + // the logic below doesn't apply to top level children + continue; + } - node = node->GetNext(); + if ( enable ) + { + // enable the child back unless it had been disabled before us + if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) ) + child->Enable(); + } + else // we're being disabled + { + if ( child->IsEnabled() ) + { + // disable it as children shouldn't stay enabled while the + // parent is not + child->Disable(); + } + else // child already disabled, remember it + { + // have we created the list of disabled children already? + if ( !m_childrenDisabled ) + m_childrenDisabled = new wxWindowList; + + m_childrenDisabled->Append(child); + } + } + } + + if ( enable && m_childrenDisabled ) + { + // we don't need this list any more, don't keep unused memory + delete m_childrenDisabled; + m_childrenDisabled = NULL; } -#endif // 0 return TRUE; } @@ -993,7 +1034,10 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) } else { - // don't bother restoring it neither + // don't bother restoring it neither: this also makes it easy to + // implement IsOfStandardClass() method which returns TRUE for the + // standard controls and FALSE for the wxWindows own windows as it can + // simply check m_oldWndProc m_oldWndProc = NULL; } } @@ -1024,35 +1068,21 @@ void wxWindowMSW::UnsubclassWin() bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC wndProc) { -#if wxUSE_UNICODE_MSLU - // VS: We can't use GetWindowLong(hwnd, GWL_WNDPROC) together with unicows.dll - // because it doesn't return pointer to the real wnd proc but rather a handle - // of a fake proc that does Unicode<->ANSI translation. - // - // The hack bellow works, because WNDCLASS contains original window handler - // rather that the unicows fake one. This may not be on purpose, though; if - // it stops working with future versions of unicows.dll, we can override - // unicows hooks by setting Unicows_{Set,Get}WindowLong and - // Unicows_RegisterClass to our own versions that keep track of - // fake<->real wnd proc mapping. - // - // FIXME: Doesn't handle wnd procs set by SetWindowLong, only these set - // with RegisterClass!! - - if ( wxUsingUnicowsDll() ) + // Unicows note: the code below works, but only because WNDCLASS contains + // original window handler rather that the unicows fake one. This may not + // be on purpose, though; if it stops working with future versions of + // unicows.dll, we can override unicows hooks by setting + // Unicows_{Set,Get}WindowLong and Unicows_RegisterClass to our own + // versions that keep track of fake<->real wnd proc mapping. + WNDCLASS cls; + if ( !::GetClassInfo(wxGetInstance(), wxGetWindowClass(hWnd), &cls) ) { - static wxChar buffer[512]; - WNDCLASS cls; + wxLogLastError(_T("GetClassInfo")); - ::GetClassName((HWND)hWnd, buffer, 512); - ::GetClassInfo(wxGetInstance(), buffer, &cls); - return wndProc == (WXFARPROC)cls.lpfnWndProc; - } - else -#endif - { - return wndProc == (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC); + return FALSE; } + + return wndProc == (WXFARPROC)cls.lpfnWndProc; } // ---------------------------------------------------------------------------- @@ -1164,12 +1194,15 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const break; } + // wxUniv doesn't use Windows dialog navigation functions at all +#ifndef __WXUNIVERSAL__ // to make the dialog navigation work with the nested panels we must - // use this style - if ( flags & wxTAB_TRAVERSAL ) + // use this style (top level windows such as dialogs don't need it) + if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() ) { *exstyle |= WS_EX_CONTROLPARENT; } +#endif // __WXUNIVERSAL__ } return style; @@ -1430,11 +1463,15 @@ void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect) void wxWindowMSW::Update() { +#ifdef __WXWINE__ + ::UpdateWindow(GetHwnd()); +#else if ( !::UpdateWindow(GetHwnd()) ) { wxLogLastError(_T("UpdateWindow")); } - +#endif + #if defined(__WIN32__) && !defined(__WXMICROWIN__) // just calling UpdateWindow() is not enough, what we did in our WM_PAINT // handler needs to be really drawn right now @@ -1912,14 +1949,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) // here we try to do all the job which ::IsDialogMessage() usually does // internally #if 1 - bool bProcess = TRUE; - if ( msg->message != WM_KEYDOWN ) - bProcess = FALSE; - - if ( bProcess && (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - bProcess = FALSE; - - if ( bProcess ) + if ( msg->message == WM_KEYDOWN ) { bool bCtrlDown = wxIsCtrlDown(); bool bShiftDown = wxIsShiftDown(); @@ -1936,6 +1966,8 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) bool bForward = TRUE, bWindowChange = FALSE; + // should we process this message specially? + bool bProcess = TRUE; switch ( msg->wParam ) { case VK_TAB: @@ -2080,9 +2112,9 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) // place edit control from being closed with Escape in a dialog if ( msg->message != WM_KEYDOWN || msg->wParam != VK_ESCAPE ) { - // ::IsDialogMessage() can enter in an infinite loop when - // WS_EX_CONTROLPARENT is specified and the currently focused - // window is disabled or hidden, so don't call it in this case + // ::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 bool canSafelyCallIsDlgMsg = TRUE; HWND hwndFocus = ::GetFocus(); @@ -2097,6 +2129,14 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) 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); } @@ -2256,7 +2296,7 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w // trace all messages - useful for the debugging #ifdef __WXDEBUG__ wxLogTrace(wxTraceMessages, wxT("Processing %s(wParam=%8lx, lParam=%8lx)"), - wxGetMessageName(message), wParam, lParam); + wxGetMessageName(message), (long) wParam, lParam); #endif // __WXDEBUG__ wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd); @@ -2439,28 +2479,36 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam break; } - if (!processed) + if ( processed ) + break; + #endif // __WXMICROWIN__ - { - // VZ: why do we need it here? DefWindowProc() is supposed - // to do this for us anyhow - if ( message == WM_LBUTTONDOWN && AcceptsFocus() ) - SetFocus(); + // VZ: if you find a situation when this is needed, tell + // me about it, do *not* uncomment this code as it + // causes other strange problems +#if 0 + if ( message == WM_LBUTTONDOWN && AcceptsFocus() ) + SetFocus(); +#endif // 0 - int x = GET_X_LPARAM(lParam), - y = GET_Y_LPARAM(lParam); + int x = GET_X_LPARAM(lParam), + y = GET_Y_LPARAM(lParam); - // redirect the event to a static control if necessary - if (this == GetCapture()) - { - processed = HandleMouseEvent(message, x, y, wParam); - } - else - { - wxWindowMSW *win = FindWindowForMouseEvent(this, &x, &y); //TW:REQ:Univ - processed = win->HandleMouseEvent(message, x, y, wParam); - } + // redirect the event to a static control if necessary by + // finding one under mouse + 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); } + + processed = win->HandleMouseEvent(message, x, y, wParam); } break; @@ -2524,11 +2572,19 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam #endif // defined(WM_DRAWITEM) case WM_GETDLGCODE: - if ( GetWindowStyleFlag() & wxWANTS_CHARS ) + if ( !IsOfStandardClass() ) { - // want everything: i.e. all keys and WM_CHAR message - rc.result = DLGC_WANTARROWS | DLGC_WANTCHARS | - DLGC_WANTTAB | DLGC_WANTMESSAGE; + // 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() @@ -2843,7 +2899,7 @@ void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) if ( oldWin && (oldWin != win) ) { wxLogDebug(wxT("HWND %X already associated with another window (%s)"), - hWnd, win->GetClassInfo()->GetClassName()); + (int) hWnd, win->GetClassInfo()->GetClassName()); } else #endif // __WXDEBUG__ @@ -2932,7 +2988,7 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, WXHWND wxWindowMSW::MSWGetParent() const { - return m_parent ? m_parent->GetHWND() : NULL; + return m_parent ? m_parent->GetHWND() : WXHWND(NULL); } bool wxWindowMSW::MSWCreate(const wxChar *wclass, @@ -2948,20 +3004,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, // controlId is menu handle for the top level windows, so set it to 0 // unless we're creating a child window - int controlId; - if ( style & WS_CHILD ) - { - controlId = GetId(); - - if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS ) - { - style |= WS_CLIPSIBLINGS; - } - } - else // !child - { - controlId = 0; - } + 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 @@ -3011,7 +3054,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, // --------------------------------------------------------------------------- #ifdef __WIN95__ -// FIXME: VZ: I'm not sure at all that the order of processing is correct + bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) { #ifndef __WXMICROWIN__ @@ -3019,12 +3062,19 @@ bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) HWND hWnd = hdr->hwndFrom; wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd); - // is this one of our windows? + // 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::Node *node = GetChildren().GetFirst(); while ( node ) @@ -3037,32 +3087,92 @@ bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) node = node->GetNext(); } +#endif // 0 - // finally try this window too (catches toolbar case) + // 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 + + if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW) || ttip.empty() ) + { + // not a tooltip message or no tooltip to show anyhow + return FALSE; + } + + LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam; + + if ( code == (WXUINT) TTN_NEEDTEXTA ) + { + ttText->lpszText = (wxChar *)ttip.c_str(); + } + else + { +#if wxUSE_UNICODE + ttText->lpszText = (wxChar *)ttip.c_str(); +#else // !Unicode + size_t lenAnsi = ttip.length(); + + // some compilers (MetroWerks and Cygwin) don't like calling mbstowcs + // with NULL argument + #if defined( __MWERKS__ ) || defined( __CYGWIN__ ) + size_t lenUnicode = 2*lenAnsi; + #else + size_t lenUnicode = mbstowcs(NULL, ttip, lenAnsi); + #endif + + // using the pointer of right type avoids us doing all sorts of + // pointer arithmetics ourselves + wchar_t *dst = (wchar_t *)ttText->szText, + *pwz = new wchar_t[lenUnicode + 1]; + mbstowcs(pwz, ttip, lenAnsi + 1); + memcpy(dst, pwz, lenUnicode*sizeof(wchar_t)); + + // put the terminating wide NUL + dst[lenUnicode] = L'\0'; + + delete [] pwz; +#endif // Unicode/!Unicode + } + + return TRUE; +} + +#endif // wxUSE_TOOLTIPS + bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl), - WXLPARAM lParam, - WXLPARAM* WXUNUSED(result)) + WXLPARAM lParam, + WXLPARAM* WXUNUSED(result)) { #if wxUSE_TOOLTIPS - NMHDR* hdr = (NMHDR *)lParam; - if ( (int)hdr->code == TTN_NEEDTEXT && m_tooltip ) + if ( m_tooltip ) { - TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam; - ttt->lpszText = (wxChar *)m_tooltip->GetTip().c_str(); - - // processed - return TRUE; + NMHDR* hdr = (NMHDR *)lParam; + if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip())) + { + // processed + return TRUE; + } } #endif // wxUSE_TOOLTIPS return FALSE; } + #endif // __WIN95__ // --------------------------------------------------------------------------- @@ -3123,7 +3233,7 @@ bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT cs, bool *mayCreate) { // there is no need to do anything for the top level windows const wxWindow *parent = GetParent(); - if ( parent && !parent->IsTopLevel() ) + while ( parent && !parent->IsTopLevel() ) { LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE); if ( !(exStyle & WS_EX_CONTROLPARENT) ) @@ -3132,6 +3242,8 @@ bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT cs, bool *mayCreate) ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE, exStyle | WS_EX_CONTROLPARENT); } + + parent = parent->GetParent(); } } @@ -3233,6 +3345,13 @@ bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) } #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); @@ -3537,7 +3656,7 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange) if ( hWndPalChange != GetHWND() ) { // check to see if we our our parents have a custom palette - wxWindow *win = this; + wxWindowMSW *win = this; while ( win && !win->HasCustomPalette() ) { win = win->GetParent(); @@ -3586,7 +3705,7 @@ bool wxWindowMSW::HandleQueryNewPalette() #if wxUSE_PALETTE // check to see if we our our parents have a custom palette - wxWindow *win = this; + wxWindowMSW *win = this; while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent(); if (win->HasCustomPalette()) { /* realize the palette to see whether redrawing is needed */ @@ -4221,7 +4340,9 @@ bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) int id; if ( isASCII ) { - // If 1 -> 26, translate to CTRL plus a letter. + // If 1 -> 26, translate to either special keycode or just set + // ctrlDown. IOW, Ctrl-C should result in keycode == 3 and + // ControlDown() == TRUE. id = wParam; if ( (id > 0) && (id < 27) ) { @@ -4241,7 +4362,7 @@ bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII) default: ctrlDown = TRUE; - id = id + 'a' - 1; + break; } } }