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:
parent
c15ae5e4a3
commit
b7cf54d24a
@ -383,6 +383,7 @@ protected:
|
|||||||
virtual void DoFreeze() wxOVERRIDE;
|
virtual void DoFreeze() wxOVERRIDE;
|
||||||
virtual void DoThaw() wxOVERRIDE;
|
virtual void DoThaw() wxOVERRIDE;
|
||||||
|
|
||||||
|
void GTKConnectFreezeWidget(GtkWidget* widget);
|
||||||
void GTKFreezeWidget(GtkWidget *w);
|
void GTKFreezeWidget(GtkWidget *w);
|
||||||
void GTKThawWidget(GtkWidget *w);
|
void GTKThawWidget(GtkWidget *w);
|
||||||
void GTKDisconnect(void* instance);
|
void GTKDisconnect(void* instance);
|
||||||
|
@ -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);
|
gulong sig_id = g_signal_connect(m_buffer, "mark_set", G_CALLBACK(mark_set), &m_anonymousMarkList);
|
||||||
// Create view
|
// Create view
|
||||||
m_text = gtk_text_view_new_with_buffer(m_buffer);
|
m_text = gtk_text_view_new_with_buffer(m_buffer);
|
||||||
|
GTKConnectFreezeWidget(m_text);
|
||||||
// gtk_text_view_set_buffer adds its own reference
|
// gtk_text_view_set_buffer adds its own reference
|
||||||
g_object_unref(m_buffer);
|
g_object_unref(m_buffer);
|
||||||
g_signal_handler_disconnect(m_buffer, sig_id);
|
g_signal_handler_disconnect(m_buffer, sig_id);
|
||||||
@ -1975,6 +1976,8 @@ void wxTextCtrl::DoFreeze()
|
|||||||
wxCHECK_RET(m_text != NULL, wxT("invalid text ctrl"));
|
wxCHECK_RET(m_text != NULL, wxT("invalid text ctrl"));
|
||||||
|
|
||||||
GTKFreezeWidget(m_text);
|
GTKFreezeWidget(m_text);
|
||||||
|
if (m_widget != m_text)
|
||||||
|
GTKFreezeWidget(m_widget);
|
||||||
|
|
||||||
if ( HasFlag(wxTE_MULTILINE) )
|
if ( HasFlag(wxTE_MULTILINE) )
|
||||||
{
|
{
|
||||||
@ -2021,6 +2024,8 @@ void wxTextCtrl::DoThaw()
|
|||||||
}
|
}
|
||||||
|
|
||||||
GTKThawWidget(m_text);
|
GTKThawWidget(m_text);
|
||||||
|
if (m_widget != m_text)
|
||||||
|
GTKThawWidget(m_widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -2138,9 +2138,6 @@ static void frame_clock_layout(GdkFrameClock*, wxWindow* win)
|
|||||||
|
|
||||||
void wxWindowGTK::GTKHandleRealized()
|
void wxWindowGTK::GTKHandleRealized()
|
||||||
{
|
{
|
||||||
if (IsFrozen())
|
|
||||||
DoFreeze();
|
|
||||||
|
|
||||||
GdkWindow* const window = GTKGetDrawingWindow();
|
GdkWindow* const window = GTKGetDrawingWindow();
|
||||||
|
|
||||||
if (m_wxwindow)
|
if (m_wxwindow)
|
||||||
@ -2224,11 +2221,6 @@ void wxWindowGTK::GTKHandleUnrealize()
|
|||||||
{
|
{
|
||||||
m_isGtkPositionValid = false;
|
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_wxwindow)
|
||||||
{
|
{
|
||||||
if (m_imContext)
|
if (m_imContext)
|
||||||
@ -2578,12 +2570,6 @@ wxWindowGTK::~wxWindowGTK()
|
|||||||
m_imContext = NULL;
|
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__
|
#ifdef __WXGTK3__
|
||||||
if (m_styleProvider)
|
if (m_styleProvider)
|
||||||
g_object_unref(m_styleProvider);
|
g_object_unref(m_styleProvider);
|
||||||
@ -2629,6 +2615,10 @@ void wxWindowGTK::PostCreation()
|
|||||||
{
|
{
|
||||||
wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
|
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
|
#if wxGTK_HAS_COMPOSITING_SUPPORT
|
||||||
// Set RGBA visual as soon as possible to minimize the possibility that
|
// Set RGBA visual as soon as possible to minimize the possibility that
|
||||||
// somebody uses the wrong one.
|
// somebody uses the wrong one.
|
||||||
@ -5120,53 +5110,49 @@ GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
|
|||||||
// freeze/thaw
|
// 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)
|
void wxWindowGTK::GTKFreezeWidget(GtkWidget* widget)
|
||||||
{
|
{
|
||||||
if (widget && gtk_widget_get_has_window(widget))
|
g_signal_handlers_unblock_by_func(widget, (void*)draw_freeze, this);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxWindowGTK::GTKThawWidget(GtkWidget* widget)
|
void wxWindowGTK::GTKThawWidget(GtkWidget* widget)
|
||||||
{
|
{
|
||||||
if (widget && gtk_widget_get_has_window(widget))
|
g_signal_handlers_block_by_func(widget, (void*)draw_freeze, this);
|
||||||
{
|
gtk_widget_queue_draw(widget);
|
||||||
GdkWindow* window = gtk_widget_get_window(widget);
|
|
||||||
if (window)
|
|
||||||
gdk_window_thaw_updates(window);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxWindowGTK::DoFreeze()
|
void wxWindowGTK::DoFreeze()
|
||||||
{
|
{
|
||||||
GtkWidget* widget = m_wxwindow;
|
wxCHECK_RET(m_widget, "invalid window");
|
||||||
if (widget == NULL)
|
|
||||||
widget = m_widget;
|
GTKFreezeWidget(m_widget);
|
||||||
GTKFreezeWidget(widget);
|
if (m_wxwindow && m_wxwindow != m_widget)
|
||||||
|
GTKFreezeWidget(m_wxwindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxWindowGTK::DoThaw()
|
void wxWindowGTK::DoThaw()
|
||||||
{
|
{
|
||||||
GtkWidget* widget = m_wxwindow;
|
wxCHECK_RET(m_widget, "invalid window");
|
||||||
if (widget == NULL)
|
|
||||||
widget = m_widget;
|
GTKThawWidget(m_widget);
|
||||||
GTKThawWidget(widget);
|
if (m_wxwindow && m_wxwindow != m_widget)
|
||||||
|
GTKThawWidget(m_wxwindow);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user