OSDN Git Service

Add Bluray support
[handbrake-jp/handbrake-jp-git.git] / gtk / src / ghbcompositor.c
1 /* "Borrowed" from: */
2 /* GTK - The GIMP Toolkit
3  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 /*
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/.
26  */
27
28 #include <config.h>
29 #include <stdlib.h>
30 #include <gtk/gtk.h>
31 #include <gtk/gtkprivate.h>
32 #include <gtk/gtkmarshal.h>
33 #include "ghbcompositor.h"
34
35 enum {
36     PROP_0,
37 };
38
39 enum {
40     CHILD_PROP_0,
41     CHILD_PROP_Z_POS,
42     CHILD_PROP_OPACITY
43 };
44
45 #define GHB_COMPOSITOR_GET_PRIVATE(obj)  G_TYPE_INSTANCE_GET_PRIVATE((obj), GHB_TYPE_COMPOSITOR, GhbCompositorPrivate)
46
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,
57                                              guint            prop_id,
58                                              const GValue    *value,
59                                              GParamSpec      *pspec);
60 static void     ghb_compositor_get_property  (GObject        *object,
61                                              guint            prop_id,
62                                              GValue          *value,
63                                              GParamSpec      *pspec);
64 static void     ghb_compositor_add          (GtkContainer    *container,
65                                              GtkWidget       *widget);
66 static void     ghb_compositor_remove       (GtkContainer    *container,
67                                              GtkWidget       *widget);
68 static void     ghb_compositor_forall       (GtkContainer    *container,
69                                              gboolean         include_internals,
70                                              GtkCallback      callback,
71                                              gpointer         data);
72 static GType    ghb_compositor_child_type   (GtkContainer    *container);
73 static void     ghb_compositor_set_child_property  (GtkContainer *container,
74                                              GtkWidget       *child,
75                                              guint            prop_id,
76                                              const GValue    *value,
77                                              GParamSpec      *pspec);
78 static void     ghb_compositor_get_child_property  (GtkContainer *container,
79                                              GtkWidget       *child,
80                                              guint            prop_id,
81                                              GValue          *value,
82                                              GParamSpec      *pspec);
83
84 G_DEFINE_TYPE (GhbCompositor, ghb_compositor, GTK_TYPE_BIN)
85
86 static void
87 ghb_compositor_class_init (GhbCompositorClass *class)
88 {
89     GObjectClass *gobject_class = G_OBJECT_CLASS (class);
90     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
91     GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
92
93     gobject_class->finalize = ghb_compositor_finalize;
94
95     gobject_class->set_property = ghb_compositor_set_property;
96     gobject_class->get_property = ghb_compositor_get_property;
97
98     widget_class->size_request = ghb_compositor_size_request;
99     widget_class->size_allocate = ghb_compositor_size_allocate;
100
101     widget_class->realize = ghb_compositor_realize;
102     widget_class->unrealize = ghb_compositor_unrealize;
103
104     widget_class->expose_event = ghb_compositor_expose;
105
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;
112
113     gtk_container_class_install_child_property (container_class,
114                         CHILD_PROP_Z_POS,
115                         g_param_spec_uint ("z-pos",
116                             "Position in Z-List",
117                             "Sets the blending order of the child.",
118                             0, 65535, 0,
119                             GTK_PARAM_READWRITE));
120
121     gtk_container_class_install_child_property (container_class,
122                         CHILD_PROP_OPACITY,
123                         g_param_spec_double ("opacity",
124                             "Opacity",
125                             "Sets the opacity of the child.",
126                             0.0, 1.0, 1.0,
127                             GTK_PARAM_READWRITE));
128
129 }
130
131 static GType
132 ghb_compositor_child_type(GtkContainer *container)
133 {
134     return GTK_TYPE_WIDGET;
135 }
136
137 static void 
138 ghb_compositor_get_property (
139     GObject    *object,
140     guint       prop_id,
141     GValue     *value,
142     GParamSpec *pspec)
143 {
144     GhbCompositor *compositor;
145
146     compositor = GHB_COMPOSITOR (object);
147
148     switch (prop_id)
149     {
150     default:
151         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
152         break;
153     }
154 }
155
156 static void 
157 ghb_compositor_set_property (
158     GObject      *object,
159     guint         prop_id,
160     const GValue *value,
161     GParamSpec   *pspec)
162 {
163     GhbCompositor *compositor;
164
165     compositor = GHB_COMPOSITOR (object);
166
167     switch (prop_id)
168     {
169     default:
170         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
171         break;
172     }
173 }
174
175 static gint
176 zsort(gconstpointer a, gconstpointer b)
177 {
178     GhbCompositorChild *cca, *ccb;
179
180     cca = (GhbCompositorChild*)a;
181     ccb = (GhbCompositorChild*)b;
182
183     return (cca->z_pos - ccb->z_pos);
184 }
185
186 static void 
187 ghb_compositor_set_child_property(
188     GtkContainer *container,
189     GtkWidget    *child,
190     guint         prop_id,
191     const GValue *value,
192     GParamSpec   *pspec)
193 {
194     GhbCompositor *compositor;
195     GhbCompositorChild *cc;
196     GList *link;
197
198     compositor = GHB_COMPOSITOR(container);
199
200     for (link = compositor->children; link != NULL; link = link->next)
201     {
202         cc = (GhbCompositorChild*)link->data;
203         if (cc->widget == child)
204             break;
205     }
206     if (link == NULL)
207     {
208         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec);
209         return;
210     }
211
212     switch (prop_id)
213     {
214     case CHILD_PROP_Z_POS:
215     {
216         cc->z_pos = g_value_get_uint(value);
217         compositor->children = g_list_sort(compositor->children, zsort);
218     } break;
219     case CHILD_PROP_OPACITY:
220     {
221         cc->opacity = g_value_get_double(value);
222     } break;
223     default:
224         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec);
225         break;
226     }
227
228     if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (compositor))
229         gtk_widget_queue_resize (child);
230
231 }
232
233 static void 
234 ghb_compositor_get_child_property(
235     GtkContainer *container,
236     GtkWidget    *child,
237     guint         prop_id,
238     GValue       *value,
239     GParamSpec   *pspec)
240 {
241     GhbCompositor *compositor;
242     GhbCompositorChild *cc;
243     GList *link;
244
245     compositor = GHB_COMPOSITOR(container);
246
247     for (link = compositor->children; link != NULL; link = link->next)
248     {
249         cc = (GhbCompositorChild*)link->data;
250         if (cc->widget == child)
251             break;
252     }
253     if (link == NULL)
254     {
255         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec);
256         return;
257     }
258
259     switch (prop_id)
260     {
261     case CHILD_PROP_Z_POS:
262     {
263         g_value_set_uint(value, cc->z_pos);
264     } break;
265     case CHILD_PROP_OPACITY:
266     {
267         g_value_set_double(value, cc->opacity);
268     } break;
269     default:
270         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec);
271         break;
272     }
273 }
274
275 static void
276 ghb_compositor_init (GhbCompositor *compositor)
277 {
278     GTK_WIDGET_UNSET_FLAGS (compositor, GTK_NO_WINDOW);
279 }
280
281 GtkWidget*
282 ghb_compositor_new (void)
283 {
284     return GTK_WIDGET(g_object_new (GHB_TYPE_COMPOSITOR, NULL));
285 }
286
287 #if 0
288 static void
289 showtype(const gchar *msg, GtkWidget *widget)
290 {
291     GType type;
292     gchar *str;
293
294     type = GTK_WIDGET_TYPE(widget);
295     if (type == GTK_TYPE_DRAWING_AREA)
296         str = "drawing area";
297     else if (type == GTK_TYPE_ALIGNMENT)
298         str = "alignment";
299     else if (type == GTK_TYPE_EVENT_BOX)
300         str = "event box";
301     else if (type == GTK_TYPE_EVENT_BOX)
302         str = "event box";
303     else
304         str = "unknown";
305     g_message("%s: %s", msg, str);
306 }
307 #endif
308
309 static GList*
310 find_drawables(GList *drawables, GtkWidget *widget)
311 {
312     if (!GTK_WIDGET_NO_WINDOW(widget))
313     {
314         drawables = g_list_append(drawables, widget);
315         return drawables;
316     }
317     if (GTK_IS_CONTAINER(widget))
318     {
319         GList *children, *link;
320
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)
324         {
325             if (!GTK_WIDGET_NO_WINDOW(GTK_WIDGET(link->data)))
326             {
327                 drawables = g_list_append(drawables, link->data);
328             }
329             else
330             {
331                 drawables = find_drawables(drawables, GTK_WIDGET(link->data));
332             }
333         }
334     }
335     return drawables;
336 }
337
338 /**
339  * ghb_compositor_zlist_insert:
340  * @compositor: a #GhbCompositor
341  * @child: widgets to insert
342  * @z_pos: position
343  * @opacity: global opacity for this widget
344  *
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
348  * 
349  **/
350 void
351 ghb_compositor_zlist_insert (
352     GhbCompositor *compositor,
353     GtkWidget *child, 
354     gint z_pos, 
355     gdouble opacity)
356 {
357     GhbCompositorChild *cc;
358     GdkDisplay *display;
359
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);
363
364     gtk_widget_set_parent(child, GTK_WIDGET(compositor));
365
366     display = gtk_widget_get_display (GTK_WIDGET(compositor));
367
368     cc = g_new(GhbCompositorChild, 1);
369     cc->widget = child;
370     cc->z_pos = z_pos;
371     cc->opacity = opacity;
372     cc->drawables = NULL;
373     compositor->children = g_list_insert_sorted(
374                                 compositor->children, cc, zsort);
375
376     if (gdk_display_supports_composite(display))
377     {
378         GList *link;
379
380         cc->drawables = find_drawables(NULL, cc->widget);
381
382         for (link = cc->drawables; link != NULL; link = link->next)
383         {
384             gtk_widget_realize(GTK_WIDGET(link->data));
385             gdk_window_set_composited(GTK_WIDGET(link->data)->window, TRUE);
386         }
387     }
388 }
389
390 static void
391 ghb_compositor_add(GtkContainer *container, GtkWidget *child)
392 {
393     GhbCompositor *compositor = GHB_COMPOSITOR(container);
394     GhbCompositorChild *cc;
395     gint z_pos = 0;
396     GList *last = g_list_last(compositor->children);
397
398     if (last != NULL)
399     {
400         cc = (GhbCompositorChild*)last->data;
401         z_pos = cc->z_pos + 1;
402     }
403     ghb_compositor_zlist_insert(compositor, child, z_pos, 1.0);
404 }
405
406 static void
407 ghb_compositor_remove(GtkContainer *container, GtkWidget *child)
408 {
409     GhbCompositor *compositor = GHB_COMPOSITOR(container);
410     GhbCompositorChild *cc;
411     GList *link;
412
413     for (link = compositor->children; link != NULL; link = link->next)
414     {
415         cc = (GhbCompositorChild*)link->data;
416         if (cc->widget == child)
417         {
418             gboolean was_visible = GTK_WIDGET_VISIBLE( child );
419             gtk_widget_unparent(child);
420             compositor->children = g_list_remove(compositor->children, child);
421             g_free(child);
422
423             if (was_visible && GTK_WIDGET_VISIBLE (container))
424                 gtk_widget_queue_resize(GTK_WIDGET(container));
425             break;
426         }
427     }
428 }
429
430 static void
431 ghb_compositor_forall(
432     GtkContainer *container,
433     gboolean      include_internals,
434     GtkCallback   callback,
435     gpointer      data)
436 {
437     GhbCompositor *compositor = GHB_COMPOSITOR (container);
438     GhbCompositorChild *cc;
439     GList *link;
440
441     for (link = compositor->children; link != NULL; link = link->next)
442     {
443         cc = (GhbCompositorChild*)link->data;
444         (*callback)(cc->widget, data);
445     }
446 }
447
448 static void
449 ghb_compositor_finalize (GObject *object)
450 {
451     GhbCompositor *compositor = GHB_COMPOSITOR (object);
452     GhbCompositorChild *cc;
453     GList *link;
454
455     for (link = compositor->children; link != NULL; link = link->next)
456     {
457         cc = (GhbCompositorChild*)link->data;
458         g_list_free(cc->drawables);
459         g_free(cc);
460     }
461     g_list_free(compositor->children);
462     G_OBJECT_CLASS (ghb_compositor_parent_class)->finalize (object);
463 }
464
465
466 static void
467 ghb_compositor_realize (GtkWidget *widget)
468 {
469     GdkWindowAttr attributes;
470     gint attributes_mask;
471     gint border_width;
472     gboolean visible_window;
473
474     GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
475
476     border_width = GTK_CONTAINER (widget)->border_width;
477
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
487             | GDK_EXPOSURE_MASK
488             | GDK_ENTER_NOTIFY_MASK
489             | GDK_LEAVE_NOTIFY_MASK;
490
491     visible_window = !GTK_WIDGET_NO_WINDOW (widget);
492     if (visible_window)
493     {
494         attributes.visual = gtk_widget_get_visual (widget);
495         attributes.colormap = gtk_widget_get_colormap (widget);
496         attributes.wclass = GDK_INPUT_OUTPUT;
497
498         attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
499
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);
503     }
504     else
505     {
506         widget->window = gtk_widget_get_parent_window (widget);
507         g_object_ref (widget->window);
508     }
509
510     widget->style = gtk_style_attach (widget->style, widget->window);
511
512     if (visible_window)
513         gtk_style_set_background(widget->style, widget->window, 
514                                 GTK_STATE_NORMAL);
515 }
516
517 static void
518 ghb_compositor_unrealize (GtkWidget *widget)
519 {
520     GTK_WIDGET_CLASS (ghb_compositor_parent_class)->unrealize (widget);
521 }
522
523 static void
524 ghb_compositor_size_request(
525     GtkWidget      *widget,
526     GtkRequisition *requisition)
527 {
528     GhbCompositor *compositor = GHB_COMPOSITOR (widget);
529     GList *link;
530     GhbCompositorChild *cc;
531     gint width = 0, height = 0;
532     GtkRequisition child_requisition;
533
534     for (link = compositor->children; link != NULL; link = link->next)
535     {
536         cc = (GhbCompositorChild*)link->data;
537         if (GTK_WIDGET_VISIBLE(cc->widget))
538         {
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);
543         }
544     }
545
546     requisition->width = width + GTK_CONTAINER (widget)->border_width * 2;
547     requisition->height = height + GTK_CONTAINER (widget)->border_width * 2;
548 }
549
550 static void
551 ghb_compositor_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
552 {
553     GhbCompositor *compositor;
554     GtkAllocation child_allocation;
555     GhbCompositorChild *cc;
556     GList *link;
557
558     widget->allocation = *allocation;
559     compositor = GHB_COMPOSITOR (widget);
560
561     if (GTK_WIDGET_NO_WINDOW (widget))
562     {
563         child_allocation.x = allocation->x + 
564                             GTK_CONTAINER(widget)->border_width;
565         child_allocation.y = allocation->y + 
566                             GTK_CONTAINER(widget)->border_width;
567     }
568     else
569     {
570         child_allocation.x = 0;
571         child_allocation.y = 0;
572     }
573
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);
578
579     if (GTK_WIDGET_REALIZED (widget))
580     {
581         if (!GTK_WIDGET_NO_WINDOW (widget))
582         {
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);
588         }
589     }
590     for (link = compositor->children; link != NULL; link = link->next)
591     {
592         cc = (GhbCompositorChild*)link->data;
593         if (GTK_WIDGET_REALIZED (cc->widget))
594                 gtk_widget_size_allocate (cc->widget, &child_allocation);
595     }
596 }
597
598 static void
599 ghb_compositor_blend (GtkWidget *widget, GdkEventExpose *event)
600 {
601     GhbCompositor *compositor = GHB_COMPOSITOR (widget);
602     GList *link, *draw;
603     GdkRegion *region;
604     GtkWidget *child;
605     cairo_t *cr;
606     GhbCompositorChild *cc;
607
608     if (compositor->children == NULL) return;
609     /* create a cairo context to draw to the window */
610     cr = gdk_cairo_create (widget->window);
611
612     for (link = compositor->children; link != NULL; link = link->next)
613     {
614
615         cc = (GhbCompositorChild*)link->data;
616         for (draw = cc->drawables; draw != NULL; draw = draw->next)
617         {
618             /* get our child */
619             child = GTK_WIDGET(draw->data);
620             if (!GTK_WIDGET_VISIBLE(cc->widget) || 
621                 !GTK_WIDGET_VISIBLE(child))
622                 continue;
623
624             /* the source data is the (composited) event box */
625             gdk_cairo_set_source_pixmap (cr, child->window,
626                                         child->allocation.x,
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);
632             cairo_clip (cr);
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);
637         }
638     }
639     /* we're done */
640     cairo_destroy (cr);
641 }
642
643 static gboolean
644 ghb_compositor_expose (GtkWidget *widget, GdkEventExpose *event)
645 {
646     if (GTK_WIDGET_DRAWABLE (widget))
647     {
648         if (!GTK_WIDGET_NO_WINDOW (widget))
649             ghb_compositor_blend (widget, event);
650
651         GTK_WIDGET_CLASS(
652             ghb_compositor_parent_class)->expose_event(widget, event);
653     }
654
655     return FALSE;
656 }