]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/toplevel.cpp
fixing focus, fixes #11911
[wxWidgets.git] / src / msw / toplevel.cpp
index f87a9827358e98aedce67319b35455759fd780bf..d5b115495e7b8d9988796b8407ca07bef2237cdc 100644 (file)
@@ -78,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)
@@ -139,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;
@@ -299,7 +288,7 @@ WXHWND wxTopLevelWindowMSW::MSWGetParent() const
         if ( !parent )
         {
             // this flag doesn't make sense then and will be ignored
-            wxFAIL_MSG( _T("wxFRAME_FLOAT_ON_PARENT but no parent?") );
+            wxFAIL_MSG( wxT("wxFRAME_FLOAT_ON_PARENT but no parent?") );
         }
         else
         {
@@ -384,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<wxDialog *>(this)->
+                    GetParentForModalDialog(GetParent());
 
     m_hWnd = (WXHWND)::CreateDialogIndirect
                        (
@@ -494,7 +464,8 @@ bool wxTopLevelWindowMSW::CreateFrame(const wxString& title,
         exflags |= WS_EX_LAYOUTRTL;
 #endif
 
-    return MSWCreate(wxCanvasClassName, title.wx_str(), pos, sz, flags, exflags);
+    return MSWCreate(MSWGetRegisteredClassName(),
+                     title.wx_str(), pos, sz, flags, exflags);
 }
 
 bool wxTopLevelWindowMSW::Create(wxWindow *parent,
@@ -505,22 +476,21 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent,
                                  long style,
                                  const wxString& name)
 {
-    bool ret wxDUMMY_INITIALIZE(false);
-
     wxSize sizeReal = size;
     if ( !sizeReal.IsFullySpecified() )
     {
         sizeReal.SetDefaults(GetDefaultSize());
     }
 
-    m_windowStyle = style;
-
-    SetName(name);
-
-    m_windowId = id == wxID_ANY ? NewControlId() : id;
-
+    // notice that we should append this window to wxTopLevelWindows list
+    // before calling CreateBase() as it behaves differently for TLW and
+    // non-TLW windows
     wxTopLevelWindows.Append(this);
 
+    bool ret = CreateBase(parent, id, pos, sizeReal, style, name);
+    if ( !ret )
+        return false;
+
     if ( parent )
         parent->AddChild(this);
 
@@ -545,7 +515,13 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent,
 
         // reuse the code in MSWGetStyle() but correct the results slightly for
         // the dialog
-        dlgTemplate->style = MSWGetStyle(style, &dlgTemplate->dwExtendedStyle);
+        //
+        // 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;
@@ -603,6 +579,8 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent,
 
 wxTopLevelWindowMSW::~wxTopLevelWindowMSW()
 {
+    SendDestroyEvent();
+
 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
     SHACTIVATEINFO* info = (SHACTIVATEINFO*) m_activateInfo;
     delete info;
@@ -634,6 +612,14 @@ void wxTopLevelWindowMSW::DoShowWindow(int nShowCmd)
     m_iconized = nShowCmd == SW_MINIMIZE;
 }
 
+void wxTopLevelWindowMSW::ShowWithoutActivating()
+{
+    if ( !wxWindowBase::Show(true) )
+        return;
+        
+    DoShowWindow(SW_SHOWNA);
+}
+
 bool wxTopLevelWindowMSW::Show(bool show)
 {
     // don't use wxWindow version as we want to call DoShowWindow() ourselves
@@ -655,6 +641,11 @@ bool wxTopLevelWindowMSW::Show(bool show)
 
             m_maximizeOnShow = false;
         }
+        else if ( m_iconized )
+        {
+            // iconize and show
+            nShowCmd = SW_MINIMIZE;
+        }
         else // just show
         {
             // we shouldn't use SW_SHOW which also activates the window for
@@ -738,7 +729,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
@@ -746,6 +747,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,
@@ -807,7 +811,7 @@ void wxTopLevelWindowMSW::DoGetPosition(int *x, int *y) const
             return;
         }
 
-        wxLogLastError(_T("GetWindowPlacement"));
+        wxLogLastError(wxT("GetWindowPlacement"));
     }
     //else: normal case
 
@@ -832,7 +836,7 @@ void wxTopLevelWindowMSW::DoGetSize(int *width, int *height) const
             return;
         }
 
-        wxLogLastError(_T("GetWindowPlacement"));
+        wxLogLastError(wxT("GetWindowPlacement"));
     }
     //else: normal case
 
@@ -966,7 +970,7 @@ wxString wxTopLevelWindowMSW::GetTitle() const
     return GetLabel();
 }
 
-void wxTopLevelWindowMSW::DoSelectAndSetIcon(const wxIconBundle& icons,
+bool wxTopLevelWindowMSW::DoSelectAndSetIcon(const wxIconBundle& icons,
                                              int smX,
                                              int smY,
                                              int i)
@@ -977,15 +981,33 @@ void wxTopLevelWindowMSW::DoSelectAndSetIcon(const wxIconBundle& icons,
     if ( icon.Ok() )
     {
         ::SendMessage(GetHwnd(), WM_SETICON, i, (LPARAM)GetHiconOf(icon));
+        return true;
     }
+
+    return false;
 }
 
 void wxTopLevelWindowMSW::SetIcons(const wxIconBundle& icons)
 {
     wxTopLevelWindowBase::SetIcons(icons);
 
-    DoSelectAndSetIcon(icons, SM_CXSMICON, SM_CYSMICON, ICON_SMALL);
-    DoSelectAndSetIcon(icons, SM_CXICON, SM_CYICON, ICON_BIG);
+    if ( icons.IsEmpty() )
+    {
+        // 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;
+    }
+
+    bool anySet =
+        DoSelectAndSetIcon(icons, SM_CXSMICON, SM_CYSMICON, ICON_SMALL);
+    if ( DoSelectAndSetIcon(icons, SM_CXICON, SM_CYICON, ICON_BIG) )
+        anySet = true;
+
+    if ( !anySet )
+    {
+        wxFAIL_MSG( "icon bundle doesn't contain any suitable icon" );
+    }
 }
 
 bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
@@ -1006,7 +1028,7 @@ bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
                           MF_BYCOMMAND |
                           (enable ? MF_ENABLED : MF_GRAYED)) == -1 )
     {
-        wxLogLastError(_T("EnableMenuItem(SC_CLOSE)"));
+        wxLogLastError(wxT("EnableMenuItem(SC_CLOSE)"));
 
         return false;
     }
