[gedit] Implement compositing support for GeditOverlay



commit 63f13103ea314499aa6f753dccb83bede2c9f1e9
Author: Jesse van den Kieboom <jessevdk gnome org>
Date:   Sat Apr 9 14:08:48 2011 +0200

    Implement compositing support for GeditOverlay
    
    https://bugzilla.gnome.org/show_bug.cgi?id=642091

 gedit/gedit-overlay-child.c |   37 +++++++-
 gedit/gedit-overlay.c       |  240 +++++++++++++++++++++++++++++++++++++++---
 gedit/gedit-overlay.h       |    3 +
 gedit/gedit-rounded-frame.c |    2 +-
 gedit/gedit-view-frame.c    |   17 +++
 5 files changed, 279 insertions(+), 20 deletions(-)
---
diff --git a/gedit/gedit-overlay-child.c b/gedit/gedit-overlay-child.c
index e30d6ed..a4b4769 100644
--- a/gedit/gedit-overlay-child.c
+++ b/gedit/gedit-overlay-child.c
@@ -97,19 +97,30 @@ gedit_overlay_child_realize (GtkWidget *widget)
 	GdkWindow *parent_window;
 	GdkWindow *window;
 	GtkStyleContext *context;
+	GdkScreen *screen;
+	GdkVisual *visual;
 
 	gtk_widget_set_realized (widget, TRUE);
 
 	parent_window = gtk_widget_get_parent_window (widget);
 	context = gtk_widget_get_style_context (widget);
 
+	screen = gtk_widget_get_screen (gtk_widget_get_parent (widget));
+	visual = gdk_screen_get_rgba_visual (screen);
+
+	if (visual == NULL)
+	{
+		visual = gdk_screen_get_system_visual (screen);
+	}
+
 	attributes.window_type = GDK_WINDOW_CHILD;
 	attributes.wclass = GDK_INPUT_OUTPUT;
 	attributes.event_mask = GDK_EXPOSURE_MASK;
 	attributes.width = 0;
 	attributes.height = 0;
+	attributes.visual = visual;
 
-	window = gdk_window_new (parent_window, &attributes, 0);
+	window = gdk_window_new (parent_window, &attributes, GDK_WA_VISUAL);
 	gdk_window_set_user_data (window, widget);
 	gtk_widget_set_window (widget, window);
 	gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL);
@@ -201,6 +212,29 @@ gedit_overlay_child_remove (GtkContainer *container,
 }
 
 static void
+gedit_overlay_child_screen_changed (GtkWidget *widget,
+                                    GdkScreen *prev)
+{
+	GdkScreen *screen;
+	GdkVisual *visual;
+
+	if (GTK_WIDGET_CLASS (gedit_overlay_child_parent_class)->screen_changed)
+	{
+		GTK_WIDGET_CLASS (gedit_overlay_child_parent_class)->screen_changed (widget, prev);
+	}
+
+	screen = gtk_widget_get_screen (widget);
+	visual = gdk_screen_get_rgba_visual (screen);
+
+	if (visual == NULL)
+	{
+		visual = gdk_screen_get_system_visual (screen);
+	}
+
+	gtk_widget_set_visual (widget, visual);
+}
+
+static void
 gedit_overlay_child_class_init (GeditOverlayChildClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -214,6 +248,7 @@ gedit_overlay_child_class_init (GeditOverlayChildClass *klass)
 	widget_class->get_preferred_width = gedit_overlay_child_get_preferred_width;
 	widget_class->get_preferred_height = gedit_overlay_child_get_preferred_height;
 	widget_class->size_allocate = gedit_overlay_child_size_allocate;
+	widget_class->screen_changed = gedit_overlay_child_screen_changed;
 
 	container_class->add = gedit_overlay_child_add;
 	container_class->remove = gedit_overlay_child_remove;
diff --git a/gedit/gedit-overlay.c b/gedit/gedit-overlay.c
index 530e602..2a60f68 100644
--- a/gedit/gedit-overlay.c
+++ b/gedit/gedit-overlay.c
@@ -31,18 +31,45 @@ struct _GeditOverlayPrivate
 	GtkWidget *main_widget;
 	GtkWidget *relative_widget;
 	GSList    *children;
+
+	guint composited : 1;
 };
 
 enum
 {
 	PROP_0,
 	PROP_MAIN_WIDGET,
-	PROP_RELATIVE_WIDGET
+	PROP_RELATIVE_WIDGET,
+	PROP_COMPOSITED
 };
 
 G_DEFINE_TYPE (GeditOverlay, gedit_overlay, GTK_TYPE_CONTAINER)
 
 static void
