Avoid using gdk_window_freeze_updates() to implement Freeze()

Implement Freeze() by blocking the GtkWindow "expose-event"/"draw" signal
instead. Since the introduction of client-side windows in GTK+ 2.18,
gdk_window_freeze_updates() is unuseable because the impl_window (and thus the
update_freeze_count) for a given GdkWindow can change unpredictably. See #16795
This commit is contained in:
Paul Cornett 2015-06-24 08:43:30 -07:00
parent c15ae5e4a3
commit b7cf54d24a
3 changed files with 41 additions and 49 deletions

View File

@ -383,6 +383,7 @@ protected:
virtual void DoFreeze() wxOVERRIDE;
virtual void DoThaw() wxOVERRIDE;
void GTKConnectFreezeWidget(GtkWidget* widget);
void GTKFreezeWidget(GtkWidget *w);
void GTKThawWidget(GtkWidget *w);
void GTKDisconnect(void* instance);

View File

@ -695,6 +695,7 @@ bool wxTextCtrl::Create( wxWindow *parent,
gulong sig_id = g_signal_connect(m_buffer, "mark_set", G_CALLBACK(mark_set), &m_anonymousMarkList);
// Create view
m_text = gtk_text_view_new_with_buffer(m_buffer);
GTKConnectFreezeWidget(m_text);
// gtk_text_view_set_buffer adds its own reference
g_object_unref(m_buffer);
g_signal_handler_disconnect(m_buffer, sig_id);
@ -1975,6 +1976,8 @@ void wxTextCtrl::DoFreeze()
wxCHECK_RET(m_text != NULL, wxT("invalid text ctrl"));
GTKFreezeWidget(m_text);
if (m_widget != m_text)
GTKFreezeWidget(m_widget);
if ( HasFlag(wxTE_MULTILINE) )
{
@ -2021,6 +2024,8 @@ void wxTextCtrl::DoThaw()
}
GTKThawWidget(m_text);
if (m_widget != m_text)
GTKThawWidget(m_widget);
}
// ----------------------------------------------------------------------------

View File

@ -2138,9 +2138,6 @@ static void frame_clock_layout(GdkFrameClock*, wxWindow* win)
void wxWindowGTK::GTKHandleRealized()
{
if (IsFrozen())
DoFreeze();
GdkWindow* const window = GTKGetDrawingWindow();
if (m_wxwindow)
@ -2224,11 +2221,6 @@ void wxWindowGTK::GTKHandleUnrealize()
{
m_isGtkPositionValid = false;
// unrealizing a frozen window seems to have some lingering effect
// preventing updates to the affected area
if (IsFrozen())
DoThaw();
if (m_wxwindow)
{
if (m_imContext)
@ -2578,12 +2570,6 @@ wxWindowGTK::~wxWindowGTK()
m_imContext = NULL;
}
// avoid problem with GTK+ 2.18 where a frozen window causes the whole
// TLW to be frozen, and if the window is then destroyed, nothing ever
// gets painted again
while (IsFrozen())
Thaw();
#ifdef __WXGTK3__
if (m_styleProvider)
g_object_unref(m_styleProvider);
@ -2629,6 +2615,10 @@ void wxWindowGTK::PostCreation()
{
wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
GTKConnectFreezeWidget(m_widget);
if (m_wxwindow && m_wxwindow != m_widget)
GTKConnectFreezeWidget(m_wxwindow);
#if wxGTK_HAS_COMPOSITING_SUPPORT
// Set RGBA visual as soon as possible to minimize the possibility that
// somebody uses the wrong one.
@ -5120,53 +5110,49 @@ GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
// freeze/thaw
// ----------------------------------------------------------------------------
extern "C" {
static gboolean draw_freeze(GtkWidget*, void*, wxWindow*)
{
// stop other handlers from being invoked
return true;
}
}
void wxWindowGTK::GTKConnectFreezeWidget(GtkWidget* widget)
{
#ifdef __WXGTK3__
gulong id = g_signal_connect(widget, "draw", G_CALLBACK(draw_freeze), this);
#else
gulong id = g_signal_connect(widget, "expose-event", G_CALLBACK(draw_freeze), this);
#endif
g_signal_handler_block(widget, id);
}
void wxWindowGTK::GTKFreezeWidget(GtkWidget* widget)
{
if (widget && gtk_widget_get_has_window(widget))
{
GdkWindow* window = gtk_widget_get_window(widget);
if (window)
{
#if GTK_CHECK_VERSION(2,18,0)
#ifndef __WXGTK3__
if (gtk_check_version(2,18,0) == NULL)
#endif
{
// impl_window for a non-native GdkWindow can change if
// gdk_window_ensure_native() is called on it or some other
// GdkWindow in the same TLW. Since the freeze count is on the
// impl_window, we have to make sure impl_window does not change
// after we call gdk_window_freeze_updates().
gdk_window_ensure_native(window);
}
#endif
gdk_window_freeze_updates(window);
}
}
g_signal_handlers_unblock_by_func(widget, (void*)draw_freeze, this);
}
void wxWindowGTK::GTKThawWidget(GtkWidget* widget)
{
if (widget && gtk_widget_get_has_window(widget))
{
GdkWindow* window = gtk_widget_get_window(widget);
if (window)
gdk_window_thaw_updates(window);
}
g_signal_handlers_block_by_func(widget, (void*)draw_freeze, this);
gtk_widget_queue_draw(widget);
}
void wxWindowGTK::DoFreeze()
{
GtkWidget* widget = m_wxwindow;
if (widget == NULL)
widget = m_widget;
GTKFreezeWidget(widget);
wxCHECK_RET(m_widget, "invalid window");
GTKFreezeWidget(m_widget);
if (m_wxwindow && m_wxwindow != m_widget)
GTKFreezeWidget(m_wxwindow);
}
void wxWindowGTK::DoThaw()
{
GtkWidget* widget = m_wxwindow;
if (widget == NULL)
widget = m_widget;
GTKThawWidget(widget);
wxCHECK_RET(m_widget, "invalid window");
GTKThawWidget(m_widget);
if (m_wxwindow && m_wxwindow != m_widget)
GTKThawWidget(m_wxwindow);
}