X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/65fd5cb0124e62ab1fc41f93382a205d95b00e75..737255678cb96a8296348fb62603afdd28133ec5:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index b9dfdd75e1..ec39a8be1d 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -54,9 +54,8 @@ #include "wx/ownerdrw.h" #endif -#if wxUSE_DRAG_AND_DROP - #include "wx/dataobj.h" - #include "wx/msw/ole/droptgt.h" +#if wxUSE_DRAG_AND_DROP + #include "wx/dnd.h" #endif #include "wx/menuitem.h" @@ -75,8 +74,8 @@ #include "wx/intl.h" #include "wx/log.h" - #include "wx/textctrl.h" +#include "wx/notebook.h" #include @@ -96,7 +95,7 @@ #ifndef __TWIN32__ #ifdef __GNUWIN32__ #ifndef wxUSE_NORLANDER_HEADERS - #include + #include "wx/msw/gnuwin32/extra.h" #endif #endif #endif @@ -120,14 +119,14 @@ extern MSG s_currentMsg; wxMenu *wxCurrentPopupMenu = NULL; extern wxList WXDLLEXPORT wxPendingDelete; -extern wxChar wxCanvasClassName[]; +extern const wxChar *wxCanvasClassName; // --------------------------------------------------------------------------- // private functions // --------------------------------------------------------------------------- // the window proc for all our windows -LRESULT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #ifdef __WXDEBUG__ @@ -142,9 +141,7 @@ wxWindow *wxFindWinFromHandle(WXHWND hWnd); // event tables // --------------------------------------------------------------------------- -#if !USE_SHARED_LIBRARY IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) -#endif BEGIN_EVENT_TABLE(wxWindow, wxWindowBase) EVT_ERASE_BACKGROUND(wxWindow::OnEraseBackground) @@ -162,8 +159,19 @@ END_EVENT_TABLE() // --------------------------------------------------------------------------- // Find an item given the MS Windows id -wxWindow *wxWindow::FindItem(int id) const +wxWindow *wxWindow::FindItem(long id) const { + wxControl *item = wxDynamicCast(this, wxControl); + if ( item ) + { + // i it we or one of our "internal" children? + if ( item->GetId() == id || + (item->GetSubcontrols().Index(id) != wxNOT_FOUND) ) + { + return item; + } + } + wxWindowList::Node *current = GetChildren().GetFirst(); while (current) { @@ -173,19 +181,6 @@ wxWindow *wxWindow::FindItem(int id) const if ( wnd ) return wnd; - if ( childWin->IsKindOf(CLASSINFO(wxControl)) ) - { - wxControl *item = (wxControl *)childWin; - if ( item->GetId() == id ) - return item; - else - { - // In case it's a 'virtual' control (e.g. radiobox) - if ( item->GetSubcontrols().Member((wxObject *)id) ) - return item; - } - } - current = current->GetNext(); } @@ -297,7 +292,7 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, long style, const wxString& name) { - wxCHECK_MSG( parent, FALSE, _T("can't create wxWindow without parent") ); + wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") ); if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) return FALSE; @@ -373,6 +368,15 @@ bool wxWindow::Enable(bool enable) if ( hWnd ) ::EnableWindow(hWnd, (BOOL)enable); + wxWindowList::Node *node = GetChildren().GetFirst(); + while ( node ) + { + wxWindow *child = node->GetData(); + child->Enable(enable); + + node = node->GetNext(); + } + return TRUE; } @@ -448,7 +452,7 @@ bool wxWindow::SetFont(const wxFont& font) { WXHANDLE hFont = m_font.GetResourceHandle(); - wxASSERT_MSG( hFont, _T("should have valid font") ); + wxASSERT_MSG( hFont, wxT("should have valid font") ); ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); } @@ -464,7 +468,7 @@ bool wxWindow::SetCursor(const wxCursor& cursor) } wxASSERT_MSG( m_cursor.Ok(), - _T("cursor must be valid after call to the base version")); + wxT("cursor must be valid after call to the base version")); HWND hWnd = GetHwnd(); @@ -801,10 +805,10 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) void wxWindow::SubclassWin(WXHWND hWnd) { - wxASSERT_MSG( !m_oldWndProc, _T("subclassing window twice?") ); + wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") ); HWND hwnd = (HWND)hWnd; - wxCHECK_RET( ::IsWindow(hwnd), _T("invalid HWND in SubclassWin") ); + wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") ); wxAssociateWinWithHandle(hwnd, this); @@ -822,7 +826,7 @@ void wxWindow::UnsubclassWin() { m_hWnd = 0; - wxCHECK_RET( ::IsWindow(hwnd), _T("invalid HWND in SubclassWin") ); + wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") ); FARPROC farProc = (FARPROC) GetWindowLong(hwnd, GWL_WNDPROC); if ( (m_oldWndProc != 0) && (farProc != (FARPROC) m_oldWndProc) ) @@ -1174,6 +1178,14 @@ void wxWindow::DoGetClientSize(int *x, int *y) const *y = rect.bottom; } +void wxWindow::DoMoveWindow(int x, int y, int width, int height) +{ + if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) ) + { + wxLogLastError("MoveWindow"); + } +} + // 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 @@ -1197,9 +1209,9 @@ void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags) return; } - if ( x == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) x = currentX; - if ( y == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) y = currentY; AdjustForParentClientOrigin(x, y, sizeFlags); @@ -1207,7 +1219,7 @@ void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags) wxSize size(-1, -1); if ( width == -1 ) { - if ( sizeFlags && wxSIZE_AUTO_WIDTH ) + if ( sizeFlags & wxSIZE_AUTO_WIDTH ) { size = DoGetBestSize(); width = size.x; @@ -1221,11 +1233,11 @@ void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags) if ( height == -1 ) { - if ( sizeFlags && wxSIZE_AUTO_HEIGHT ) + if ( sizeFlags & wxSIZE_AUTO_HEIGHT ) { if ( size.x == -1 ) { - size= DoGetBestSize(); + size = DoGetBestSize(); } //else: already called DoGetBestSize() above @@ -1238,16 +1250,7 @@ void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags) } } - if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) ) - { - wxLogLastError("MoveWindow"); - } -} - -// for a generic window there is no natural best size - just use the current one -wxSize wxWindow::DoGetBestSize() -{ - return GetSize(); + DoMoveWindow(x, y, width, height); } void wxWindow::DoSetClientSize(int width, int height) @@ -1281,7 +1284,7 @@ void wxWindow::DoSetClientSize(int width, int height) ::ScreenToClient(hParentWnd, &point); } - MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE); + DoMoveWindow(point.x, point.y, actual_width, actual_height); wxSizeEvent event(wxSize(width, height), m_windowId); event.SetEventObject(this); @@ -1466,6 +1469,10 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) { // intercept dialog navigation keys MSG *msg = (MSG *)pMsg; + + // here we try to do all the job which ::IsDialogMessage() usually does + // internally +#if 0 bool bProcess = TRUE; if ( msg->message != WM_KEYDOWN ) bProcess = FALSE; @@ -1583,6 +1590,36 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) } } } +#else + // let ::IsDialogMessage() do almost everything and handle just the + // things it doesn't here: Ctrl-TAB for switching notebook pages + if ( msg->message == WM_KEYDOWN ) + { + // don't process system keys here + if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) ) + { + if ( (msg->wParam == VK_TAB) && + (::GetKeyState(VK_CONTROL) & 0x100) != 0 ) + { + // find the first notebook parent and change its page + wxWindow *win = this; + wxNotebook *nbook = NULL; + while ( win && !nbook ) + { + nbook = wxDynamicCast(win, wxNotebook); + win = win->GetParent(); + } + + if ( nbook ) + { + bool forward = !(::GetKeyState(VK_SHIFT) & 0x100); + + nbook->AdvanceSelection(forward); + } + } + } + } +#endif // 0 if ( ::IsDialogMessage(GetHwnd(), msg) ) return TRUE; @@ -1705,11 +1742,11 @@ void wxWindow::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, wxWindow *wxWndHook = NULL; // Main window proc -LRESULT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { // trace all messages - useful for the debugging #ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, _T("Processing %s(wParam=%8lx, lParam=%8lx)"), + wxLogTrace(wxTraceMessages, wxT("Processing %s(wParam=%8lx, lParam=%8lx)"), wxGetMessageName(message), wParam, lParam); #endif // __WXDEBUG__ @@ -1719,6 +1756,12 @@ LRESULT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARA // it with wxWindow stored in wxWndHook if ( !wnd && wxWndHook ) { +#if 0 // def __WXDEBUG__ + char buf[512]; + ::GetClassNameA((HWND) hWnd, buf, 512); + wxString className(buf); +#endif + wxAssociateWinWithHandle(hWnd, wxWndHook); wnd = wxWndHook; wxWndHook = NULL; @@ -1823,7 +1866,20 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) break; case WM_MOUSEMOVE: + { + short x = LOWORD(lParam); + short y = HIWORD(lParam); + + processed = HandleMouseMove(x, y, wParam); + } + break; + case WM_LBUTTONDOWN: + // set focus to this window + SetFocus(); + + // fall through + case WM_LBUTTONUP: case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: @@ -1933,6 +1989,8 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) case VK_RETURN: case VK_BACK: case VK_TAB: + case VK_ADD: + case VK_SUBTRACT: // 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 @@ -2088,7 +2146,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) if ( !processed ) { #ifdef __WXDEBUG__ - wxLogTrace(wxTraceMessages, _T("Forwarding %s to DefWindowProc."), + wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."), wxGetMessageName(message)); #endif // __WXDEBUG__ rc.result = MSWDefWindowProc(message, wParam, lParam); @@ -2124,19 +2182,44 @@ wxWindow *wxFindWinFromHandle(WXHWND hWnd) return (wxWindow *)node->Data(); } +#if 0 // def __WXDEBUG__ +static int gs_AssociationCount = 0; +#endif + void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win) { // adding NULL hWnd is (first) surely a result of an error and // (secondly) breaks menu command processing wxCHECK_RET( hWnd != (HWND)NULL, - _T("attempt to add a NULL hWnd to window list ignored") ); + wxT("attempt to add a NULL hWnd to window list ignored") ); + + + wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd); + if ( oldWin && (oldWin != win) ) + { + wxString str(win->GetClassInfo()->GetClassName()); + wxLogError(wxT("Bug! Found existing HWND %X for new window of class %s"), (int) hWnd, (const wxChar*) str); + } + else if (!oldWin) + { +#if 0 // def __WXDEBUG__ + gs_AssociationCount ++; + wxLogDebug("+ Association %d", gs_AssociationCount); +#endif - if ( !wxWinHandleList->Find((long)hWnd) ) wxWinHandleList->Append((long)hWnd, win); + } } void wxRemoveHandleAssociation(wxWindow *win) { +#if 0 // def __WXDEBUG__ + if (wxWinHandleList->Member(win)) + { + wxLogDebug("- Association %d", gs_AssociationCount); + gs_AssociationCount --; + } +#endif wxWinHandleList->DeleteObject(win); } @@ -2160,12 +2243,12 @@ void wxWindow::MSWDetachWindowMenu() int chars = GetMenuString(hMenu, i, buf, 100, MF_BYPOSITION); if ( !chars ) { - wxLogLastError(_T("GetMenuString")); + wxLogLastError(wxT("GetMenuString")); continue; } - if ( wxStrcmp(buf, _T("&Window")) == 0 ) + if ( wxStrcmp(buf, wxT("&Window")) == 0 ) { RemoveMenu(hMenu, i, MF_BYPOSITION); @@ -2209,11 +2292,7 @@ bool wxWindow::MSWCreate(int id, if ( width > -1 ) width1 = width; if ( height > -1 ) height1 = height; -#ifdef __WXWINE__ HWND hParent = (HWND)NULL; -#else - HWND hParent = NULL; -#endif if ( parent ) hParent = (HWND) parent->GetHWND(); @@ -2241,14 +2320,14 @@ bool wxWindow::MSWCreate(int id, if ( !::SetWindowPos(GetHwnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE) ) { - wxLogLastError(_T("SetWindowPos")); + wxLogLastError(wxT("SetWindowPos")); } } // move the dialog to its initial position without forcing repainting if ( !::MoveWindow(GetHwnd(), x1, y1, width1, height1, FALSE) ) { - wxLogLastError(_T("MoveWindow")); + wxLogLastError(wxT("MoveWindow")); } } else @@ -2260,12 +2339,12 @@ bool wxWindow::MSWCreate(int id, wxString className(wclass); if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE ) { - className += _T("NR"); + className += wxT("NR"); } m_hWnd = (WXHWND)CreateWindowEx(extendedStyle, - wclass, - title ? title : _T(""), + className, + title ? title : wxT(""), style, x1, y1, width1, height1, @@ -2284,7 +2363,18 @@ bool wxWindow::MSWCreate(int id, } wxWndHook = NULL; - wxWinHandleList->Append((long)m_hWnd, this); +#ifdef __WXDEBUG__ + wxNode* node = wxWinHandleList->Member(this); + if (node) + { + HWND hWnd = (HWND) node->GetKeyInteger(); + if (hWnd != (HWND) m_hWnd) + { + wxLogError(wxT("A second HWND association is being added for the same window!")); + } + } +#endif + wxAssociateWinWithHandle((HWND) m_hWnd, this); return TRUE; } @@ -2336,7 +2426,7 @@ bool wxWindow::MSWOnNotify(int WXUNUSED(idCtrl), { #if wxUSE_TOOLTIPS NMHDR* hdr = (NMHDR *)lParam; - if ( hdr->code == TTN_NEEDTEXT && m_tooltip ) + if ( (int)hdr->code == TTN_NEEDTEXT && m_tooltip ) { TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam; ttt->lpszText = (wxChar *)m_tooltip->GetTip().c_str(); @@ -2359,7 +2449,7 @@ bool wxWindow::HandleQueryEndSession(long logOff, bool *mayEnd) wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1); event.SetEventObject(wxTheApp); event.SetCanVeto(TRUE); - event.SetLoggingOff(logOff == ENDSESSION_LOGOFF); + event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF); bool rc = wxTheApp->ProcessEvent(event); @@ -2382,7 +2472,7 @@ bool wxWindow::HandleEndSession(bool endSession, long logOff) wxCloseEvent event(wxEVT_END_SESSION, -1); event.SetEventObject(wxTheApp); event.SetCanVeto(FALSE); - event.SetLoggingOff( (logOff == ENDSESSION_LOGOFF) ); + event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) ); if ( (this == wxTheApp->GetTopWindow()) && // Only send once wxTheApp->ProcessEvent(event)) { @@ -2621,10 +2711,9 @@ bool wxWindow::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) { return ((wxControl *)item)->MSWOnDraw(itemStruct); } - else -#endif - return FALSE; +#endif // USE_OWNER_DRAWN + return FALSE; } bool wxWindow::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) @@ -2893,14 +2982,32 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) return popupMenu->MSWCommand(cmd, id); } - wxWindow *win = FindItem(id); - if ( !win ) + wxWindow *win; + if ( cmd == 0 || cmd == 1 ) // menu or accel - use id { + // must cast to a signed type before comparing with other ids! + win = FindItem((signed short)id); + } + else + { + // find it from HWND - this works even with the broken programs using + // the same ids for different controls win = wxFindWinFromHandle(control); } if ( win ) return win->MSWCommand(cmd, id); + else + { + // If no child window, it may be an accelerator, e.g. for + // a popup menu command. + + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED); + event.SetEventObject(this); + event.SetId(id); + event.SetInt(id); + return ProcessEvent(event); + } return FALSE; } @@ -3229,7 +3336,7 @@ bool wxWindow::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags) break; default: - wxFAIL_MSG(_T("no such joystick event")); + wxFAIL_MSG(wxT("no such joystick event")); return FALSE; } @@ -3286,8 +3393,11 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam, event.m_eventType = wxEVT_SCROLLWIN_PAGEDOWN; break; - case SB_THUMBTRACK: case SB_THUMBPOSITION: + event.m_isScrolling = FALSE; + /* fall-through */ + + case SB_THUMBTRACK: event.m_eventType = wxEVT_SCROLLWIN_THUMBTRACK; break; @@ -3302,7 +3412,7 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam, // global functions // =========================================================================== -void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) +void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font) { TEXTMETRIC tm; HDC dc = ::GetDC((HWND) wnd); @@ -3312,7 +3422,7 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y,wxFont *the_font) { // the_font->UseResource(); // the_font->RealizeResource(); - fnt = (HFONT)the_font->GetResourceHandle(); + fnt = (HFONT)((wxFont *)the_font)->GetResourceHandle(); // const_cast if ( fnt ) was = (HFONT) SelectObject(dc,fnt); } @@ -3513,17 +3623,22 @@ void wxSetKeyboardHook(bool doIt) { wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance()); wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(), + #if defined(__WIN32__) && !defined(__TWIN32__) GetCurrentThreadId()); // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right? #else - GetCurrentTask()); + GetCurrentTask()); #endif } else { UnhookWindowsHookEx(wxTheKeyboardHook); + // avoids mingw warning about statement with no effect (FreeProcInstance + // doesn't do anything under Win32) +#ifndef __GNUWIN32__ FreeProcInstance(wxTheKeyboardHookProc); +#endif } }