@@ -1014,7 +1036,7 @@ bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
     // update appearance immediately
     if ( !::DrawMenuBar(GetHwnd()) )
     {
-        wxLogLastError(_T("DrawMenuBar"));
+        wxLogLastError(wxT("DrawMenuBar"));
     }
 #endif
 #endif // !__WXMICROWIN__
@@ -1027,7 +1049,7 @@ bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
 bool wxTopLevelWindowMSW::SetShape(const wxRegion& region)
 {
     wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false,
-                 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
+                 wxT("Shaped windows must be created with the wxFRAME_SHAPED style."));
 
     // The empty region signifies that the shape should be removed from the
     // window.
@@ -1035,7 +1057,7 @@ bool wxTopLevelWindowMSW::SetShape(const wxRegion& region)
     {
         if (::SetWindowRgn(GetHwnd(), NULL, TRUE) == 0)
         {
-            wxLogLastError(_T("SetWindowRgn"));
+            wxLogLastError(wxT("SetWindowRgn"));
             return false;
         }
         return true;
@@ -1056,13 +1078,13 @@ 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.
     if (::SetWindowRgn(GetHwnd(), hrgn, TRUE) == 0)
     {
-        wxLogLastError(_T("SetWindowRgn"));
+        wxLogLastError(wxT("SetWindowRgn"));
         return false;
     }
     return true;
@@ -1080,12 +1102,12 @@ void wxTopLevelWindowMSW::RequestUserAttention(int flags)
 #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"));
+        wxDynamicLibrary dllUser32(wxT("user32.dll"));
         s_pfnFlashWindowEx = (FlashWindowEx_t)
-                                dllUser32.GetSymbol(_T("FlashWindowEx"));
+                                dllUser32.GetSymbol(wxT("FlashWindowEx"));
 
         // we can safely unload user32.dll here, it's going to remain loaded as
         // long as the program is running anyhow
@@ -1125,15 +1147,23 @@ 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"));
+        wxDynamicLibrary dllUser32(wxT("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
 
@@ -1198,7 +1228,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 %p activated."), m_hWnd);
+        wxLogTrace(wxT("focus"), wxT("wxTLW %p activated."), m_hWnd);
 
         wxWindow *winFocus = FindFocus();
         if ( !winFocus || wxGetTopLevelParent(winFocus) != this )
@@ -1221,7 +1251,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 )
@@ -1230,8 +1262,8 @@ void wxTopLevelWindowMSW::OnActivate(wxActivateEvent& event)
             }
         }
 
-        wxLogTrace(_T("focus"),
-                   _T("wxTLW %p deactivated, last focused: %p."),
+        wxLogTrace(wxT("focus"),
+                   wxT("wxTLW %p deactivated, last focused: %p."),
                    m_hWnd,
                    m_winLastFocused ? GetHwndOf(m_winLastFocused) : NULL);
 
@@ -1305,7 +1337,7 @@ void wxTLWHiddenParentModule::OnExit()
     {
         if ( !::DestroyWindow(ms_hwnd) )
         {
-            wxLogLastError(_T("DestroyWindow(hidden TLW parent)"));
+            wxLogLastError(wxT("DestroyWindow(hidden TLW parent)"));
         }
 
         ms_hwnd = NULL;
@@ -1315,7 +1347,7 @@ void wxTLWHiddenParentModule::OnExit()
     {
         if ( !::UnregisterClass(ms_className, wxGetInstance()) )
         {
-            wxLogLastError(_T("UnregisterClass(\"wxTLWHiddenParent\")"));
+            wxLogLastError(wxT("UnregisterClass(\"wxTLWHiddenParent\")"));
         }
 
         ms_className = NULL;
@@ -1329,7 +1361,7 @@ HWND wxTLWHiddenParentModule::GetHWND()
     {
         if ( !ms_className )
         {
-            static const wxChar *HIDDEN_PARENT_CLASS = _T("wxTLWHiddenParent");
+            static const wxChar *HIDDEN_PARENT_CLASS = wxT("wxTLWHiddenParent");
 
             WNDCLASS wndclass;
             wxZeroMemory(wndclass);
@@ -1340,7 +1372,7 @@ HWND wxTLWHiddenParentModule::GetHWND()
 
             if ( !::RegisterClass(&wndclass) )
             {
-                wxLogLastError(_T("RegisterClass(\"wxTLWHiddenParent\")"));
+                wxLogLastError(wxT("RegisterClass(\"wxTLWHiddenParent\")"));
             }
             else
             {
@@ -1352,7 +1384,7 @@ HWND wxTLWHiddenParentModule::GetHWND()
                                  (HMENU)NULL, wxGetInstance(), NULL);
         if ( !ms_hwnd )
         {
-            wxLogLastError(_T("CreateWindow(hidden TLW parent)"));
+            wxLogLastError(wxT("CreateWindow(hidden TLW parent)"));
         }
     }