From 2c7b21718f18ab743cd79784ae28cad582f58503 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 20 May 2016 16:59:51 +0100 Subject: [PATCH] Simplify the widget rendering entry point Now that GDK has the appropriate API, we can simplify the widget drawing code into a single function. https://bugzilla.gnome.org/show_bug.cgi?id=766675 --- gtk/gtkmain.c | 27 +--------- gtk/gtkwidget.c | 114 ++++++++++++++++++++++++----------------- gtk/gtkwidgetprivate.h | 5 ++ 3 files changed, 74 insertions(+), 72 deletions(-) diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index f104f16fce..d0d91efdd6 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -1804,32 +1804,7 @@ gtk_main_do_event (GdkEvent *event) case GDK_EXPOSE: if (event->any.window) - { - gboolean is_double_buffered; - - G_GNUC_BEGIN_IGNORE_DEPRECATIONS; - is_double_buffered = gtk_widget_get_double_buffered (event_widget); - G_GNUC_END_IGNORE_DEPRECATIONS; - - if (is_double_buffered) - { - /* We handle exposes only on native windows, relying on the - * draw() handler to propagate down to non-native windows. - * This is ok now that child windows are always considered - * (semi)transparent. - */ - if (gdk_window_has_native (event->expose.window)) - { - gdk_window_begin_paint_region (event->any.window, event->expose.region); - gtk_widget_send_expose (event_widget, event); - gdk_window_end_paint (event->any.window); - } - } - else - { - gtk_widget_send_expose (event_widget, event); - } - } + gtk_widget_render (event_widget, event->any.window, event->expose.region); break; case GDK_PROPERTY_NOTIFY: diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 006be5ee85..2751a4ddb3 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -6883,21 +6883,22 @@ gtk_widget_real_mnemonic_activate (GtkWidget *widget, return TRUE; } -static const cairo_user_data_key_t event_window_key; +static const cairo_user_data_key_t mark_for_draw_key; -static GdkWindow * -gtk_cairo_get_event_window (cairo_t *cr) +static gboolean +gtk_cairo_is_marked_for_draw (cairo_t *cr) { - g_return_val_if_fail (cr != NULL, NULL); - - return cairo_get_user_data (cr, &event_window_key); + return cairo_get_user_data (cr, &mark_for_draw_key) != NULL; } static void -gtk_cairo_set_event_window (cairo_t *cr, - GdkWindow *event_window) +gtk_cairo_set_marked_for_draw (cairo_t *cr, + gboolean marked) { - cairo_set_user_data (cr, &event_window_key, event_window, NULL); + if (marked) + cairo_set_user_data (cr, &mark_for_draw_key, GINT_TO_POINTER (1), NULL); + else + cairo_set_user_data (cr, &mark_for_draw_key, NULL, NULL); } /** @@ -6919,25 +6920,28 @@ gtk_cairo_set_event_window (cairo_t *cr, * Returns: %TRUE if @window should be drawn * * Since: 3.0 - **/ + */ gboolean -gtk_cairo_should_draw_window (cairo_t *cr, +gtk_cairo_should_draw_window (cairo_t *cr, GdkWindow *window) { - GdkWindow *event_window; + GdkWindow *tmp; g_return_val_if_fail (cr != NULL, FALSE); g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); - event_window = gtk_cairo_get_event_window (cr); + if (gtk_cairo_is_marked_for_draw (cr)) + return TRUE; - if (event_window == NULL) + tmp = gdk_cairo_get_window (cr); + + if (tmp == NULL) return TRUE; while (!gdk_window_has_native (window)) window = gdk_window_get_parent (window); - return event_window == window; + return tmp == window; } void @@ -6964,9 +6968,19 @@ gtk_widget_draw_internal (GtkWidget *widget, gboolean result; gboolean push_group; - event_window = gtk_cairo_get_event_window (cr); - if (event_window) - gdk_window_mark_paint_from_clip (event_window, cr); + /* If this was a cairo_t passed via gtk_widget_draw() then we don't + * require a window + */ + if (gtk_cairo_is_marked_for_draw (cr)) + { + event_window = NULL; + } + else + { + event_window = gdk_cairo_get_window (cr); + if (event_window != NULL) + gdk_window_mark_paint_from_clip (event_window, cr); + } push_group = widget->priv->alpha != 255 && @@ -7077,7 +7091,7 @@ void gtk_widget_draw (GtkWidget *widget, cairo_t *cr) { - GdkWindow *tmp_event_window; + gboolean was_marked; g_return_if_fail (GTK_IS_WIDGET (widget)); g_return_if_fail (!widget->priv->alloc_needed); @@ -7086,17 +7100,18 @@ gtk_widget_draw (GtkWidget *widget, cairo_save (cr); - /* We have to reset the event here so that draw functions can call - * gtk_widget_draw() on random other widgets and get the desired - * effect: Drawing all contents, not just the current window. + was_marked = gtk_cairo_is_marked_for_draw (cr); + + /* We mark the window so that gtk_cairo_should_draw_window() + * will always return TRUE, and all GdkWindows get drawn */ - tmp_event_window = gtk_cairo_get_event_window (cr); - gtk_cairo_set_event_window (cr, NULL); + gtk_cairo_set_marked_for_draw (cr, TRUE); gtk_widget_draw_internal (widget, cr, TRUE); + gtk_cairo_set_marked_for_draw (cr, was_marked); + cairo_restore (cr); - gtk_cairo_set_event_window (cr, tmp_event_window); } static gboolean @@ -7506,32 +7521,12 @@ gint gtk_widget_send_expose (GtkWidget *widget, GdkEvent *event) { - cairo_t *cr; - int x, y; - gboolean do_clip; - g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE); g_return_val_if_fail (gtk_widget_get_realized (widget), TRUE); g_return_val_if_fail (event != NULL, TRUE); g_return_val_if_fail (event->type == GDK_EXPOSE, TRUE); - cr = gdk_cairo_create (event->expose.window); - gtk_cairo_set_event_window (cr, event->expose.window); - - gdk_cairo_region (cr, event->expose.region); - cairo_clip (cr); - - do_clip = _gtk_widget_get_translation_to_window (widget, - event->expose.window, - &x, &y); - cairo_translate (cr, -x, -y); - - gtk_widget_draw_internal (widget, cr, do_clip); - - /* unset here, so if someone keeps a reference to cr we - * don't leak the window. */ - gtk_cairo_set_event_window (cr, NULL); - cairo_destroy (cr); + gtk_widget_render (widget, event->any.window, event->expose.region); return FALSE; } @@ -17439,3 +17434,30 @@ gtk_widget_reset_controllers (GtkWidget *widget) gtk_event_controller_reset (controller_data->controller); } } + +void +gtk_widget_render (GtkWidget *widget, + GdkWindow *window, + const cairo_region_t *region) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + gboolean do_clip; + cairo_t *cr; + int x, y; + + if (priv->double_buffered) + { + /* We only render double buffered on native windows */ + if (!gdk_window_has_native (window)) + return; + } + + cr = gdk_window_begin_draw_frame (window, region); + + do_clip = _gtk_widget_get_translation_to_window (widget, window, &x, &y); + cairo_translate (cr, -x, -y); + + gtk_widget_draw_internal (widget, cr, do_clip); + + gdk_window_end_draw_frame (window, cr); +} diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index e51dd396a5..aa7dba6652 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -302,6 +302,11 @@ gboolean gtk_widget_query_tooltip (GtkWidget *widget, gboolean keyboard_mode, GtkTooltip *tooltip); +void gtk_widget_render (GtkWidget *widget, + GdkWindow *window, + const cairo_region_t *region); + + /* inline getters */ static inline gboolean