+enable_compositing (GeditOverlay *overlay,
+                    GtkWidget    *child,
+                    gboolean      enable)
+{
+	GdkWindow *window;
+	GdkWindow *mywindow;
+
+	mywindow = gtk_widget_get_window (GTK_WIDGET (overlay));
+	window = gtk_widget_get_window (child);
+
+	if (window != NULL && window != mywindow)
+	{
+		gdk_window_set_composited (window, enable);
+	}
+}
+
+static void
+on_child_realized (GtkWidget    *child,
+                   GeditOverlay *overlay)
+{
+	enable_compositing (overlay, child, overlay->priv->composited);
+}
+
+static void
 add_toplevel_widget (GeditOverlay *overlay,
                      GtkWidget    *child)
 {
@@ -50,6 +77,13 @@ add_toplevel_widget (GeditOverlay *overlay,
 
 	overlay->priv->children = g_slist_append (overlay->priv->children,
 	                                          child);
+
+	enable_compositing (overlay, child, overlay->priv->composited);
+
+	g_signal_connect_after (child,
+	                        "realize",
+	                        G_CALLBACK (on_child_realized),
+	                        overlay);
 }
 
 static void
@@ -59,6 +93,30 @@ gedit_overlay_dispose (GObject *object)
 }
 
 static void
