X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7ce6cc9b8eda3c0195ae5233d8a4d35707a88190..b5a5362e55572bcc057d014c5bdde81d75804653:/src/msw/toplevel.cpp diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index 0c5d936882..6407ca753f 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -34,24 +34,23 @@ #include "wx/intl.h" #include "wx/frame.h" #include "wx/containr.h" // wxSetFocusToChild() + #include "wx/module.h" #endif //WX_PRECOMP -#include "wx/module.h" #include "wx/dynlib.h" #include "wx/msw/private.h" #if defined(__WXWINCE__) && !defined(__HANDHELDPC__) - #include - #include - // Standard SDK doesn't have aygshell.dll: see include/wx/msw/wince/libraries.h - #if _WIN32_WCE < 400 || !defined(__WINCE_STANDARDSDK__) - #include - #endif -#include "wx/msw/wince/missing.h" + #include + #include + // Standard SDK doesn't have aygshell.dll: see include/wx/msw/wince/libraries.h + #if _WIN32_WCE < 400 || !defined(__WINCE_STANDARDSDK__) + #include + #endif #endif -#include "wx/msw/missing.h" #include "wx/msw/winundef.h" +#include "wx/msw/missing.h" #include "wx/display.h" @@ -79,17 +78,6 @@ static inline bool IsZoomed(HWND WXUNUSED(hwnd)) { return false; } LONG APIENTRY _EXPORT wxDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -// ---------------------------------------------------------------------------- -// globals -// ---------------------------------------------------------------------------- - -// the name of the default wxWidgets class -#ifdef __WXWINCE__ -extern wxChar *wxCanvasClassName; -#else -extern const wxChar *wxCanvasClassName; -#endif - // ---------------------------------------------------------------------------- // wxTLWHiddenParentModule: used to manage the hidden parent window (we need a // module to ensure that the window is always deleted) @@ -140,7 +128,7 @@ void wxTopLevelWindowMSW::Init() m_fsIsMaximized = false; m_fsIsShowing = false; - m_winLastFocused = (wxWindow *)NULL; + m_winLastFocused = NULL; #if defined(__SMARTPHONE__) && defined(__WXWINCE__) m_MenuBarHWND = 0; @@ -222,9 +210,11 @@ WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const } #ifndef __WXWINCE__ - if ( style & wxSYSTEM_MENU ) + // notice that if wxCLOSE_BOX is specified we need to use WS_SYSMENU too as + // otherwise the close box doesn't appear + if ( style & (wxSYSTEM_MENU | wxCLOSE_BOX) ) msflags |= WS_SYSMENU; -#endif +#endif // !__WXWINCE__ // NB: under CE these 2 styles are not supported currently, we should // call Minimize()/Maximize() "manually" if we want to support them @@ -331,48 +321,6 @@ bool wxTopLevelWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam) } #endif -bool wxTopLevelWindowMSW::MSWProcessMessage(WXMSG* pMsg) -{ - // MSW specific feature: if the dialog has only one notebook-like child - // window (actually it could be any window that returns true from its - // HasMultiplePages()), then [Shift-]Ctrl-Tab and Ctrl-PageUp/Down keys - // should iterate over its pages even if the focus is outside of the - // control because this is how the standard MSW properties dialogs behave - if ( pMsg->message == WM_KEYDOWN && wxIsCtrlDown() && - (pMsg->wParam == VK_TAB || - pMsg->wParam == VK_PRIOR || - pMsg->wParam == VK_NEXT) ) - { - // check if we have a unique notebook-like child - wxWindow *bookctrl = NULL; - for ( wxWindowList::const_iterator i = GetChildren().begin(), - end = GetChildren().end(); - i != end; - ++i ) - { - wxWindow * const window = *i; - if ( window->HasMultiplePages() ) - { - if ( bookctrl ) - { - // this is the second book-like control already so don't do - // anything as we don't know which one should have its page - // changed - bookctrl = NULL; - break; - } - - bookctrl = window; - } - } - - if ( bookctrl && bookctrl->wxWindowMSW::MSWProcessMessage(pMsg) ) - return true; - } - - return wxTopLevelWindowBase::MSWProcessMessage(pMsg); -} - WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) { WXLRESULT rc = 0; @@ -425,29 +373,10 @@ bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate, // no dialogs support under MicroWin yet return CreateFrame(title, pos, size); #else // !__WXMICROWIN__ - wxWindow *parent = GetParent(); - - // for the dialogs without wxDIALOG_NO_PARENT style, use the top level - // app window as parent - this avoids creating modal dialogs without - // parent - if ( !parent && !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT) ) - { - parent = wxTheApp->GetTopWindow(); - - if ( parent ) - { - // don't use transient windows as parents, this is dangerous as it - // can lead to a crash if the parent is destroyed before the child - // - // also don't use the window which is currently hidden as then the - // dialog would be hidden as well - if ( (parent->GetExtraStyle() & wxWS_EX_TRANSIENT) || - !parent->IsShown() ) - { - parent = NULL; - } - } - } + // static cast is valid as we're only ever called for dialogs + wxWindow * const + parent = static_cast(this)-> + GetParentForModalDialog(GetParent()); m_hWnd = (WXHWND)::CreateDialogIndirect ( @@ -466,25 +395,10 @@ bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate, return false; } - WXDWORD exflags; - (void)MSWGetCreateWindowFlags(&exflags); - - if ( exflags ) - { - ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exflags); - ::SetWindowPos(GetHwnd(), - exflags & WS_EX_TOPMOST ? HWND_TOPMOST : 0, - 0, 0, 0, 0, - SWP_NOSIZE | - SWP_NOMOVE | - (exflags & WS_EX_TOPMOST ? 0 : SWP_NOZORDER) | - SWP_NOACTIVATE); - } - #if !defined(__WXWINCE__) // For some reason, the system menu is activated when we use the // WS_EX_CONTEXTHELP style, so let's set a reasonable icon - if ( exflags & WS_EX_CONTEXTHELP ) + if ( HasExtraStyle(wxWS_EX_CONTEXTHELP) ) { wxFrame *winTop = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame); if ( winTop ) @@ -498,7 +412,7 @@ bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate, } } } -#endif +#endif // !__WXWINCE__ // move the dialog to its initial position without forcing repainting int x, y, w, h; @@ -522,7 +436,7 @@ bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate, if ( !title.empty() ) { - ::SetWindowText(GetHwnd(), title); + ::SetWindowText(GetHwnd(), title.wx_str()); } SubclassWin(m_hWnd); @@ -545,7 +459,13 @@ bool wxTopLevelWindowMSW::CreateFrame(const wxString& title, const wxSize sz = IsAlwaysMaximized() ? wxDefaultSize : size; - return MSWCreate(wxCanvasClassName, title, pos, sz, flags, exflags); +#ifndef __WXWINCE__ + if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) + exflags |= WS_EX_LAYOUTRTL; +#endif + + return MSWCreate(MSWGetRegisteredClassName(), + title.wx_str(), pos, sz, flags, exflags); } bool wxTopLevelWindowMSW::Create(wxWindow *parent, @@ -558,9 +478,6 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent, { bool ret wxDUMMY_INITIALIZE(false); - // init our fields - Init(); - wxSize sizeReal = size; if ( !sizeReal.IsFullySpecified() ) { @@ -599,12 +516,23 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent, // reuse the code in MSWGetStyle() but correct the results slightly for // the dialog - dlgTemplate->style = MSWGetStyle(style, NULL); + // + // NB: we need a temporary variable as we can't pass pointer to + // dwExtendedStyle directly, it's not aligned correctly for 64 bit + // architectures + WXDWORD dwExtendedStyle; + dlgTemplate->style = MSWGetStyle(style, &dwExtendedStyle); + dlgTemplate->dwExtendedStyle = dwExtendedStyle; // all dialogs are popups dlgTemplate->style |= WS_POPUP; #ifndef __WXWINCE__ + if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) + { + dlgTemplate->dwExtendedStyle |= WS_EX_LAYOUTRTL; + } + // force 3D-look if necessary, it looks impossibly ugly otherwise if ( style & (wxRESIZE_BORDER | wxCAPTION) ) dlgTemplate->style |= DS_MODALFRAME; @@ -652,6 +580,8 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent, wxTopLevelWindowMSW::~wxTopLevelWindowMSW() { + SendDestroyEvent(); + #if defined(__SMARTPHONE__) || defined(__POCKETPC__) SHACTIVATEINFO* info = (SHACTIVATEINFO*) m_activateInfo; delete info; @@ -704,12 +634,21 @@ bool wxTopLevelWindowMSW::Show(bool show) m_maximizeOnShow = false; } + else if ( m_iconized ) + { + // iconize and show + nShowCmd = SW_MINIMIZE; + } else // just show { - if ( GetWindowStyle() & wxFRAME_TOOL_WINDOW ) - nShowCmd = SW_SHOWNA; - else - nShowCmd = SW_SHOW; + // we shouldn't use SW_SHOW which also activates the window for + // tool frames (as they shouldn't steal focus from the main window) + // nor for the currently disabled windows as they would be enabled + // as a side effect + if ( HasFlag(wxFRAME_TOOL_WINDOW) || !IsEnabled() ) + nShowCmd = SW_SHOWNA; + else + nShowCmd = SW_SHOW; } } else // hide @@ -774,7 +713,8 @@ void wxTopLevelWindowMSW::Maximize(bool maximize) bool wxTopLevelWindowMSW::IsMaximized() const { return IsAlwaysMaximized() || -#if !defined(__SMARTPHONE__) && !defined(__POCKETPC__) +#if !defined(__SMARTPHONE__) && !defined(__POCKETPC__) && !defined(__WINCE_STANDARDSDK__) + (::IsZoomed(GetHwnd()) != 0) || #endif m_maximizeOnShow; @@ -782,7 +722,17 @@ bool wxTopLevelWindowMSW::IsMaximized() const void wxTopLevelWindowMSW::Iconize(bool iconize) { - DoShowWindow(iconize ? SW_MINIMIZE : SW_RESTORE); + if ( IsShown() ) + { + // change the window state immediately + DoShowWindow(iconize ? SW_MINIMIZE : SW_RESTORE); + } + else // hidden + { + // iconizing the window shouldn't show it so just remember that we need + // to become iconized when shown later + m_iconized = true; + } } bool wxTopLevelWindowMSW::IsIconized() const @@ -790,6 +740,9 @@ bool wxTopLevelWindowMSW::IsIconized() const #ifdef __WXWINCE__ return false; #else + if ( !IsShown() ) + return m_iconized; + // don't use m_iconized, it may be briefly out of sync with the real state // as it's only modified when we receive a WM_SIZE and we could be called // from an event handler from one of the messages we receive before it, @@ -803,6 +756,88 @@ void wxTopLevelWindowMSW::Restore() DoShowWindow(SW_RESTORE); } +void wxTopLevelWindowMSW::SetLayoutDirection(wxLayoutDirection dir) +{ + if ( dir == wxLayout_Default ) + dir = wxTheApp->GetLayoutDirection(); + + if ( dir != wxLayout_Default ) + wxTopLevelWindowBase::SetLayoutDirection(dir); +} + +// ---------------------------------------------------------------------------- +// wxTopLevelWindowMSW geometry +// ---------------------------------------------------------------------------- + +#ifndef __WXWINCE__ + +void wxTopLevelWindowMSW::DoGetPosition(int *x, int *y) const +{ + if ( IsIconized() ) + { + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + if ( ::GetWindowPlacement(GetHwnd(), &wp) ) + { + RECT& rc = wp.rcNormalPosition; + + // the position returned by GetWindowPlacement() is in workspace + // coordinates except for windows with WS_EX_TOOLWINDOW style + if ( !HasFlag(wxFRAME_TOOL_WINDOW) ) + { + // we must use the correct display for the translation as the + // task bar might be shown on one display but not the other one + int n = wxDisplay::GetFromWindow(this); + wxDisplay dpy(n == wxNOT_FOUND ? 0 : n); + const wxPoint ptOfs = dpy.GetClientArea().GetPosition() - + dpy.GetGeometry().GetPosition(); + + rc.left += ptOfs.x; + rc.top += ptOfs.y; + } + + if ( x ) + *x = rc.left; + if ( y ) + *y = rc.top; + + return; + } + + wxLogLastError(_T("GetWindowPlacement")); + } + //else: normal case + + wxTopLevelWindowBase::DoGetPosition(x, y); +} + +void wxTopLevelWindowMSW::DoGetSize(int *width, int *height) const +{ + if ( IsIconized() ) + { + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + if ( ::GetWindowPlacement(GetHwnd(), &wp) ) + { + const RECT& rc = wp.rcNormalPosition; + + if ( width ) + *width = rc.right - rc.left; + if ( height ) + *height = rc.bottom - rc.top; + + return; + } + + wxLogLastError(_T("GetWindowPlacement")); + } + //else: normal case + + wxTopLevelWindowBase::DoGetSize(width, height); +} + +#endif // __WXWINCE__ + // ---------------------------------------------------------------------------- // wxTopLevelWindowMSW fullscreen // ---------------------------------------------------------------------------- @@ -898,7 +933,7 @@ bool wxTopLevelWindowMSW::ShowFullScreen(bool show, long style) // finally send an event allowing the window to relayout itself &c wxSizeEvent event(rect.GetSize(), GetId()); - GetEventHandler()->ProcessEvent(event); + HandleWindowEvent(event); } else // stop showing full screen { @@ -928,30 +963,44 @@ wxString wxTopLevelWindowMSW::GetTitle() const return GetLabel(); } -void wxTopLevelWindowMSW::SetIcon(const wxIcon& icon) +bool wxTopLevelWindowMSW::DoSelectAndSetIcon(const wxIconBundle& icons, + int smX, + int smY, + int i) { - SetIcons( wxIconBundle( icon ) ); + const wxSize size(::GetSystemMetrics(smX), ::GetSystemMetrics(smY)); + + const wxIcon icon = icons.GetIconOfExactSize(size); + if ( icon.Ok() ) + { + ::SendMessage(GetHwnd(), WM_SETICON, i, (LPARAM)GetHiconOf(icon)); + return true; + } + + return false; } void wxTopLevelWindowMSW::SetIcons(const wxIconBundle& icons) { wxTopLevelWindowBase::SetIcons(icons); -#if !defined(__WXMICROWIN__) - const wxIcon& sml = icons.GetIcon( wxSize( 16, 16 ) ); - if( sml.Ok() && sml.GetWidth() == 16 && sml.GetHeight() == 16 ) + if ( icons.IsEmpty() ) { - ::SendMessage( GetHwndOf( this ), WM_SETICON, ICON_SMALL, - (LPARAM)GetHiconOf(sml) ); + // FIXME: SetIcons(wxNullIconBundle) should unset existing icons, + // but we currently don't do that + wxASSERT_MSG( m_icons.IsEmpty(), "unsetting icons doesn't work" ); + return; } - const wxIcon& big = icons.GetIcon( wxSize( 32, 32 ) ); - if( big.Ok() && big.GetWidth() == 32 && big.GetHeight() == 32 ) + bool anySet = + DoSelectAndSetIcon(icons, SM_CXSMICON, SM_CYSMICON, ICON_SMALL); + if ( DoSelectAndSetIcon(icons, SM_CXICON, SM_CYICON, ICON_BIG) ) + anySet = true; + + if ( !anySet ) { - ::SendMessage( GetHwndOf( this ), WM_SETICON, ICON_BIG, - (LPARAM)GetHiconOf(big) ); + wxFAIL_MSG( "icon bundle doesn't contain any suitable icon" ); } -#endif // !__WXMICROWIN__ } bool wxTopLevelWindowMSW::EnableCloseButton(bool enable) @@ -1022,7 +1071,7 @@ bool wxTopLevelWindowMSW::SetShape(const wxRegion& region) DWORD dwStyle = ::GetWindowLong(GetHwnd(), GWL_STYLE); DWORD dwExStyle = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE); ::GetClientRect(GetHwnd(), &rect); - ::AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle); + ::AdjustWindowRectEx(&rect, dwStyle, ::GetMenu(GetHwnd()) != NULL, dwExStyle); ::OffsetRgn(hrgn, -rect.left, -rect.top); // Now call the shape API with the new region. @@ -1043,10 +1092,10 @@ void wxTopLevelWindowMSW::RequestUserAttention(int flags) // provide FlashWindowEx() declaration, so try to detect whether we have // real headers for WINVER 0x0500 by checking for existence of a symbol not // declated in MSVC6 header -#if defined(FLASHW_STOP) && defined(VK_XBUTTON1) +#if defined(FLASHW_STOP) && defined(VK_XBUTTON1) && wxUSE_DYNLIB_CLASS // available in the headers, check if it is supported by the system typedef BOOL (WINAPI *FlashWindowEx_t)(FLASHWINFO *pfwi); - FlashWindowEx_t s_pfnFlashWindowEx = NULL; + static FlashWindowEx_t s_pfnFlashWindowEx = NULL; if ( !s_pfnFlashWindowEx ) { wxDynamicLibrary dllUser32(_T("user32.dll")); @@ -1089,17 +1138,27 @@ void wxTopLevelWindowMSW::RequestUserAttention(int flags) bool wxTopLevelWindowMSW::SetTransparent(wxByte alpha) { +#if wxUSE_DYNLIB_CLASS typedef DWORD (WINAPI *PSETLAYEREDWINDOWATTR)(HWND, DWORD, BYTE, DWORD); - static PSETLAYEREDWINDOWATTR pSetLayeredWindowAttributes = NULL; + static PSETLAYEREDWINDOWATTR + pSetLayeredWindowAttributes = (PSETLAYEREDWINDOWATTR)-1; - if ( pSetLayeredWindowAttributes == NULL ) + if ( pSetLayeredWindowAttributes == (PSETLAYEREDWINDOWATTR)-1 ) { wxDynamicLibrary dllUser32(_T("user32.dll")); + + // use RawGetSymbol() and not GetSymbol() to avoid error messages under + // Windows 95: there is nothing the user can do about this anyhow pSetLayeredWindowAttributes = (PSETLAYEREDWINDOWATTR) - dllUser32.GetSymbol(wxT("SetLayeredWindowAttributes")); + dllUser32.RawGetSymbol(wxT("SetLayeredWindowAttributes")); + + // it's ok to destroy dllUser32 here, we link statically to user32.dll + // anyhow so it won't be unloaded } - if ( pSetLayeredWindowAttributes == NULL ) + + if ( !pSetLayeredWindowAttributes ) return false; +#endif // wxUSE_DYNLIB_CLASS LONG exstyle = GetWindowLong(GetHwnd(), GWL_EXSTYLE); @@ -1111,26 +1170,45 @@ bool wxTopLevelWindowMSW::SetTransparent(wxByte alpha) return true; } +#if wxUSE_DYNLIB_CLASS // Otherwise, set the layered style if needed and set the alpha value if ((exstyle & WS_EX_LAYERED) == 0 ) SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyle | WS_EX_LAYERED); - return pSetLayeredWindowAttributes(GetHwnd(), 0, (BYTE)alpha, LWA_ALPHA) != 0; + if ( pSetLayeredWindowAttributes(GetHwnd(), 0, (BYTE)alpha, LWA_ALPHA) ) + return true; +#endif // wxUSE_DYNLIB_CLASS + + return false; } bool wxTopLevelWindowMSW::CanSetTransparent() { // The API is available on win2k and above - + static int os_type = -1; static int ver_major = -1; if (os_type == -1) os_type = ::wxGetOsVersion(&ver_major); - return (os_type == wxWINDOWS_NT && ver_major >= 5); + return (os_type == wxOS_WINDOWS_NT && ver_major >= 5); +} + + +void wxTopLevelWindowMSW::DoFreeze() +{ + // do nothing: freezing toplevel window causes paint and mouse events + // to go through it any TLWs under it, so the best we can do is to freeze + // all children -- and wxWindowBase::Freeze() does that } +void wxTopLevelWindowMSW::DoThaw() +{ + // intentionally empty -- see DoFreeze() +} + + // ---------------------------------------------------------------------------- // wxTopLevelWindow event handling // ---------------------------------------------------------------------------- @@ -1143,7 +1221,7 @@ void wxTopLevelWindowMSW::OnActivate(wxActivateEvent& event) { // restore focus to the child which was last focused unless we already // have it - wxLogTrace(_T("focus"), _T("wxTLW %08x activated."), (int) m_hWnd); + wxLogTrace(_T("focus"), _T("wxTLW %p activated."), m_hWnd); wxWindow *winFocus = FindFocus(); if ( !winFocus || wxGetTopLevelParent(winFocus) != this ) @@ -1166,7 +1244,9 @@ void wxTopLevelWindowMSW::OnActivate(wxActivateEvent& event) if ( m_winLastFocused ) { // let it know that it doesn't have focus any more - m_winLastFocused->HandleKillFocus((WXHWND)NULL); + // But this will already be done via WM_KILLFOCUS, so we'll get two kill + // focus events if we call it explicitly. + // m_winLastFocused->HandleKillFocus((WXHWND)NULL); // and don't remember it if it's a child from some other frame if ( wxGetTopLevelParent(m_winLastFocused) != this ) @@ -1176,10 +1256,9 @@ void wxTopLevelWindowMSW::OnActivate(wxActivateEvent& event) } wxLogTrace(_T("focus"), - _T("wxTLW %08x deactivated, last focused: %08x."), - (int) m_hWnd, - (int) (m_winLastFocused ? GetHwndOf(m_winLastFocused) - : NULL)); + _T("wxTLW %p deactivated, last focused: %p."), + m_hWnd, + m_winLastFocused ? GetHwndOf(m_winLastFocused) : NULL); event.Skip(); }