diff --git a/include/wx/gtk/toplevel.h b/include/wx/gtk/toplevel.h index 2cf22d8e41..ac2e27a7fd 100644 --- a/include/wx/gtk/toplevel.h +++ b/include/wx/gtk/toplevel.h @@ -138,6 +138,16 @@ public: void GTKDoAfterShow(); +#ifdef __WXGTK3__ + void GTKUpdateClientSizeIfNecessary(); + + virtual void WXSetInitialFittingClientSize(int flags) wxOVERRIDE; + +private: + // Flags to call WXSetInitialFittingClientSize() with if != 0. + int m_pendingFittingClientSizeFlags; +#endif // __WXGTK3__ + protected: // give hints to the Window Manager for how the size // of the TLW can be changed by dragging diff --git a/include/wx/window.h b/include/wx/window.h index ece8b65451..4bc21b75b9 100644 --- a/include/wx/window.h +++ b/include/wx/window.h @@ -139,6 +139,13 @@ enum wxSEND_EVENT_POST = 1 }; +// Flags for WXSetInitialFittingClientSize(). +enum +{ + wxSIZE_SET_CURRENT = 0x0001, // Set the current size. + wxSIZE_SET_MIN = 0x0002 // Set the size as the minimum allowed size. +}; + // ---------------------------------------------------------------------------- // (pseudo)template list classes // ---------------------------------------------------------------------------- @@ -1541,6 +1548,13 @@ public: // window is part of a composite control. bool WXSendContextMenuEvent(const wxPoint& posInScreenCoords); + // This internal function needs to be called to set the fitting client size + // (i.e. the minimum size determined by the window sizer) when the size + // that we really need to use is not known until the window is actually + // shown, as is the case for TLWs with recent GTK versions, as it will + // update the size again when it does become known, if necessary. + virtual void WXSetInitialFittingClientSize(int flags); + // get the handle of the window for the underlying window system: this // is only used for wxWin itself or for user code which wants to call // platform-specific APIs diff --git a/src/common/sizer.cpp b/src/common/sizer.cpp index 110a5d69c3..127a557ed6 100644 --- a/src/common/sizer.cpp +++ b/src/common/sizer.cpp @@ -999,31 +999,12 @@ wxSize wxSizer::ComputeFittingWindowSize(wxWindow *window) return window->ClientToWindowSize(ComputeFittingClientSize(window)); } -#ifdef __WXGTK3__ -static void FitOnShow(wxShowEvent& event) -{ - wxWindow* win = static_cast(event.GetEventObject()); - wxSizer* sizer = win->GetSizer(); - if (sizer) - sizer->Fit(win); - win->Unbind(wxEVT_SHOW, FitOnShow); -} -#endif - wxSize wxSizer::Fit( wxWindow *window ) { wxCHECK_MSG( window, wxDefaultSize, "window can't be NULL" ); -#ifdef __WXGTK3__ - // GTK3 updates cached style information before showing a TLW, - // which may affect best size calculations, so add a handler to - // redo the calculations at that time - if (!window->IsShown() && window->IsTopLevel()) - window->Bind(wxEVT_SHOW, FitOnShow); -#endif - // set client size - window->SetClientSize(ComputeFittingClientSize(window)); + window->WXSetInitialFittingClientSize(wxSIZE_SET_CURRENT); // return entire size return window->GetSize(); @@ -1059,38 +1040,11 @@ void wxSizer::Layout() RepositionChildren(minSize); } -#ifdef __WXGTK3__ -static void SetSizeHintsOnShow(wxShowEvent& event) -{ - wxWindow* win = static_cast(event.GetEventObject()); - wxSizer* sizer = win->GetSizer(); - if (sizer) - sizer->SetSizeHints(win); - win->Unbind(wxEVT_SHOW, SetSizeHintsOnShow); -} -#endif - void wxSizer::SetSizeHints( wxWindow *window ) { // Preserve the window's max size hints, but set the // lower bound according to the sizer calculations. - - // This is equivalent to calling Fit(), except that we need to set - // the size hints _in between_ the two steps performed by Fit - // (1. ComputeFittingClientSize, 2. SetClientSize). That's because - // otherwise SetClientSize() could have no effect if there already are - // size hints in effect that forbid requested client size. - -#ifdef __WXGTK3__ - // see comment in Fit() - if (!window->IsShown() && window->IsTopLevel()) - window->Bind(wxEVT_SHOW, SetSizeHintsOnShow); -#endif - - const wxSize clientSize = ComputeFittingClientSize(window); - - window->SetMinClientSize(clientSize); - window->SetClientSize(clientSize); + window->WXSetInitialFittingClientSize(wxSIZE_SET_CURRENT | wxSIZE_SET_MIN); } #if WXWIN_COMPATIBILITY_2_8 diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp index cad8c190bf..c43f6f813d 100644 --- a/src/common/wincmn.cpp +++ b/src/common/wincmn.cpp @@ -1002,6 +1002,25 @@ wxSize wxWindowBase::WindowToClientSize(const wxSize& size) const size.y == -1 ? -1 : size.y - diff.y); } +void wxWindowBase::WXSetInitialFittingClientSize(int flags) +{ + wxSizer* const sizer = GetSizer(); + if ( !sizer ) + return; + + const wxSize + size = sizer->ComputeFittingClientSize(static_cast(this)); + + // It is important to set the min client size before changing the size + // itself as the existing size hints could prevent SetClientSize() from + // working otherwise. + if ( flags & wxSIZE_SET_MIN ) + SetMinClientSize(size); + + if ( flags & wxSIZE_SET_CURRENT ) + SetClientSize(size); +} + void wxWindowBase::SetWindowVariant( wxWindowVariant variant ) { if ( m_windowVariant != variant ) diff --git a/src/gtk/toplevel.cpp b/src/gtk/toplevel.cpp index 113da04eaf..e68cf9de0d 100644 --- a/src/gtk/toplevel.cpp +++ b/src/gtk/toplevel.cpp @@ -612,6 +612,10 @@ void wxTopLevelWindowGTK::Init() m_incWidth = m_incHeight = 0; m_urgency_hint = -2; + +#ifdef __WXGTK3__ + m_pendingFittingClientSizeFlags = 0; +#endif // __WXGTK3__ } bool wxTopLevelWindowGTK::Create( wxWindow *parent, @@ -1161,6 +1165,12 @@ bool wxTopLevelWindowGTK::Show( bool show ) bool change = base_type::Show(show); #ifdef __WXGTK3__ + if (change && show) + { + // We may need to redo it after showing the window. + GTKUpdateClientSizeIfNecessary(); + } + if (m_needSizeEvent) { m_needSizeEvent = false; @@ -1525,8 +1535,41 @@ void wxTopLevelWindowGTK::GTKDoAfterShow() wxShowEvent showEvent(GetId(), true); showEvent.SetEventObject(this); HandleWindowEvent(showEvent); + +#ifdef __WXGTK3__ + // Set the client size again if necessary, we should be able to do it + // correctly by now as the style cache should be up to date. + GTKUpdateClientSizeIfNecessary(); +#endif // __WXGTK3__ } +#ifdef __WXGTK3__ + +void wxTopLevelWindowGTK::GTKUpdateClientSizeIfNecessary() +{ + if ( m_pendingFittingClientSizeFlags ) + { + WXSetInitialFittingClientSize(m_pendingFittingClientSizeFlags); + + m_pendingFittingClientSizeFlags = 0; + } +} + +void wxTopLevelWindowGTK::WXSetInitialFittingClientSize(int flags) +{ + // In any case, update the size immediately. + wxTopLevelWindowBase::WXSetInitialFittingClientSize(flags); + + // But if we're not shown yet, the fitting size may be wrong because GTK + // style cache hasn't been updated yet and we need to do it again when the + // window becomes visible as we can be sure that by then we'll be able to + // compute the best size correctly. + if ( !IsShown() ) + m_pendingFittingClientSizeFlags = flags; +} + +#endif // __WXGTK3__ + // ---------------------------------------------------------------------------- // frame title/icon // ----------------------------------------------------------------------------