Merge branch 'gtk-persist-tlw'

Fix bugs affecting wxPersistentTLW under GTK.

See https://github.com/wxWidgets/wxWidgets/pull/1419
This commit is contained in:
Vadim Zeitlin
2019-07-18 17:44:35 +02:00
5 changed files with 118 additions and 3 deletions

View File

@@ -112,6 +112,14 @@ public:
// size of WM decorations
struct DecorSize
{
DecorSize()
{
left =
right =
top =
bottom = 0;
}
int left, right, top, bottom;
};
DecorSize m_decorSize;
@@ -156,6 +164,9 @@ private:
// size hint increments
int m_incWidth, m_incHeight;
// position before it last changed
wxPoint m_lastPos;
// is the frame currently iconized?
bool m_isIconized;

View File

@@ -228,6 +228,12 @@ public:
/**
Iconizes or restores the window.
Note that in wxGTK the change to the window state is not immediate,
i.e. IsIconized() will typically return @false right after a call to
Iconize() and its return value will only change after the control flow
returns to the event loop and the notification about the window being
really iconized is received.
@param iconize
If @true, iconizes the window; if @false, shows and restores it.
@@ -285,6 +291,9 @@ public:
/**
Maximizes or restores the window.
Note that, just as with Iconize(), the change to the window state is
not immediate in at least wxGTK port.
@param maximize
If @true, maximizes the window, otherwise it restores it.

View File

@@ -307,7 +307,6 @@ bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title
if (style & wxRESIZE_BORDER)
m_gdkFunc |= GDK_FUNC_RESIZE;
gtk_window_set_default_size(GTK_WINDOW(m_widget), m_width, m_height);
memset(&m_decorSize, 0, sizeof(m_decorSize));
m_deferShow = false;
if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))

View File

@@ -326,6 +326,8 @@ void wxTopLevelWindowGTK::GTKConfigureEvent(int x, int y)
if (m_x != point.x || m_y != point.y)
{
m_lastPos = wxPoint(m_x, m_y);
m_x = point.x;
m_y = point.y;
wxMoveEvent event(point, GetId());
@@ -565,7 +567,6 @@ void wxTopLevelWindowGTK::Init()
m_updateDecorSize = true;
m_netFrameExtentsTimerId = 0;
m_incWidth = m_incHeight = 0;
memset(&m_decorSize, 0, sizeof(m_decorSize));
m_urgency_hint = -2;
}
@@ -1496,6 +1497,62 @@ void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
{
if ( iconize != m_isIconized )
{
/*
We get a configure-event _before_ the window is iconized with dummy
(0, 0) coordinates. Unfortunately we can't just ignore this event
when we get it, because we can't know if we're going to be iconized
or not: even remembering that we should be soon in Iconize() itself
doesn't help due to the crazy sequence of events generated by GTK,
e.g. under X11 for the sequence of Iconize() and Show() calls we
get the following events with GTK2:
- window-state changes to GDK_WINDOW_STATE_ICONIFIED | WITHDRAWN
- window-state changes to just GDK_WINDOW_STATE_ICONIFIED
- map event
- window-state changes to normal
- configure event with normal size
- window-state changes to GDK_WINDOW_STATE_ICONIFIED
- configure event with normal size
- configure event with (0, 0) size
- window-state changes to normal (yes, again)
- configure event with (0, 0) size
- window-state changes to GDK_WINDOW_STATE_ICONIFIED
So even though we could ignore the first (0, 0) configure event, we
still wouldn't be able to ignore the second one, happening after
the inexplicable switch to normal state.
For completeness, with GTK3 the sequence of events is simpler, but
still very unhelpful for our purposes:
- window-state changes to GDK_WINDOW_STATE_ICONIFIED
- window-state changes to normal
- map event
- configure event with normal size
- configure event with normal size (yes, because one is not enough)
- configure event with (0, 0) size
- configure event with (0, 0) size (because why not have 2 of them)
- window-state changes to GDK_WINDOW_STATE_ICONIFIED
Here again we have (0, 0) configure events happening _after_ the
window-state switch to normal, that would reset our flag.
In conclusion, we have no choice but to assume that the window got
really moved, but at least we can remember its previous position in
order to restore it here if it turns out that it was just iconized.
*/
if ( iconize )
{
if ( wxPoint(m_x, m_y) == wxPoint(0, 0) )
{
m_x = m_lastPos.x;
m_y = m_lastPos.y;
// This is not really necessary, but seems tidier.
m_lastPos = wxPoint();
}
}
m_isIconized = iconize;
(void)SendIconizeEvent(iconize);
}

View File

@@ -20,6 +20,10 @@
#ifndef WX_PRECOMP
#include "wx/frame.h"
#ifdef __WXGTK__
#include "wx/stopwatch.h"
#endif // __WXGTK__
#endif // WX_PRECOMP
#include "wx/persist/toplevel.h"
@@ -88,6 +92,7 @@ TEST_CASE_METHOD(PersistenceTests, "wxPersistTLW", "[persist][tlw]")
}
// Now try recreating the frame using the restored values.
bool checkIconized = true;
{
wxFrame* const frame = CreatePersistenceTestFrame();
@@ -106,6 +111,21 @@ TEST_CASE_METHOD(PersistenceTests, "wxPersistTLW", "[persist][tlw]")
frame->Iconize();
frame->Show();
#ifdef __WXGTK__
wxStopWatch sw;
while ( !frame->IsIconized() )
{
wxYield();
if ( sw.Time() > 500 )
{
// 500ms should be enough for the window to end up iconized.
WARN("Frame wasn't iconized as expected");
checkIconized = false;
break;
}
}
#endif // __WXGTK__
delete frame;
}
@@ -115,8 +135,27 @@ TEST_CASE_METHOD(PersistenceTests, "wxPersistTLW", "[persist][tlw]")
CHECK(wxPersistenceManager::Get().RegisterAndRestore(frame));
// As above, we need to show the frame for it to be actually iconized.
frame->Show();
CHECK(!frame->IsMaximized());
CHECK(frame->IsIconized());
if ( checkIconized )
{
#ifdef __WXGTK__
wxStopWatch sw;
while ( !frame->IsIconized() )
{
wxYield();
if ( sw.Time() > 500 )
{
INFO("Abandoning wait after " << sw.Time() << "ms");
break;
}
}
#endif // __WXGTK__
CHECK(frame->IsIconized());
}
frame->Restore();