X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b889a3a24bda7d1e9d361d866ada776400b2fb81..a174f139e105c38ae852104eb6a894b3a0d88e07:/src/msw/window.cpp?ds=inline diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 742aa707aa..3dd8c2240e 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -118,7 +118,6 @@ #endif #endif - // --------------------------------------------------------------------------- // global variables // --------------------------------------------------------------------------- @@ -378,7 +377,7 @@ bool wxWindowMSW::Create(wxWindow *parent, // // the correct solution is to create the controls as siblings of the // static box - wxASSERT_MSG( !wxDynamicCastThis(wxStaticBox), + wxASSERT_MSG( !wxDynamicCast(parent, wxStaticBox), _T("wxStaticBox can't be used as a window parent!") ); #endif // wxUSE_STATBOX @@ -826,36 +825,23 @@ int wxWindowMSW::GetScrollThumb(int orient) const void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh) { -#if defined(__WIN95__) - SCROLLINFO info; - int dir; + HWND hWnd = GetHwnd(); + wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") ); - if ( orient == wxHORIZONTAL ) { - dir = SB_HORZ; - } else { - dir = SB_VERT; - } + int dir = orient == wxHORIZONTAL ? SB_HORZ : SB_VERT; +#if defined(__WIN95__) + SCROLLINFO info; info.cbSize = sizeof(SCROLLINFO); info.nPage = 0; info.nMin = 0; info.nPos = pos; info.fMask = SIF_POS; - HWND hWnd = GetHwnd(); - if ( hWnd ) - ::SetScrollInfo(hWnd, dir, &info, refresh); -#else - int wOrient; - if ( orient == wxHORIZONTAL ) - wOrient = SB_HORZ; - else - wOrient = SB_VERT; - - HWND hWnd = GetHwnd(); - if ( hWnd ) - ::SetScrollPos(hWnd, wOrient, pos, refresh); -#endif + ::SetScrollInfo(hWnd, dir, &info, refresh); +#else // !__WIN95__ + ::SetScrollPos(hWnd, dir, pos, refresh); +#endif // __WIN95__/!__WIN95__ } // New function that will replace some of the above. @@ -982,11 +968,11 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) wxAssociateWinWithHandle(hwnd, this); - m_oldWndProc = (WXFARPROC)::GetWindowLong(hwnd, GWL_WNDPROC); - + m_oldWndProc = (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC); + // we don't need to subclass the window of our own class (in the Windows // sense of the word) - if ( (WXFARPROC) m_oldWndProc != (WXFARPROC) wxWndProc ) + if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) ) { ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc); } @@ -1011,8 +997,7 @@ void wxWindowMSW::UnsubclassWin() if ( m_oldWndProc ) { - FARPROC wndProc = (FARPROC)::GetWindowLong(hwnd, GWL_WNDPROC); - if ( wndProc != (FARPROC) m_oldWndProc ) + if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) ) { ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc); } @@ -1022,6 +1007,35 @@ 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!! + + static wxChar buffer[512]; + WNDCLASS cls; + + ::GetClassName((HWND)hWnd, buffer, 512); + ::GetClassInfo(wxGetInstance(), buffer, &cls); + return wndProc == (WXFARPROC)cls.lpfnWndProc; +#else + return wndProc == (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC); +#endif +} + + // Make a Windows extended style from the given wxWindows window style WXDWORD wxWindowMSW::MakeExtendedStyle(long style, bool eliminateBorders) { @@ -1234,7 +1248,9 @@ void wxWindowMSW::Clear() static inline void SendSetRedraw(HWND hwnd, bool on) { +#ifndef __WXMICROWIN__ ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0); +#endif } void wxWindowMSW::Freeze() @@ -1430,6 +1446,12 @@ void wxWindowMSW::DoClientToScreen(int *x, int *y) const 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 ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) ) { wxLogLastError(wxT("MoveWindow")); @@ -1505,40 +1527,67 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) void wxWindowMSW::DoSetClientSize(int width, int height) { - wxWindow *parent = GetParent(); - HWND hWnd = GetHwnd(); - HWND hParentWnd = (HWND) 0; - if ( parent ) - hParentWnd = (HWND) parent->GetHWND(); + // setting the client size is less obvious than it it could have been + // because in the result of changing the total size the window scrollbar + // may [dis]appear and/or its menubar may [un]wrap and so the client size + // will not be correct as the difference between the total and client size + // changes - so we keep changing it until we get it right + // + // normally this loop shouldn't take more than 3 iterations (usually 1 but + // if scrollbars [dis]appear as the result of the first call, then 2 and it + // may become 3 if the window had 0 size originally and so we didn't + // calculate the scrollbar correction correctly during the first iteration) + // but just to be on the safe side we check for it instead of making it an + // "infinite" loop (i.e. leaving break inside as the only way to get out) + for ( int i = 0; i < 4; i++ ) + { + RECT rectClient; + ::GetClientRect(GetHwnd(), &rectClient); - RECT rect; - ::GetClientRect(hWnd, &rect); + // if the size is already ok, stop here (rectClient.left = top = 0) + if ( rectClient.right == width && rectClient.bottom == height ) + { + break; + } + + if ( i == 3 ) + { + // how did it happen? maybe OnSize() handler does something really + // strange in this class? + wxFAIL_MSG( _T("logic error in DoSetClientSize") ); + + break; + } - RECT rect2; - GetWindowRect(hWnd, &rect2); + int widthClient = width, + heightClient = height; - // Find the difference between the entire window (title bar and all) - // and the client area; add this to the new client size to move the - // window - int actual_width = rect2.right - rect2.left - rect.right + width; - int actual_height = rect2.bottom - rect2.top - rect.bottom + height; + // 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); - // If there's a parent, must subtract the parent's top left corner - // since MoveWindow moves relative to the parent + widthClient += rectWin.right - rectWin.left - rectClient.right; + heightClient += rectWin.bottom - rectWin.top - rectClient.bottom; - POINT point; - point.x = rect2.left; - point.y = rect2.top; - if ( parent ) - { - ::ScreenToClient(hParentWnd, &point); - } + POINT point; + point.x = rectWin.left; + point.y = rectWin.top; - DoMoveWindow(point.x, point.y, actual_width, actual_height); + // MoveWindow positions the child windows relative to the parent, so + // adjust if necessary + if ( !IsTopLevel() ) + { + wxWindow *parent = GetParent(); + if ( parent ) + { + ::ScreenToClient(GetHwndOf(parent), &point); + } + } - wxSizeEvent event(wxSize(width, height), m_windowId); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + DoMoveWindow(point.x, point.y, widthClient, heightClient); + } } // For implementation purposes - sometimes decorations make the client area @@ -2562,7 +2611,10 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam break; #endif // __WIN32__ -#ifdef __WXUNIVERSAL__ + // unfortunately this doesn't really work as then window which + // doesn't accept focus doesn't get any mouse events neither which + // means it can't get any input at all +#if 0 //def __WXUNIVERSAL__ case WM_NCHITTEST: // we shouldn't allow the windows which don't want to get focus to // get it @@ -2591,14 +2643,11 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam // wxWindow <-> HWND map // ---------------------------------------------------------------------------- -wxList *wxWinHandleList = NULL; +wxWinHashTable *wxWinHandleHash = NULL; wxWindow *wxFindWinFromHandle(WXHWND hWnd) { - wxNode *node = wxWinHandleList->Find((long)hWnd); - if ( !node ) - return NULL; - return (wxWindow *)node->Data(); + return wxWinHandleHash->Get((long)hWnd); } void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) @@ -2619,13 +2668,13 @@ void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) #endif // __WXDEBUG__ if (!oldWin) { - wxWinHandleList->Append((long)hWnd, win); + wxWinHandleHash->Put((long)hWnd, (wxWindow *)win); } } void wxRemoveHandleAssociation(wxWindowMSW *win) { - wxWinHandleList->DeleteObject(win); + wxWinHandleHash->Delete((long)win->GetHWND()); } // ---------------------------------------------------------------------------- @@ -3064,11 +3113,9 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) { #ifndef __WXMICROWIN__ HDROP hFilesInfo = (HDROP) wParam; - POINT dropPoint; - DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint); // Get the total number of files dropped - WORD gwFilesDropped = (WORD)::DragQueryFile + UINT gwFilesDropped = ::DragQueryFile ( (HDROP)hFilesInfo, (UINT)-1, @@ -3077,24 +3124,28 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) ); wxString *files = new wxString[gwFilesDropped]; - int wIndex; - for (wIndex=0; wIndex < (int)gwFilesDropped; wIndex++) + for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ ) { - DragQueryFile (hFilesInfo, wIndex, (LPTSTR) wxBuffer, 1000); - files[wIndex] = wxBuffer; + // first get the needed buffer length (+1 for terminating NUL) + size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1; + + // and now get the file name + ::DragQueryFile(hFilesInfo, wIndex, + files[wIndex].GetWriteBuf(len), len); + + files[wIndex].UngetWriteBuf(); } DragFinish (hFilesInfo); wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files); event.m_eventObject = this; + + POINT dropPoint; + DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint); event.m_pos.x = dropPoint.x; event.m_pos.y = dropPoint.y; - bool rc = GetEventHandler()->ProcessEvent(event); - - delete[] files; - - return rc; + return GetEventHandler()->ProcessEvent(event); #else // __WXMICROWIN__ return FALSE; #endif @@ -3267,7 +3318,11 @@ bool wxWindowMSW::HandleSysColorChange() wxSysColourChangedEvent event; event.SetEventObject(this); - return GetEventHandler()->ProcessEvent(event); + (void)GetEventHandler()->ProcessEvent(event); + + // always let the system carry on the default processing to allow the + // native controls to react to the colours update + return FALSE; } bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, @@ -3334,19 +3389,35 @@ bool wxWindowMSW::HandleQueryNewPalette() // Responds to colour changes: passes event on to children. void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& event) { - wxNode *node = GetChildren().First(); + wxWindowList::Node *node = GetChildren().GetFirst(); while ( node ) { - // Only propagate to non-top-level windows - wxWindow *win = (wxWindow *)node->Data(); - if ( win->GetParent() ) + // Only propagate to non-top-level windows because Windows already + // sends this event to all top-level ones + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() ) { - wxSysColourChangedEvent event2; - event.m_eventObject = win; - win->GetEventHandler()->ProcessEvent(event2); + // we need to send the real WM_SYSCOLORCHANGE and not just trigger + // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for + // the standard controls + ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0); } - node = node->Next(); + node = node->GetNext(); + } + + // update the colours we use if they were not set explicitly by the user: + // this must be done or OnCtlColor() would continue to use the old colours + if ( !m_hasFgCol ) + { + m_foregroundColour = wxSystemSettings:: + GetSystemColour(wxSYS_COLOUR_WINDOWTEXT); + } + + if ( !m_hasBgCol ) + { + m_backgroundColour = wxSystemSettings:: + GetSystemColour(wxSYS_COLOUR_BTNFACE); } } @@ -3523,7 +3594,7 @@ bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo) bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) { #if wxUSE_MENUS_NATIVE - if ( wxCurrentPopupMenu ) + if ( !cmd && wxCurrentPopupMenu ) { wxMenu *popupMenu = wxCurrentPopupMenu; wxCurrentPopupMenu = NULL; @@ -3532,18 +3603,20 @@ bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) } #endif // wxUSE_MENUS_NATIVE - wxWindow *win = (wxWindow*) NULL; - if ( cmd == 0 || cmd == 1 ) // menu or accel - use id + wxWindow *win = NULL; + + // first try to find it from HWND - this works even with the broken + // programs using the same ids for different controls + if ( control ) { - // must cast to a signed type before comparing with other ids! - win = FindItem((signed short)id); + win = wxFindWinFromHandle(control); } - if (!win && control) + // try the id + if ( !win ) { - // find it from HWND - this works even with the broken programs using - // the same ids for different controls - win = wxFindWinFromHandle(control); + // must cast to a signed type before comparing with other ids! + win = FindItem((signed short)id); } if ( win ) @@ -4287,11 +4360,13 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) // FIXME: this is clearly not the best way to do it but I think we'll // need to change HWND <-> wxWindow code more heavily than I can // do it now to fix it +#ifndef __WXMICROWIN__ if ( ::GetWindow(hwnd, GW_OWNER) ) { // it's a dialog box, don't go upwards break; } +#endif hwnd = ::GetParent(hwnd); win = wxFindWinFromHandle((WXHWND)hwnd);