X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a0e449ff41f55b4d82f108f72638f852c962da2d..b3bd664a906b228e24eb08f481c60c46139f454a:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 7bbf3ce5cd..dc8a956358 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -39,7 +39,6 @@ #include "wx/dcclient.h" #include "wx/utils.h" #include "wx/app.h" - #include "wx/panel.h" #include "wx/layout.h" #include "wx/dialog.h" #include "wx/frame.h" @@ -131,7 +130,6 @@ extern MSG s_currentMsg; wxMenu *wxCurrentPopupMenu = NULL; #endif // wxUSE_MENUS_NATIVE -extern wxList WXDLLEXPORT wxPendingDelete; extern const wxChar *wxCanvasClassName; // --------------------------------------------------------------------------- @@ -158,8 +156,25 @@ static void TranslateKbdEventToMouse(wxWindowMSW *win, // get the text metrics for the current font static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win); -// check if the mouse is in the window or its child -//static bool IsMouseInWindow(HWND hwnd); +// wrapper around BringWindowToTop() API +static inline void wxBringWindowToTop(HWND hwnd) +{ +#ifdef __WXMICROWIN__ + // It seems that MicroWindows brings the _parent_ of the window to the top, + // which can be the wrong one. + + // activate (set focus to) specified window + ::SetFocus(hwnd); + + // raise top level parent to top of z order + ::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); +#else // !__WXMICROWIN__ + if ( !::BringWindowToTop(hwnd) ) + { + wxLogLastError(_T("BringWindowToTop")); + } +#endif // __WXMICROWIN__/!__WXMICROWIN__ +} // --------------------------------------------------------------------------- // event tables @@ -178,7 +193,6 @@ BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase) EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged) EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog) EVT_IDLE(wxWindowMSW::OnIdle) - EVT_SET_FOCUS(wxWindowMSW::OnSetFocus) END_EVENT_TABLE() // =========================================================================== @@ -309,17 +323,21 @@ wxWindowMSW::~wxWindowMSW() MSWDetachWindowMenu(); +#ifndef __WXUNIVERSAL__ // VS: make sure there's no wxFrame with last focus set to us: - for (wxWindow *win = GetParent(); win; win = win->GetParent()) + for ( wxWindow *win = GetParent(); win; win = win->GetParent() ) { wxFrame *frame = wxDynamicCast(win, wxFrame); if ( frame ) { if ( frame->GetLastFocus() == this ) + { frame->SetLastFocus((wxWindow*)NULL); + } break; } } +#endif // __WXUNIVERSAL__ // VS: destroy children first and _then_ detach *this from its parent. // If we'd do it the other way around, children wouldn't be able @@ -415,11 +433,7 @@ bool wxWindowMSW::Create(wxWindow *parent, m_isShown = FALSE; } - return MSWCreate(m_windowId, parent, wxCanvasClassName, - (wxWindow *)this, NULL, - pos.x, pos.y, - WidthDefault(size.x), HeightDefault(size.y), - msflags, NULL, exStyle); + return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exStyle); } // --------------------------------------------------------------------------- @@ -506,19 +520,7 @@ bool wxWindowMSW::Show(bool show) if ( show ) { -#ifdef __WXMICROWIN__ - // It seems that MicroWindows brings the _parent_ of the - // window to the top, which can be the wrong one. - - // activate (set focus to) specified window - ::SetFocus(hWnd); - - // raise top level parent to top of z order - ::SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, - SWP_NOMOVE|SWP_NOSIZE); -#else - BringWindowToTop(hWnd); -#endif + wxBringWindowToTop(hWnd); } return TRUE; @@ -527,22 +529,7 @@ bool wxWindowMSW::Show(bool show) // Raise the window to the top of the Z order void wxWindowMSW::Raise() { -#ifdef __WIN16__ - ::BringWindowToTop(GetHwnd()); -#else // Win32 -#ifdef __WXMICROWIN__ - // It seems that MicroWindows brings the _parent_ of the - // window to the top, which can be the wrong one. - - // activate (set focus to) specified window - ::SetFocus(GetHwnd()); - - // raise top level parent to top of z order - ::SetWindowPos(GetHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); -#else - ::SetForegroundWindow(GetHwnd()); -#endif -#endif + wxBringWindowToTop(GetHwnd()); } // Lower the window to the bottom of the Z order @@ -621,8 +608,7 @@ bool wxWindowMSW::SetCursor(const wxCursor& cursor) POINT point; ::GetCursorPos(&point); - RECT rect; - ::GetWindowRect(hWnd, &rect); + RECT rect = wxGetWindowRect(hWnd); if ( ::PtInRect(&rect, point) && !wxIsBusy() ) ::SetCursor(GetHcursorOf(m_cursor)); @@ -770,6 +756,15 @@ int wxWindowMSW::GetScrollPage(int orient) const #endif // WXWIN_COMPATIBILITY +inline int GetScrollPosition(HWND hWnd, int wOrient) +{ +#ifdef __WXMICROWIN__ + return ::GetScrollPosWX(hWnd, wOrient); +#else + return ::GetScrollPos(hWnd, wOrient); +#endif +} + int wxWindowMSW::GetScrollPos(int orient) const { int wOrient; @@ -777,17 +772,11 @@ int wxWindowMSW::GetScrollPos(int orient) const wOrient = SB_HORZ; else wOrient = SB_VERT; + HWND hWnd = GetHwnd(); - if ( hWnd ) - { -#ifdef __WXMICROWIN__ - return ::GetScrollPosWX(hWnd, wOrient); -#else - return ::GetScrollPos(hWnd, wOrient); -#endif - } - else - return 0; + wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") ); + + return GetScrollPosition(hWnd, wOrient); } // This now returns the whole range, not just the number @@ -940,6 +929,46 @@ void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect) ::ScrollWindow(GetHwnd(), dx, dy, prect ? &rect : NULL, NULL); } +static bool ScrollVertically(HWND hwnd, int kind, int count) +{ + int posStart = GetScrollPosition(hwnd, SB_VERT); + + int pos = posStart; + for ( int n = 0; n < count; n++ ) + { + ::SendMessage(hwnd, WM_VSCROLL, kind, 0); + + int posNew = GetScrollPosition(hwnd, SB_VERT); + if ( posNew == pos ) + { + // don't bother to continue, we're already at top/bottom + break; + } + + pos = posNew; + } + + return pos != posStart; +} + +bool wxWindowMSW::ScrollLines(int lines) +{ + bool down = lines > 0; + + return ScrollVertically(GetHwnd(), + down ? SB_LINEDOWN : SB_LINEUP, + down ? lines : -lines); +} + +bool wxWindowMSW::ScrollPages(int pages) +{ + bool down = pages > 0; + + return ScrollVertically(GetHwnd(), + down ? SB_PAGEDOWN : SB_PAGEUP, + down ? pages : -pages); +} + // --------------------------------------------------------------------------- // subclassing // --------------------------------------------------------------------------- @@ -953,11 +982,19 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) wxAssociateWinWithHandle(hwnd, this); - m_oldWndProc = (WXFARPROC) GetWindowLong(hwnd, GWL_WNDPROC); + m_oldWndProc = (WXFARPROC)::GetWindowLong(hwnd, GWL_WNDPROC); - wxASSERT( (WXFARPROC) m_oldWndProc != (WXFARPROC) wxWndProc ); - - SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc); + // 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 ) + { + ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc); + } + else + { + // don't bother restoring it neither + m_oldWndProc = NULL; + } } void wxWindowMSW::UnsubclassWin() @@ -972,11 +1009,15 @@ void wxWindowMSW::UnsubclassWin() wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") ); - FARPROC farProc = (FARPROC) GetWindowLong(hwnd, GWL_WNDPROC); - if ( (m_oldWndProc != 0) && (farProc != (FARPROC) m_oldWndProc) ) + if ( m_oldWndProc ) { - SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc); - m_oldWndProc = 0; + FARPROC wndProc = (FARPROC)::GetWindowLong(hwnd, GWL_WNDPROC); + if ( wndProc != (FARPROC) m_oldWndProc ) + { + ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc); + } + + m_oldWndProc = NULL; } } } @@ -1002,6 +1043,7 @@ WXDWORD wxWindowMSW::MakeExtendedStyle(long style, bool eliminateBorders) exStyle |= WS_EX_STATICEDGE; #endif } + return exStyle; } @@ -1009,7 +1051,7 @@ WXDWORD wxWindowMSW::MakeExtendedStyle(long style, bool eliminateBorders) // applying a default border style if required, and returning an extended // style to pass to CreateWindowEx. WXDWORD wxWindowMSW::Determine3DEffects(WXDWORD defaultBorderStyle, - bool *want3D) const + bool *want3D) const { // If matches certain criteria, then assume no 3D effects // unless specifically requested (dealt with in MakeExtendedStyle) @@ -1020,7 +1062,7 @@ WXDWORD wxWindowMSW::Determine3DEffects(WXDWORD defaultBorderStyle, || (m_windowStyle & wxNO_BORDER) ) { *want3D = FALSE; - return MakeExtendedStyle(m_windowStyle, FALSE); + return MakeExtendedStyle(m_windowStyle); } // Determine whether we should be using 3D effects or not. @@ -1154,11 +1196,7 @@ void wxWindowMSW::OnIdle(wxIdleEvent& WXUNUSED(event)) // we need to have client coordinates here for symmetry with // wxEVT_ENTER_WINDOW - RECT rect; - if ( !::GetWindowRect(GetHwnd(), &rect) ) - { - wxLogLastError(_T("GetWindowRect")); - } + RECT rect = wxGetWindowRect(GetHwnd()); pt.x -= rect.left; pt.y -= rect.top; @@ -1201,12 +1239,16 @@ static inline void SendSetRedraw(HWND hwnd, bool on) void wxWindowMSW::Freeze() { - SendSetRedraw(FALSE); + SendSetRedraw(GetHwnd(), FALSE); } void wxWindowMSW::Thaw() { - SendSetRedraw(TRUE); + SendSetRedraw(GetHwnd(), TRUE); + + // we need to refresh everything or otherwise he invalidated area is not + // repainted + Refresh(); } void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect) @@ -1295,28 +1337,28 @@ void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip) // Get total size void wxWindowMSW::DoGetSize(int *x, int *y) const { - HWND hWnd = GetHwnd(); - RECT rect; -#ifdef __WIN16__ - ::GetWindowRect(hWnd, &rect); -#else - if ( !::GetWindowRect(hWnd, &rect) ) - { - wxLogLastError(_T("GetWindowRect")); - } -#endif + RECT rect = wxGetWindowRect(GetHwnd()); + if ( x ) *x = rect.right - rect.left; if ( y ) *y = rect.bottom - rect.top; } -void wxWindowMSW::DoGetPosition(int *x, int *y) const +// Get size *available for subwindows* i.e. excluding menu bar etc. +void wxWindowMSW::DoGetClientSize(int *x, int *y) const { - HWND hWnd = GetHwnd(); + RECT rect = wxGetClientRect(GetHwnd()); - RECT rect; - GetWindowRect(hWnd, &rect); + if ( x ) + *x = rect.right; + if ( y ) + *y = rect.bottom; +} + +void wxWindowMSW::DoGetPosition(int *x, int *y) const +{ + RECT rect = wxGetWindowRect(GetHwnd()); POINT point; point.x = rect.left; @@ -1362,8 +1404,7 @@ void wxWindowMSW::DoScreenToClient(int *x, int *y) const if ( y ) pt.y = *y; - HWND hWnd = GetHwnd(); - ::ScreenToClient(hWnd, &pt); + ::ScreenToClient(GetHwnd(), &pt); if ( x ) *x = pt.x; @@ -1379,8 +1420,7 @@ void wxWindowMSW::DoClientToScreen(int *x, int *y) const if ( y ) pt.y = *y; - HWND hWnd = GetHwnd(); - ::ClientToScreen(hWnd, &pt); + ::ClientToScreen(GetHwnd(), &pt); if ( x ) *x = pt.x; @@ -1388,18 +1428,6 @@ void wxWindowMSW::DoClientToScreen(int *x, int *y) const *y = pt.y; } -// Get size *available for subwindows* i.e. excluding menu bar etc. -void wxWindowMSW::DoGetClientSize(int *x, int *y) const -{ - HWND hWnd = GetHwnd(); - RECT rect; - ::GetClientRect(hWnd, &rect); - if ( x ) - *x = rect.right; - if ( y ) - *y = rect.bottom; -} - void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height) { if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) ) @@ -1520,24 +1548,6 @@ wxPoint wxWindowMSW::GetClientAreaOrigin() const return wxPoint(0, 0); } -// Makes an adjustment to the window position (for example, a frame that has -// a toolbar that it manages itself). -void wxWindowMSW::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) -{ - // don't do it for the dialogs/frames - they float independently of their - // parent - if ( !IsTopLevel() ) - { - wxWindow *parent = GetParent(); - if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent ) - { - wxPoint pt(parent->GetClientAreaOrigin()); - x += pt.x; - y += pt.y; - } - } -} - // --------------------------------------------------------------------------- // text metrics // --------------------------------------------------------------------------- @@ -1645,6 +1655,8 @@ void wxWindowMSW::GetCaretPos(int *x, int *y) const // 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 // @@ -1662,8 +1674,6 @@ static void wxYieldForCommandsOnly() } } -#if wxUSE_MENUS_NATIVE - bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) { menu->SetInvokingWindow(this); @@ -1799,18 +1809,13 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) bProcess = FALSE; } -#if wxUSE_BUTTON + // FIXME: this should be handled by + // wxNavigationKeyEvent handler and not here!! else { - wxPanel *panel = wxDynamicCastThis(wxPanel); - wxButton *btn = NULL; - if ( panel ) - { - // panel may have a default button which should - // be activated by Enter - btn = panel->GetDefaultItem(); - } - +#if wxUSE_BUTTON + wxButton *btn = wxDynamicCast(GetDefaultItem(), + wxButton); if ( btn && btn->IsEnabled() ) { // if we do have a default button, do press it @@ -1818,11 +1823,15 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) return TRUE; } - // else: but if it does not it makes sense to make - // it work like a TAB - and that's what we do. - // Note that Ctrl-Enter always works this way. - } + 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; + } + } } break; @@ -1839,20 +1848,11 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) if ( GetEventHandler()->ProcessEvent(event) ) { -#if wxUSE_BUTTON - wxButton *btn = wxDynamicCast(FindFocus(), wxButton); - if ( btn ) - { - // the button which has focus should be default - btn->SetDefault(); - } -#endif // wxUSE_BUTTON - return TRUE; } } } -#else +#else // 0 // 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 ) @@ -1880,7 +1880,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) } } } -#endif // 0 +#endif // 1/0 if ( ::IsDialogMessage(GetHwnd(), msg) ) { @@ -1912,6 +1912,12 @@ bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg) #endif // wxUSE_ACCEL } +bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* pMsg) +{ + // preprocess all messages by default + return TRUE; +} + // --------------------------------------------------------------------------- // message params unpackers (different for Win16 and Win32) // --------------------------------------------------------------------------- @@ -2010,7 +2016,19 @@ void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam, // Hook for new window just as it's being created, when the window isn't yet // associated with the handle -wxWindowMSW *wxWndHook = NULL; +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) @@ -2024,38 +2042,21 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd); // when we get the first message for the HWND we just created, we associate - // it with wxWindow stored in wxWndHook - if ( !wnd && wxWndHook ) + // it with wxWindow stored in gs_winBeingCreated + if ( !wnd && gs_winBeingCreated ) { -#if 0 // def __WXDEBUG__ - char buf[512]; - ::GetClassNameA((HWND) hWnd, buf, 512); - wxString className(buf); -#endif - - wxAssociateWinWithHandle(hWnd, wxWndHook); - wnd = wxWndHook; - wxWndHook = NULL; + wxAssociateWinWithHandle(hWnd, gs_winBeingCreated); + wnd = gs_winBeingCreated; + gs_winBeingCreated = NULL; wnd->SetHWND((WXHWND)hWnd); } LRESULT rc; - // Stop right here if we don't have a valid handle in our wxWindow object. - if ( wnd && !wnd->GetHWND() ) - { - // FIXME: why do we do this? - wnd->SetHWND((WXHWND) hWnd); - rc = wnd->MSWDefWindowProc(message, wParam, lParam ); - wnd->SetHWND(0); - } + if ( wnd ) + rc = wnd->MSWWindowProc(message, wParam, lParam); else - { - if ( wnd ) - rc = wnd->MSWWindowProc(message, wParam, lParam); - else - rc = DefWindowProc( hWnd, message, wParam, lParam ); - } + rc = ::DefWindowProc(hWnd, message, wParam, lParam); return rc; } @@ -2092,7 +2093,11 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam break; case WM_DESTROY: - processed = HandleDestroy(); + // 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_MOVE: @@ -2557,7 +2562,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 @@ -2582,25 +2590,12 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam return rc.result; } -// Dialog window proc -LONG APIENTRY _EXPORT -wxDlgProc(HWND WXUNUSED(hWnd), UINT message, WPARAM WXUNUSED(wParam), LPARAM WXUNUSED(lParam)) -{ - if ( message == WM_INITDIALOG ) - { - // for this message, returning TRUE tells system to set focus to the - // first control in the dialog box - return TRUE; - } - else - { - // for all the other ones, FALSE means that we didn't process the - // message - return 0; - } -} +// ---------------------------------------------------------------------------- +// wxWindow <-> HWND map +// ---------------------------------------------------------------------------- wxList *wxWinHandleList = NULL; + wxWindow *wxFindWinFromHandle(WXHWND hWnd) { wxNode *node = wxWinHandleList->Find((long)hWnd); @@ -2609,10 +2604,6 @@ wxWindow *wxFindWinFromHandle(WXHWND hWnd) return (wxWindow *)node->Data(); } -#if 0 // def __WXDEBUG__ -static int gs_AssociationCount = 0; -#endif - void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) { // adding NULL hWnd is (first) surely a result of an error and @@ -2620,36 +2611,30 @@ void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) 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) ) { - wxString str(win->GetClassInfo()->GetClassName()); - wxLogError(wxT("Bug! Found existing HWND %X for new window of class %s"), (int) hWnd, (const wxChar*) str); + wxLogDebug(wxT("HWND %X already associated with another window (%s)"), + hWnd, win->GetClassInfo()->GetClassName()); } - else if (!oldWin) + else +#endif // __WXDEBUG__ + if (!oldWin) { -#if 0 // def __WXDEBUG__ - gs_AssociationCount ++; - wxLogDebug("+ Association %d", gs_AssociationCount); -#endif - wxWinHandleList->Append((long)hWnd, win); } } void wxRemoveHandleAssociation(wxWindowMSW *win) { -#if 0 // def __WXDEBUG__ - if (wxWinHandleList->Member(win)) - { - wxLogDebug("- Association %d", gs_AssociationCount); - gs_AssociationCount --; - } -#endif wxWinHandleList->DeleteObject(win); } +// ---------------------------------------------------------------------------- +// 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() @@ -2685,61 +2670,78 @@ void wxWindowMSW::MSWDetachWindowMenu() } } } -#endif +#endif // __WXUNIVERSAL__ } -bool wxWindowMSW::MSWCreate(int id, - wxWindow *parent, - const wxChar *wclass, - wxWindow * WXUNUSED(wx_win), - const wxChar *title, - int x, - int y, - int width, - int height, - WXDWORD style, - const wxChar *dialog_template, - WXDWORD extendedStyle) +bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos, + const wxSize& size, + int& x, int& y, + int& w, int& h) const { - int x1 = CW_USEDEFAULT; - int y1 = 0; - int width1 = CW_USEDEFAULT; - int height1 = 100; + bool nonDefault = FALSE; - // Find parent's size, if it exists, to set up a possible default - // panel size the size of the parent window - RECT rectParent; - if ( parent ) + if ( pos.x == -1 ) { - ::GetClientRect(GetHwndOf(parent), &rectParent); - - width1 = rectParent.right - rectParent.left; - height1 = rectParent.bottom - rectParent.top; - } - - if ( x != -1 ) - x1 = x; - if ( y != -1 ) - y1 = y; - if ( width != -1 ) - width1 = width; - if ( height != -1 ) - height1 = height; - - // unfortunately, setting WS_EX_CONTROLPARENT only for some windows in the - // hierarchy with several embedded panels (and not all of them) causes the - // program to hang during the next call to IsDialogMessage() due to the bug - // in this function (at least in Windows NT 4.0, it seems to work ok in - // Win2K) -#if 0 - // if we have wxTAB_TRAVERSAL style, we want WS_EX_CONTROLPARENT or - // IsDialogMessage() won't work for us - if ( GetWindowStyleFlag() & wxTAB_TRAVERSAL ) + // if set x 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 { - extendedStyle |= WS_EX_CONTROLPARENT; + x = pos.x; + y = pos.y == -1 ? CW_USEDEFAULT : 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 wxWindows 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 wxWindows 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. + */ + if ( size.x == -1 ) + { + // as abobe, h is not used at all in this case anyhow + w = + h = CW_USEDEFAULT; } -#endif // 0 + else + { + w = size.x; + h = size.y == -1 ? CW_USEDEFAULT : size.y; + nonDefault = TRUE; + } + + return nonDefault; +} + +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); + + // find the correct parent HWND + wxWindow *parent = GetParent(); + bool isChild = (style & WS_CHILD) != 0; HWND hParent; if ( GetWindowStyleFlag() & wxPOPUP_WINDOW ) { @@ -2747,148 +2749,77 @@ bool wxWindowMSW::MSWCreate(int id, // be limited to the parents client area as child windows usually are hParent = ::GetDesktopWindow(); } - else if ( parent ) + else // !popup { - hParent = GetHwndOf(parent); - } - else - { - // top level window - hParent = NULL; - } - - wxWndHook = this; - -#ifndef __WXMICROWIN__ - if ( dialog_template ) - { - // for the dialogs without wxDIALOG_NO_PARENT style, use the top level - // app window as parent - this avoids creating modal dialogs without - // parent - if ( !hParent && !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT) ) - { - wxWindow *winTop = wxTheApp->GetTopWindow(); - if ( winTop ) - hParent = GetHwndOf(winTop); - } - - m_hWnd = (WXHWND)::CreateDialog(wxGetInstance(), - dialog_template, - hParent, - (DLGPROC)wxDlgProc); - - if ( m_hWnd == 0 ) + if ( (isChild || HasFlag(wxFRAME_TOOL_WINDOW)) && parent ) { - wxLogError(_("Can't find dialog template '%s'!\nCheck resource include path for finding wx.rc."), - dialog_template); - - return FALSE; + // this is either a normal child window or a top level window with + // wxFRAME_TOOL_WINDOW style (see below) + hParent = GetHwndOf(parent); } - - if ( extendedStyle != 0 ) - { - ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, extendedStyle); - ::SetWindowPos(GetHwnd(), NULL, 0, 0, 0, 0, - SWP_NOSIZE | - SWP_NOMOVE | - SWP_NOZORDER | - SWP_NOACTIVATE); - } - -#if defined(__WIN95__) - // For some reason, the system menu is activated when we use the - // WS_EX_CONTEXTHELP style, so let's set a reasonable icon - if (extendedStyle & WS_EX_CONTEXTHELP) + else { - wxFrame *winTop = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame); - if ( winTop ) - { - wxIcon icon = winTop->GetIcon(); - if ( icon.Ok() ) - { - ::SendMessage(GetHwnd(), WM_SETICON, - (WPARAM)TRUE, - (LPARAM)GetHiconOf(icon)); - } - } + // 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; } -#endif // __WIN95__ - - // JACS: is the following still necessary? The above seems to work. + } - // ::SetWindowLong(GWL_EXSTYLE) doesn't work for the dialogs, so try - // to take care of (at least some) extended style flags ourselves - if ( extendedStyle & WS_EX_TOPMOST ) - { - if ( !::SetWindowPos(GetHwnd(), HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE) ) - { - wxLogLastError(wxT("SetWindowPos")); - } - } + // controlId is menu handle for the top level windows, so set it to 0 + // unless we're creating a child window + int controlId; + if ( isChild ) + { + controlId = GetId(); - // move the dialog to its initial position without forcing repainting - if ( !::MoveWindow(GetHwnd(), x1, y1, width1, height1, FALSE) ) + if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS ) { - wxLogLastError(wxT("MoveWindow")); + style |= WS_CLIPSIBLINGS; } - } - else // creating a normal window, not a dialog -#endif // !__WXMICROWIN__ + else // !child { - int controlId = 0; - if ( style & WS_CHILD ) - { - controlId = id; - - if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS ) - { - style |= WS_CLIPSIBLINGS; - } - } - - wxString className(wclass); - if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE ) - { - className += wxT("NR"); - } - - m_hWnd = (WXHWND)CreateWindowEx(extendedStyle, - className, - title ? title : wxT(""), - style, - x1, y1, - width1, height1, - hParent, (HMENU)controlId, - wxGetInstance(), - NULL); - - if ( !m_hWnd ) - { - wxLogError(_("Can't create window of class %s!\nPossible Windows 3.x compatibility problem?"), - wclass); + controlId = 0; + } - return FALSE; - } + // 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 ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE ) + { + className += wxT("NR"); } - wxWndHook = NULL; + // do create the window + wxWindowCreationHook hook(this); -#ifdef __WXDEBUG__ - wxNode* node = wxWinHandleList->Member(this); - if (node) + m_hWnd = (WXHWND)::CreateWindowEx + ( + extendedStyle, + className, + title ? title : wxT(""), + style, + x, y, w, h, + hParent, + (HMENU)controlId, + wxGetInstance(), + NULL // no extra data + ); + + if ( !m_hWnd ) { - HWND hWnd = (HWND) node->GetKeyInteger(); - if (hWnd != (HWND) m_hWnd) - { - wxLogError(wxT("A second HWND association is being added for the same window!")); - } + wxLogSysError(_("Can't create window of class %s"), wclass); + + return FALSE; } -#endif // Debug - wxAssociateWinWithHandle((HWND) m_hWnd, this); + SubclassWin(m_hWnd); SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT)); @@ -2987,15 +2918,16 @@ bool wxWindowMSW::HandleEndSession(bool endSession, long logOff) if ( !endSession ) return FALSE; + // only send once + if ( (this != wxTheApp->GetTopWindow()) ) + return FALSE; + wxCloseEvent event(wxEVT_END_SESSION, -1); event.SetEventObject(wxTheApp); event.SetCanVeto(FALSE); event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) ); - if ( (this == wxTheApp->GetTopWindow()) && // Only send once - wxTheApp->ProcessEvent(event)) - { - } - return TRUE; + + return wxTheApp->ProcessEvent(event); } // --------------------------------------------------------------------------- @@ -3037,33 +2969,6 @@ bool wxWindowMSW::HandleDestroy() // activation/focus // --------------------------------------------------------------------------- -void wxWindowMSW::OnSetFocus(wxFocusEvent& event) -{ - // panel wants to track the window which was the last to have focus in it, - // so we want to set ourselves as the window which last had focus - // - // notice that it's also important to do it upwards the tree becaus - // otherwise when the top level panel gets focus, it won't set it back to - // us, but to some other sibling - wxWindow *win = (wxWindow *)this; - while ( win ) - { - wxWindow *parent = win->GetParent(); - wxPanel *panel = wxDynamicCast(parent, wxPanel); - if ( panel ) - { - panel->SetLastFocus(win); - } - - win = parent; - } - - wxLogTrace(_T("focus"), _T("%s (0x%08x) gets focus"), - GetClassInfo()->GetClassName(), GetHandle()); - - event.Skip(); -} - bool wxWindowMSW::HandleActivate(int state, bool WXUNUSED(minimized), WXHWND WXUNUSED(activate)) @@ -3078,6 +2983,11 @@ bool wxWindowMSW::HandleActivate(int state, bool wxWindowMSW::HandleSetFocus(WXHWND hwnd) { + // 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 ) @@ -3086,6 +2996,15 @@ bool wxWindowMSW::HandleSetFocus(WXHWND hwnd) } #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); @@ -3105,6 +3024,16 @@ bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) } #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 + wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId); event.SetEventObject(this); @@ -3161,7 +3090,8 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam) wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files); event.m_eventObject = this; - event.m_pos.x = dropPoint.x; event.m_pos.x = dropPoint.y; + event.m_pos.x = dropPoint.x; + event.m_pos.y = dropPoint.y; bool rc = GetEventHandler()->ProcessEvent(event); @@ -3270,9 +3200,9 @@ bool wxWindowMSW::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct) #if wxUSE_MENUS_NATIVE // is it a menu item? - if ( id == 0 ) + DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct; + if ( id == 0 && pDrawStruct->CtlType == ODT_MENU ) { - DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct; wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData); wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); @@ -3311,9 +3241,9 @@ bool wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct) { #if wxUSE_OWNER_DRAWN // is it a menu item? - if ( id == 0 ) + MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct; + if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU ) { - MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct; wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData); wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE ); @@ -3814,8 +3744,8 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) // create the key event of the given type for the given key - used by // HandleChar and HandleKeyDown/Up wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType, - int id, - WXLPARAM lParam) const + int id, + WXLPARAM lParam) const { wxKeyEvent event(evType); event.SetId(GetId()); @@ -4347,19 +4277,27 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) #endif // wxUSE_SPINCTRL #endif // Win32 - - if ( !win ) - { - // hwnd is not a wxWindow, try its parent next below - hwnd = ::GetParent(hwnd); - } } } while ( hwnd && !win ) { - win = wxFindWinFromHandle((WXHWND)hwnd); + // this is a really ugly hack needed to avoid mistakenly returning the + // parent frame wxWindow for the find/replace modeless dialog HWND - + // this, in turn, is needed to call IsDialogMessage() from + // wxApp::ProcessMessage() as for this we must return NULL from here + // + // 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 + if ( ::GetWindow(hwnd, GW_OWNER) ) + { + // it's a dialog box, don't go upwards + break; + } + hwnd = ::GetParent(hwnd); + win = wxFindWinFromHandle((WXHWND)hwnd); } return win;