+set_enable_compositing (GeditOverlay *overlay,
+                        gboolean      enabled)
+{
+	GSList *item;
+
+	if (overlay->priv->composited == enabled)
+	{
+		return;
+	}
+
+	overlay->priv->composited = enabled;
+
+	/* Enable/disable compositing on all the children */
+	for (item = overlay->priv->children; item; item = g_slist_next (item))
+	{
+		GtkWidget *child = item->data;
+
+		enable_compositing (overlay, child, enabled);
+	}
+
+	g_object_notify (G_OBJECT (overlay), "composited");
+}
+
+static void
 gedit_overlay_get_property (GObject    *object,
                             guint       prop_id,
                             GValue     *value,
@@ -77,6 +135,10 @@ gedit_overlay_get_property (GObject    *object,
 			g_value_set_object (value, priv->relative_widget);
 			break;
 
+		case PROP_COMPOSITED:
+			g_value_set_boolean (value, priv->composited);
+			break;
+
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 			break;
@@ -84,6 +146,51 @@ gedit_overlay_get_property (GObject    *object,
 }
 
 static void
+set_transparent_background_color (GtkWidget *widget)
+{
+	GtkStyleContext *context;
+	GdkRGBA bg_color;
+
+	context = gtk_widget_get_style_context (widget);
+	gtk_style_context_get_background_color (context,
+	                                        GTK_STATE_NORMAL,
+	                                        &bg_color);
+
+	bg_color.alpha = 0;
+
+	gtk_widget_override_background_color (widget,
+	                                      GTK_STATE_FLAG_NORMAL,
+	                                      &bg_color);
+}
+
+static GtkWidget *
+wrap_child_if_needed (GtkWidget *widget,
+                      gboolean   make_transparent)
+{
+	GtkWidget *child;
+
+	if (GEDIT_IS_OVERLAY_CHILD (widget))
+	{
+		return widget;
+	}
+
+	child = GTK_WIDGET (gedit_overlay_child_new (widget));
+	gtk_widget_show (child);
+
+	if (make_transparent)
+	{
+		set_transparent_background_color (child);
+	}
+
+	g_signal_connect_swapped (widget,
+	                          "destroy",
+	                          G_CALLBACK (gtk_widget_destroy),
+	                          child);
+
+	return child;
+}
+
+static void
 gedit_overlay_set_property (GObject      *object,
                             guint         prop_id,
                             const GValue *value,
@@ -95,14 +202,23 @@ gedit_overlay_set_property (GObject      *object,
 	switch (prop_id)
 	{
 		case PROP_MAIN_WIDGET:
-			priv->main_widget = g_value_get_object (value);
-			add_toplevel_widget (overlay, priv->main_widget);
-			break;
+		{
+			priv->main_widget = wrap_child_if_needed (g_value_get_object (value),
+			                                          FALSE);
 
+			add_toplevel_widget (overlay,
+			                     priv->main_widget);
+			break;
+		}
 		case PROP_RELATIVE_WIDGET:
 			priv->relative_widget = g_value_get_object (value);
 			break;
 
+		case PROP_COMPOSITED:
+			set_enable_compositing (overlay,
+			                        g_value_get_boolean (value));
+			break;
+
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 			break;
@@ -300,20 +416,8 @@ overlay_add (GtkContainer *overlay,
 
 	if (child == NULL)
 	{
-		if (GEDIT_IS_OVERLAY_CHILD (widget))
-		{
-			child = GEDIT_OVERLAY_CHILD (widget);
-		}
-		else
-		{
-			child = gedit_overlay_child_new (widget);
-			gtk_widget_show (GTK_WIDGET (child));
-
-			g_signal_connect_swapped (widget, "destroy",
-			                          G_CALLBACK (gtk_widget_destroy), child);
-		}
-
-		add_toplevel_widget (GEDIT_OVERLAY (overlay), GTK_WIDGET (child));
+		add_toplevel_widget (GEDIT_OVERLAY (overlay),
+		                     wrap_child_if_needed (widget, TRUE));
 	}
 }
 
@@ -330,6 +434,10 @@ gedit_overlay_remove (GtkContainer *overlay,
 
 		if (child == widget)
 		{
+			g_signal_handlers_disconnect_by_func (child,
+			                                      on_child_realized,
+			                                      overlay);
+
 			gtk_widget_unparent (widget);
 			priv->children = g_slist_remove_link (priv->children,
 			                                      l);
@@ -365,6 +473,81 @@ gedit_overlay_child_type (GtkContainer *overlay)
 	return GTK_TYPE_WIDGET;
 }
 
+static gboolean
+gedit_overlay_draw (GtkWidget *widget,
+                    cairo_t   *cr)
+{
+	GeditOverlay *overlay;
+	GSList *item;
+	GdkWindow *mywindow;
+	GdkRectangle cliprect;
+	gboolean isclipped;
+
+	GTK_WIDGET_CLASS (gedit_overlay_parent_class)->draw (widget, cr);
+
+	overlay = GEDIT_OVERLAY (widget);
+
+	/* Draw composited children if necessary */
+	if (!overlay->priv->composited ||
+	    !gdk_display_supports_composite (gtk_widget_get_display (widget)))
+	{
+		return FALSE;
+	}
+
+	mywindow = gtk_widget_get_window (widget);
+	isclipped = gdk_cairo_get_clip_rectangle (cr, &cliprect);
+
+	cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+	for (item = overlay->priv->children; item; item = g_slist_next (item))
+	{
+		GtkWidget *child = item->data;
+		GdkWindow *window;
+		GtkAllocation allocation;
+		GdkRectangle childrect;
+		GdkRectangle cliparea;
+
+		window = gtk_widget_get_window (child);
+
+		if (window == NULL || window == mywindow)
+		{
+			continue;
+		}
+
+		gtk_widget_get_allocation (child, &allocation);
+
+		childrect.x = allocation.x;
+		childrect.y = allocation.y;
+		childrect.width = allocation.width;
+		childrect.height = allocation.height;
+
+		if (isclipped)
+		{
+			gdk_rectangle_intersect (&cliprect,
+			                         &childrect,
+			                         &cliparea);
+		}
+		else
+		{
+			cliparea = childrect;
+		}
+
+		cairo_save (cr);
+
+		gdk_cairo_rectangle (cr, &cliparea);
+		cairo_clip (cr);
+
+		gdk_cairo_set_source_window (cr,
+		                             window,
+		                             allocation.x,
+		                             allocation.y);
+
+		cairo_paint (cr);
+		cairo_restore (cr);
+	}
+
+	return FALSE;
+}
 
 static void
 gedit_overlay_class_init (GeditOverlayClass *klass)
@@ -381,6 +564,7 @@ gedit_overlay_class_init (GeditOverlayClass *klass)
 	widget_class->get_preferred_width = gedit_overlay_get_preferred_width;
 	widget_class->get_preferred_height = gedit_overlay_get_preferred_height;
 	widget_class->size_allocate = gedit_overlay_size_allocate;
+	widget_class->draw = gedit_overlay_draw;
 
 	container_class->add = overlay_add;
 	container_class->remove = gedit_overlay_remove;
@@ -404,6 +588,15 @@ gedit_overlay_class_init (GeditOverlayClass *klass)
 	                                                      G_PARAM_READWRITE |
 	                                                      G_PARAM_STATIC_STRINGS));
 
+	g_object_class_install_property (object_class,
+	                                 PROP_COMPOSITED,
+	                                 g_param_spec_boolean ("composited",
+	                                                       "Composited",
+	                                                       "Whether the overlay composites its children",
+	                                                       FALSE,
+	                                                       G_PARAM_READWRITE |
+	                                                       G_PARAM_STATIC_STRINGS));
+
 	g_type_class_add_private (object_class, sizeof (GeditOverlayPrivate));
 }
 
@@ -411,6 +604,8 @@ static void
 gedit_overlay_init (GeditOverlay *overlay)
 {
 	overlay->priv = GEDIT_OVERLAY_GET_PRIVATE (overlay);
+
+	gtk_widget_set_app_paintable (GTK_WIDGET (overlay), TRUE);
 }
 
 /**
@@ -465,3 +660,12 @@ gedit_overlay_add (GeditOverlay             *overlay,
 	gedit_overlay_child_set_position (child, position);
 	gedit_overlay_child_set_offset (child, offset);
 }
+
+void
+gedit_overlay_set_composited (GeditOverlay *overlay,
+                              gboolean      enabled)
+{
+	g_return_if_fail (GEDIT_IS_OVERLAY (overlay));
+
+	set_enable_compositing (overlay, enabled);
+}
diff --git a/gedit/gedit-overlay.h b/gedit/gedit-overlay.h
index 9e1c769..224c3ee 100644
--- a/gedit/gedit-overlay.h
+++ b/gedit/gedit-overlay.h
@@ -62,6 +62,9 @@ void		 gedit_overlay_add			(GeditOverlay             *overlay,
 							 GeditOverlayChildPosition position,
 							 guint                     offset);
 
+void             gedit_overlay_set_composited           (GeditOverlay             *overlay,
+                                                         gboolean                  enabled);
+
 G_END_DECLS
 
 #endif /* __GEDIT_OVERLAY_H__ */
diff --git a/gedit/gedit-rounded-frame.c b/gedit/gedit-rounded-frame.c
index ae84593..5fa5479 100644
--- a/gedit/gedit-rounded-frame.c
+++ b/gedit/gedit-rounded-frame.c
@@ -242,7 +242,7 @@ gedit_rounded_frame_init (GeditRoundedFrame *frame)
 	frame->priv->frame_width = 3; /* Make it a prop */
 
 	gtk_widget_set_has_window (GTK_WIDGET (frame), FALSE);
-	gtk_widget_set_app_paintable (GTK_WIDGET (frame), FALSE);
+	gtk_widget_set_app_paintable (GTK_WIDGET (frame), TRUE);
 }
 
 GtkWidget *
diff --git a/gedit/gedit-view-frame.c b/gedit/gedit-view-frame.c
index d881bc9..4a51609 100644
--- a/gedit/gedit-view-frame.c
+++ b/gedit/gedit-view-frame.c
@@ -1090,6 +1090,7 @@ create_search_widget (GeditViewFrame *frame)
 
 	hbox = gtk_hbox_new (FALSE, 3);
 	gtk_widget_show (hbox);
+
 	gtk_container_add (GTK_CONTAINER (search_widget), hbox);
 	gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);
 
@@ -1417,6 +1418,8 @@ gedit_view_frame_init (GeditViewFrame *frame)
 	GeditDocument *doc;
 	GtkWidget *sw;
 	GeditOverlayChildPosition position;
+	GtkStyleContext *context;
+	GdkRGBA bg_color;
 
 	frame->priv = GEDIT_VIEW_FRAME_GET_PRIVATE (frame);
 
@@ -1448,6 +1451,8 @@ gedit_view_frame_init (GeditViewFrame *frame)
 	gtk_widget_show (sw);
 
 	frame->priv->overlay = gedit_animated_overlay_new (sw, frame->priv->view);
+
+	gedit_overlay_set_composited (GEDIT_OVERLAY (frame->priv->overlay), TRUE);
 	gtk_widget_show (frame->priv->overlay);
 
 	gtk_box_pack_start (GTK_BOX (frame), frame->priv->overlay, TRUE, TRUE, 0);
@@ -1472,6 +1477,18 @@ gedit_view_frame_init (GeditViewFrame *frame)
 	              "orientation", GTK_ORIENTATION_VERTICAL,
 	              NULL);
 
+	/* Force search widget slider to be transparent */
+	context = gtk_widget_get_style_context (frame->priv->slider);
+	gtk_style_context_get_background_color (context,
+	                                        GTK_STATE_NORMAL,
+	                                        &bg_color);
+
+	bg_color.alpha = 0;
+
+	gtk_widget_override_background_color (frame->priv->slider,
+	                                      GTK_STATE_NORMAL,
+	                                      &bg_color);
+
 	gedit_animated_overlay_add (GEDIT_ANIMATED_OVERLAY (frame->priv->overlay),
 	                            GEDIT_ANIMATABLE (frame->priv->slider));
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]