Skip to content

Commit

Permalink
Avoid using gdk_window_freeze_updates() to implement Freeze()
Browse files Browse the repository at this point in the history
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
  • Loading branch information
paulcor committed Jun 24, 2015
1 parent c15ae5e commit b7cf54d
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 49 deletions.
1 change: 1 addition & 0 deletions include/wx/gtk/window.h
Expand Up @@ -383,6 +383,7 @@ class WXDLLIMPEXP_CORE wxWindowGTK : public wxWindowBase
virtual void DoFreeze() wxOVERRIDE;
virtual void DoThaw() wxOVERRIDE;

void GTKConnectFreezeWidget(GtkWidget* widget);
void GTKFreezeWidget(GtkWidget *w);
void GTKThawWidget(GtkWidget *w);
void GTKDisconnect(void* instance);
Expand Down
5 changes: 5 additions & 0 deletions src/gtk/textctrl.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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) )
{
Expand Down Expand Up @@ -2021,6 +2024,8 @@ void wxTextCtrl::DoThaw()
}

GTKThawWidget(m_text);
if (m_widget != m_text)
GTKThawWidget(m_widget);
}

// ----------------------------------------------------------------------------
Expand Down
84 changes: 35 additions & 49 deletions src/gtk/window.cpp
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -5120,53 +5110,49 @@ GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
// freeze/thaw
// ----------------------------------------------------------------------------

void wxWindowGTK::GTKFreezeWidget(GtkWidget* widget)
extern "C" {
static gboolean draw_freeze(GtkWidget*, void*, wxWindow*)
{
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);
}
// 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
gdk_window_freeze_updates(window);
}
}
g_signal_handler_block(widget, id);
}

void wxWindowGTK::GTKFreezeWidget(GtkWidget* widget)
{
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);
}

0 comments on commit b7cf54d

Please sign in to comment.