2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
31 #include <gtk/gtkprivate.h>
32 #include <gtk/gtkmarshal.h>
33 #include "ghbcompositor.h"
45 #define GHB_COMPOSITOR_GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE((obj), GHB_TYPE_COMPOSITOR, GhbCompositorPrivate)
47 static void ghb_compositor_finalize (GObject *object);
48 static void ghb_compositor_realize (GtkWidget *widget);
49 static void ghb_compositor_unrealize (GtkWidget *widget);
50 static void ghb_compositor_size_request (GtkWidget *widget,
51 GtkRequisition *requisition);
52 static void ghb_compositor_size_allocate (GtkWidget *widget,
53 GtkAllocation *allocation);
54 static gboolean ghb_compositor_expose (GtkWidget *widget,
55 GdkEventExpose *event);
56 static void ghb_compositor_set_property (GObject *object,
60 static void ghb_compositor_get_property (GObject *object,
64 static void ghb_compositor_add (GtkContainer *container,
66 static void ghb_compositor_remove (GtkContainer *container,
68 static void ghb_compositor_forall (GtkContainer *container,
69 gboolean include_internals,
72 static GType ghb_compositor_child_type (GtkContainer *container);
73 static void ghb_compositor_set_child_property (GtkContainer *container,
78 static void ghb_compositor_get_child_property (GtkContainer *container,
84 G_DEFINE_TYPE (GhbCompositor, ghb_compositor, GTK_TYPE_BIN)
87 ghb_compositor_class_init (GhbCompositorClass *class)
89 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
90 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
91 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
93 gobject_class->finalize = ghb_compositor_finalize;
95 gobject_class->set_property = ghb_compositor_set_property;
96 gobject_class->get_property = ghb_compositor_get_property;
98 widget_class->size_request = ghb_compositor_size_request;
99 widget_class->size_allocate = ghb_compositor_size_allocate;
101 widget_class->realize = ghb_compositor_realize;
102 widget_class->unrealize = ghb_compositor_unrealize;
104 widget_class->expose_event = ghb_compositor_expose;
106 container_class->add = ghb_compositor_add;
107 container_class->remove = ghb_compositor_remove;
108 container_class->forall = ghb_compositor_forall;
109 container_class->child_type = ghb_compositor_child_type;
110 container_class->set_child_property = ghb_compositor_set_child_property;
111 container_class->get_child_property = ghb_compositor_get_child_property;
113 gtk_container_class_install_child_property (container_class,
115 g_param_spec_uint ("z-pos",
116 "Position in Z-List",
117 "Sets the blending order of the child.",
119 GTK_PARAM_READWRITE));
121 gtk_container_class_install_child_property (container_class,
123 g_param_spec_double ("opacity",
125 "Sets the opacity of the child.",
127 GTK_PARAM_READWRITE));
132 ghb_compositor_child_type(GtkContainer *container)
134 return GTK_TYPE_WIDGET;
138 ghb_compositor_get_property (
144 GhbCompositor *compositor;
146 compositor = GHB_COMPOSITOR (object);
151 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
157 ghb_compositor_set_property (
163 GhbCompositor *compositor;
165 compositor = GHB_COMPOSITOR (object);
170 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176 zsort(gconstpointer a, gconstpointer b)
178 GhbCompositorChild *cca, *ccb;
180 cca = (GhbCompositorChild*)a;
181 ccb = (GhbCompositorChild*)b;
183 return (cca->z_pos - ccb->z_pos);
187 ghb_compositor_set_child_property(
188 GtkContainer *container,
194 GhbCompositor *compositor;
195 GhbCompositorChild *cc;
198 compositor = GHB_COMPOSITOR(container);
200 for (link = compositor->children; link != NULL; link = link->next)
202 cc = (GhbCompositorChild*)link->data;
203 if (cc->widget == child)
208 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec);
214 case CHILD_PROP_Z_POS:
216 cc->z_pos = g_value_get_uint(value);
217 compositor->children = g_list_sort(compositor->children, zsort);
219 case CHILD_PROP_OPACITY:
221 cc->opacity = g_value_get_double(value);
224 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec);
228 if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (compositor))
229 gtk_widget_queue_resize (child);
234 ghb_compositor_get_child_property(
235 GtkContainer *container,
241 GhbCompositor *compositor;
242 GhbCompositorChild *cc;
245 compositor = GHB_COMPOSITOR(container);
247 for (link = compositor->children; link != NULL; link = link->next)
249 cc = (GhbCompositorChild*)link->data;
250 if (cc->widget == child)
255 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec);
261 case CHILD_PROP_Z_POS:
263 g_value_set_uint(value, cc->z_pos);
265 case CHILD_PROP_OPACITY:
267 g_value_set_double(value, cc->opacity);
270 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec);
276 ghb_compositor_init (GhbCompositor *compositor)
278 GTK_WIDGET_UNSET_FLAGS (compositor, GTK_NO_WINDOW);
282 ghb_compositor_new (void)
284 return GTK_WIDGET(g_object_new (GHB_TYPE_COMPOSITOR, NULL));
289 showtype(const gchar *msg, GtkWidget *widget)
294 type = GTK_WIDGET_TYPE(widget);
295 if (type == GTK_TYPE_DRAWING_AREA)
296 str = "drawing area";
297 else if (type == GTK_TYPE_ALIGNMENT)
299 else if (type == GTK_TYPE_EVENT_BOX)
301 else if (type == GTK_TYPE_EVENT_BOX)
305 g_message("%s: %s", msg, str);
310 find_drawables(GList *drawables, GtkWidget *widget)
312 if (!GTK_WIDGET_NO_WINDOW(widget))
314 drawables = g_list_append(drawables, widget);
317 if (GTK_IS_CONTAINER(widget))
319 GList *children, *link;
321 children = gtk_container_get_children(GTK_CONTAINER(widget));
322 // Look for a child with a window
323 for (link = children; link != NULL; link = link->next)
325 if (!GTK_WIDGET_NO_WINDOW(GTK_WIDGET(link->data)))
327 drawables = g_list_append(drawables, link->data);
331 drawables = find_drawables(drawables, GTK_WIDGET(link->data));
339 * ghb_compositor_zlist_insert:
340 * @compositor: a #GhbCompositor
341 * @child: widgets to insert
343 * @opacity: global opacity for this widget
345 * Insert in the given position of the zlist in the compositor.
346 * All children in the zlist must have associated GdkDrawable's
347 * This means they must be GtkDrawingArea or GtkEventBox
351 ghb_compositor_zlist_insert (
352 GhbCompositor *compositor,
357 GhbCompositorChild *cc;
360 g_return_if_fail (GHB_IS_COMPOSITOR (compositor));
361 g_return_if_fail (GTK_IS_WIDGET (child));
362 g_return_if_fail (child->parent == NULL);
364 gtk_widget_set_parent(child, GTK_WIDGET(compositor));
366 display = gtk_widget_get_display (GTK_WIDGET(compositor));
368 cc = g_new(GhbCompositorChild, 1);
371 cc->opacity = opacity;
372 cc->drawables = NULL;
373 compositor->children = g_list_insert_sorted(
374 compositor->children, cc, zsort);
376 if (gdk_display_supports_composite(display))
380 cc->drawables = find_drawables(NULL, cc->widget);
382 for (link = cc->drawables; link != NULL; link = link->next)
384 gtk_widget_realize(GTK_WIDGET(link->data));
385 gdk_window_set_composited(GTK_WIDGET(link->data)->window, TRUE);
391 ghb_compositor_add(GtkContainer *container, GtkWidget *child)
393 GhbCompositor *compositor = GHB_COMPOSITOR(container);
394 GhbCompositorChild *cc;
396 GList *last = g_list_last(compositor->children);
400 cc = (GhbCompositorChild*)last->data;
401 z_pos = cc->z_pos + 1;
403 ghb_compositor_zlist_insert(compositor, child, z_pos, 1.0);
407 ghb_compositor_remove(GtkContainer *container, GtkWidget *child)
409 GhbCompositor *compositor = GHB_COMPOSITOR(container);
410 GhbCompositorChild *cc;
413 for (link = compositor->children; link != NULL; link = link->next)
415 cc = (GhbCompositorChild*)link->data;
416 if (cc->widget == child)
418 gboolean was_visible = GTK_WIDGET_VISIBLE( child );
419 gtk_widget_unparent(child);
420 compositor->children = g_list_remove(compositor->children, child);
423 if (was_visible && GTK_WIDGET_VISIBLE (container))
424 gtk_widget_queue_resize(GTK_WIDGET(container));
431 ghb_compositor_forall(
432 GtkContainer *container,
433 gboolean include_internals,
434 GtkCallback callback,
437 GhbCompositor *compositor = GHB_COMPOSITOR (container);
438 GhbCompositorChild *cc;
441 for (link = compositor->children; link != NULL; link = link->next)
443 cc = (GhbCompositorChild*)link->data;
444 (*callback)(cc->widget, data);
449 ghb_compositor_finalize (GObject *object)
451 GhbCompositor *compositor = GHB_COMPOSITOR (object);
452 GhbCompositorChild *cc;
455 for (link = compositor->children; link != NULL; link = link->next)
457 cc = (GhbCompositorChild*)link->data;
458 g_list_free(cc->drawables);
461 g_list_free(compositor->children);
462 G_OBJECT_CLASS (ghb_compositor_parent_class)->finalize (object);
467 ghb_compositor_realize (GtkWidget *widget)
469 GdkWindowAttr attributes;
470 gint attributes_mask;
472 gboolean visible_window;
474 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
476 border_width = GTK_CONTAINER (widget)->border_width;
478 attributes.x = widget->allocation.x + border_width;
479 attributes.y = widget->allocation.y + border_width;
480 attributes.width = widget->allocation.width - 2*border_width;
481 attributes.height = widget->allocation.height - 2*border_width;
482 attributes.window_type = GDK_WINDOW_CHILD;
483 attributes.event_mask = gtk_widget_get_events (widget)
484 | GDK_BUTTON_MOTION_MASK
485 | GDK_BUTTON_PRESS_MASK
486 | GDK_BUTTON_RELEASE_MASK
488 | GDK_ENTER_NOTIFY_MASK
489 | GDK_LEAVE_NOTIFY_MASK;
491 visible_window = !GTK_WIDGET_NO_WINDOW (widget);
494 attributes.visual = gtk_widget_get_visual (widget);
495 attributes.colormap = gtk_widget_get_colormap (widget);
496 attributes.wclass = GDK_INPUT_OUTPUT;
498 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
500 widget->window = gdk_window_new(gtk_widget_get_parent_window (widget),
501 &attributes, attributes_mask);
502 gdk_window_set_user_data (widget->window, widget);
506 widget->window = gtk_widget_get_parent_window (widget);
507 g_object_ref (widget->window);
510 widget->style = gtk_style_attach (widget->style, widget->window);
513 gtk_style_set_background(widget->style, widget->window,
518 ghb_compositor_unrealize (GtkWidget *widget)
520 GTK_WIDGET_CLASS (ghb_compositor_parent_class)->unrealize (widget);
524 ghb_compositor_size_request(
526 GtkRequisition *requisition)
528 GhbCompositor *compositor = GHB_COMPOSITOR (widget);
530 GhbCompositorChild *cc;
531 gint width = 0, height = 0;
532 GtkRequisition child_requisition;
534 for (link = compositor->children; link != NULL; link = link->next)
536 cc = (GhbCompositorChild*)link->data;
537 if (GTK_WIDGET_VISIBLE(cc->widget))
539 gtk_widget_size_request(cc->widget, NULL);
540 gtk_widget_get_child_requisition(cc->widget, &child_requisition);
541 width = MAX(child_requisition.width, width);
542 height = MAX(child_requisition.height, height);
546 requisition->width = width + GTK_CONTAINER (widget)->border_width * 2;
547 requisition->height = height + GTK_CONTAINER (widget)->border_width * 2;
551 ghb_compositor_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
553 GhbCompositor *compositor;
554 GtkAllocation child_allocation;
555 GhbCompositorChild *cc;
558 widget->allocation = *allocation;
559 compositor = GHB_COMPOSITOR (widget);
561 if (GTK_WIDGET_NO_WINDOW (widget))
563 child_allocation.x = allocation->x +
564 GTK_CONTAINER(widget)->border_width;
565 child_allocation.y = allocation->y +
566 GTK_CONTAINER(widget)->border_width;
570 child_allocation.x = 0;
571 child_allocation.y = 0;
574 child_allocation.width = MAX (allocation->width -
575 GTK_CONTAINER (widget)->border_width * 2, 0);
576 child_allocation.height = MAX (allocation->height -
577 GTK_CONTAINER (widget)->border_width * 2, 0);
579 if (GTK_WIDGET_REALIZED (widget))
581 if (!GTK_WIDGET_NO_WINDOW (widget))
583 gdk_window_move_resize (widget->window,
584 allocation->x + GTK_CONTAINER (widget)->border_width,
585 allocation->y + GTK_CONTAINER (widget)->border_width,
586 child_allocation.width,
587 child_allocation.height);
590 for (link = compositor->children; link != NULL; link = link->next)
592 cc = (GhbCompositorChild*)link->data;
593 if (GTK_WIDGET_REALIZED (cc->widget))
594 gtk_widget_size_allocate (cc->widget, &child_allocation);
599 ghb_compositor_blend (GtkWidget *widget, GdkEventExpose *event)
601 GhbCompositor *compositor = GHB_COMPOSITOR (widget);
606 GhbCompositorChild *cc;
608 if (compositor->children == NULL) return;
609 /* create a cairo context to draw to the window */
610 cr = gdk_cairo_create (widget->window);
612 for (link = compositor->children; link != NULL; link = link->next)
615 cc = (GhbCompositorChild*)link->data;
616 for (draw = cc->drawables; draw != NULL; draw = draw->next)
619 child = GTK_WIDGET(draw->data);
620 if (!GTK_WIDGET_VISIBLE(cc->widget) ||
621 !GTK_WIDGET_VISIBLE(child))
624 /* the source data is the (composited) event box */
625 gdk_cairo_set_source_pixmap (cr, child->window,
627 child->allocation.y);
628 /* draw no more than our expose event intersects our child */
629 region = gdk_region_rectangle (&child->allocation);
630 gdk_region_intersect (region, event->region);
631 gdk_cairo_region (cr, region);
633 /* composite, with an opacity */
634 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
635 cairo_paint_with_alpha (cr, cc->opacity);
636 cairo_reset_clip(cr);
644 ghb_compositor_expose (GtkWidget *widget, GdkEventExpose *event)
646 if (GTK_WIDGET_DRAWABLE (widget))
648 if (!GTK_WIDGET_NO_WINDOW (widget))
649 ghb_compositor_blend (widget, event);
652 ghb_compositor_parent_class)->expose_event(widget, event);