diff options
author | jstebbins <[email protected]> | 2009-04-08 17:26:10 +0000 |
---|---|---|
committer | jstebbins <[email protected]> | 2009-04-08 17:26:10 +0000 |
commit | 16159cf96511adeda529ecc555d482454371eba5 (patch) | |
tree | 13aa74719cf6f7d1ad0753e1e931147ae73726a0 | |
parent | 637b5bf7561e4256015c5371e26f3488797766ad (diff) |
LinGui: create custom widget that manages multiple overlay layers
composites the layers using per-pixel and global alpha values
the preview hud now uses this.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2312 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r-- | gtk/src/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/src/composite_example.c | 78 | ||||
-rw-r--r-- | gtk/src/ghb.ui | 404 | ||||
-rw-r--r-- | gtk/src/ghbcompositor.c | 657 | ||||
-rw-r--r-- | gtk/src/ghbcompositor.h | 74 | ||||
-rw-r--r-- | gtk/src/main.c | 53 | ||||
-rw-r--r-- | gtk/src/preview.c | 2 |
7 files changed, 1029 insertions, 241 deletions
diff --git a/gtk/src/Makefile.am b/gtk/src/Makefile.am index 04cebe2a6..8abcc6f97 100644 --- a/gtk/src/Makefile.am +++ b/gtk/src/Makefile.am @@ -110,6 +110,8 @@ ghb_SOURCES = \ renderer_button.c \ ghbcellrenderertext.c \ ghbcellrenderertext.h \ + ghbcompositor.c \ + ghbcompositor.h \ ghb-dvd.c \ ghb-dvd.h \ marshalers.c \ diff --git a/gtk/src/composite_example.c b/gtk/src/composite_example.c new file mode 100644 index 000000000..7918b3083 --- /dev/null +++ b/gtk/src/composite_example.c @@ -0,0 +1,78 @@ +#include <gtk/gtk.h> +#include "ghbcompositor.h" + +// GhbCompositor example +int +main(gint argc, gchar *argv[]) +{ + GtkWidget *window; + GtkWidget *blender; + GtkWidget *eb_bottom; + GtkWidget *eb_top1; + GtkWidget *eb_top2; + GtkWidget *eb_top3; + GtkWidget *bottom; + GtkWidget *top1; + GtkWidget *top2; + GtkWidget *top3; + GtkWidget *table; + GtkWidget *image; + + gtk_init(&argc, &argv); + + // Make the top level window + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + // Only widgets that have a GdkDrawing area can be composited + // These would be GtkEventBox or GtkDrawingArea + // Create the widgets that will be composited + eb_bottom = gtk_event_box_new(); + eb_top1 = gtk_event_box_new(); + eb_top2 = gtk_event_box_new(); + eb_top3 = gtk_event_box_new(); + + // Create the compositor + blender = ghb_compositor_new(); + + // Create an button to put on the bottom layer + bottom = gtk_button_new_with_label("Bottom"); + image = gtk_image_new_from_stock("gtk-help", 6); + gtk_button_set_image(GTK_BUTTON(bottom), image); + + // The button must be placed inside an event box since + // buttons do not have their own window. + gtk_container_add(GTK_CONTAINER(eb_bottom), bottom); + + // Create the buttons that will be visible on the top layer + top1 = gtk_button_new_with_label("Top 1"); + top2 = gtk_button_new_with_label("Top 2"); + top3 = gtk_button_new_with_label("Top 3"); + + // The buttons must be placed inside an event box since + // buttons do not have their own window. + gtk_container_add(GTK_CONTAINER(eb_top1), top1); + gtk_container_add(GTK_CONTAINER(eb_top2), top2); + gtk_container_add(GTK_CONTAINER(eb_top3), top3); + + // Create the table that will be the top layer + // Using a layout widget gives flexibility in the layout of the layer + table = gtk_table_new(3, 3, TRUE); + gtk_table_attach(GTK_TABLE(table), eb_top1, 0, 1, 0, 1, 0, 0, 0, 0); + gtk_table_attach(GTK_TABLE(table), eb_top2, 1, 2, 1, 2, 0, 0, 0, 0); + gtk_table_attach(GTK_TABLE(table), eb_top3, 2, 3, 2, 3, 0, 0, 0, 0); + + // Add the blender to the main window. + gtk_container_add(GTK_CONTAINER(window), blender); + + // Set the blenders zlist, with opacity values + // Bottom layer is opaque, top layer 60% + ghb_compositor_zlist_insert(GHB_COMPOSITOR(blender), eb_bottom, 1, 1); + ghb_compositor_zlist_insert(GHB_COMPOSITOR(blender), table, 2, 0.6); + + // Start the show + gtk_widget_show_all(window); + + gtk_main(); + return 0; +} + diff --git a/gtk/src/ghb.ui b/gtk/src/ghb.ui index ccee23c6e..937c8773f 100644 --- a/gtk/src/ghb.ui +++ b/gtk/src/ghb.ui @@ -4851,240 +4851,228 @@ location as the movie.</property> </child> </object> - <object class="GtkWindow" id="preview_window"> - <property name="title" translatable="yes">Preview</property> - <property name="window_position">GTK_WIN_POS_CENTER</property> - <property name="skip_taskbar_hint">True</property> - <property name="skip_pager_hint">True</property> - <property name="resizable">False</property> - <property name="events">GDK_STRUCTURE_MASK | GDK_POINTER_MOTION_MASK</property> - <signal handler="preview_configure_cb" name="configure-event"/> - <signal handler="preview_window_delete_cb" name="delete_event"/> + <object class="GtkDrawingArea" id="preview_image"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK</property> + <property name="app_paintable">True</property> + <signal name="motion-notify-event" handler="preview_motion_cb"/> + <signal name="leave-notify-event" handler="preview_leave_cb"/> + </object> + + <object class="GtkAlignment" id="preview_hud"> + <property name="visible">False</property> + <property name="xalign">.5</property> + <property name="yalign">.9</property> + <property name="xscale">0</property> + <property name="yscale">0</property> <child> - <object class="GtkAlignment" id="alignment111"> + <object class="GtkEventBox" id="preview_event_box"> <property name="visible">True</property> - <property name="xalign">.5</property> - <property name="yalign">.5</property> - <property name="xscale">0</property> - <property name="yscale">0</property> + <property name="width-request">500</property> + <property name="app-paintable">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK</property> + <signal name="enter-notify-event" handler="hud_enter_cb"/> <child> - <object class="GtkTable" id="table111"> + <object class="GtkAlignment" id="alignment53"> <property name="visible">True</property> - <property name="n_rows">1</property> - <property name="n_columns">1</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="left_padding">10</property> + <property name="right_padding">10</property> + <property name="top_padding">5</property> + <property name="bottom_padding">5</property> <child> - <object class="GtkDrawingArea" id="preview_image"> + <object class="GtkVBox" id="vbox35"> <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK</property> - <property name="app_paintable">True</property> - <signal name="motion-notify-event" handler="preview_motion_cb"/> - <signal name="leave-notify-event" handler="preview_leave_cb"/> - </object> - <packing> - </packing> - </child> - <child> - <object class="GtkAlignment" id="preview_hud"> - <property name="visible">False</property> - <property name="xalign">.5</property> - <property name="yalign">.9</property> - <property name="xscale">0</property> - <property name="yscale">0</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <child> - <object class="GtkEventBox" id="preview_event_box"> + <object class="GtkHScale" id="preview_frame"> <property name="visible">True</property> - <property name="width-request">500</property> - <property name="app-paintable">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK</property> - <signal name="enter-notify-event" handler="hud_enter_cb"/> + <property name="can_focus">True</property> + <property name="adjustment">adjustment19</property> + <property name="digits">0</property> + <property name="value_pos">bottom</property> + <signal name="value_changed" handler="preview_frame_value_changed_cb"/> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox70"> + <property name="visible">True</property> + <property name="spacing">5</property> <child> - <object class="GtkAlignment" id="alignment53"> + <object class="GtkButton" id="live_preview_play"> + <property name="height_request">30</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="relief">none</property> + <signal name="clicked" handler="live_preview_start_cb"/> + <child> + <object class="GtkImage" id="live_preview_play_image"> + <property name="visible">True</property> + <property name="stock">gtk-media-play</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHScale" id="live_preview_progress"> + <property name="can_focus">True</property> + <property name="adjustment">preview_progress_adj</property> + <property name="draw_value">False</property> + <property name="value_pos">right</property> + <signal name="value_changed" handler="live_preview_seek_cb"/> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="live_progress_box"> <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="left_padding">10</property> - <property name="right_padding">10</property> - <property name="top_padding">5</property> - <property name="bottom_padding">5</property> <child> - <object class="GtkVBox" id="vbox35"> + <object class="GtkLabel" id="label71"> + <property name="height_request">1</property> + <property name="visible">True</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkProgressBar" id="live_encode_progress"> + <property name="height_request">16</property> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <child> - <object class="GtkHScale" id="preview_frame"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="adjustment">adjustment19</property> - <property name="digits">0</property> - <property name="value_pos">bottom</property> - <signal name="value_changed" handler="preview_frame_value_changed_cb"/> - </object> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkHBox" id="hbox70"> - <property name="visible">True</property> - <property name="spacing">5</property> - <child> - <object class="GtkButton" id="live_preview_play"> - <property name="height_request">30</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="relief">none</property> - <signal name="clicked" handler="live_preview_start_cb"/> - <child> - <object class="GtkImage" id="live_preview_play_image"> - <property name="visible">True</property> - <property name="stock">gtk-media-play</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkHScale" id="live_preview_progress"> - <property name="can_focus">True</property> - <property name="adjustment">preview_progress_adj</property> - <property name="draw_value">False</property> - <property name="value_pos">right</property> - <signal name="value_changed" handler="live_preview_seek_cb"/> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkVBox" id="live_progress_box"> - <property name="visible">True</property> - <child> - <object class="GtkLabel" id="label71"> - <property name="height_request">1</property> - <property name="visible">True</property> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkProgressBar" id="live_encode_progress"> - <property name="height_request">16</property> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label72"> - <property name="height_request">1</property> - <property name="visible">True</property> - </object> - <packing> - <property name="position">2</property> - </packing> - </child> - </object> - <packing> - <property name="position">2</property> - </packing> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkHBox" id="hbox26"> - <property name="visible">True</property> - <property name="spacing">10</property> - <child> - <object class="GtkHBox" id="hbox60"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <object class="GtkLabel" id="label37"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>Duration:</b></property> - <property name="use_markup">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSpinButton" id="live_duration"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="adjustment">adjustment21</property> - <property name="numeric">True</property> - <signal name="value_changed" handler="preview_duration_changed_cb"/> - </object> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkToggleButton" id="preview_fullscreen"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="tooltip-text" translatable="yes">View Fullscreen Preview</property> - <property name="label" translatable="yes">Fullscreen</property> - <signal handler="fullscreen_clicked_cb" name="clicked"/> - </object> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkButton" id="settings_button"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="tooltip-text" translatable="yes">Open Picture Settings</property> - <property name="label" translatable="yes">Settings</property> - <signal handler="picture_settings_alt2_clicked_cb" name="clicked"/> - </object> - <packing> - <property name="expand">False</property> - <property name="position">2</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">2</property> - </packing> - </child> </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label72"> + <property name="height_request">1</property> + <property name="visible">True</property> + </object> + <packing> + <property name="position">2</property> + </packing> </child> </object> + <packing> + <property name="position">2</property> + </packing> </child> </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox26"> + <property name="visible">True</property> + <property name="spacing">10</property> + <child> + <object class="GtkHBox" id="hbox60"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child> + <object class="GtkLabel" id="label37"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Duration:</b></property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="live_duration"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="adjustment">adjustment21</property> + <property name="numeric">True</property> + <signal name="value_changed" handler="preview_duration_changed_cb"/> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkToggleButton" id="preview_fullscreen"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip-text" translatable="yes">View Fullscreen Preview</property> + <property name="label" translatable="yes">Fullscreen</property> + <signal handler="fullscreen_clicked_cb" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="settings_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip-text" translatable="yes">Open Picture Settings</property> + <property name="label" translatable="yes">Settings</property> + <signal handler="picture_settings_alt2_clicked_cb" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">2</property> + </packing> </child> </object> - <packing> - </packing> </child> </object> </child> </object> </child> </object> + + <object class="GtkWindow" id="preview_window"> + <property name="title" translatable="yes">Preview</property> + <property name="window_position">GTK_WIN_POS_CENTER</property> + <property name="skip_taskbar_hint">True</property> + <property name="skip_pager_hint">True</property> + <property name="resizable">False</property> + <property name="events">GDK_STRUCTURE_MASK | GDK_POINTER_MOTION_MASK</property> + <signal handler="preview_configure_cb" name="configure-event"/> + <signal handler="preview_window_delete_cb" name="delete_event"/> + <child> + <object class="GtkAlignment" id="preview_window_alignment"> + <property name="visible">True</property> + <property name="xalign">.5</property> + <property name="yalign">.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + </object> + </child> + </object> + <object class="GtkAboutDialog" id="hb_about"> <property name="border_width">5</property> <property name="title" translatable="yes">About HandBrake</property> diff --git a/gtk/src/ghbcompositor.c b/gtk/src/ghbcompositor.c new file mode 100644 index 000000000..eec5c09af --- /dev/null +++ b/gtk/src/ghbcompositor.c @@ -0,0 +1,657 @@ +/* "Borrowed" from: */ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include <config.h> +#include <stdlib.h> +#include <gtk/gtk.h> +#include <gtk/gtkprivate.h> +#include <gtk/gtkmarshal.h> +#include "ghbcompositor.h" + +#ifdef ENABLE_NLS +#define P_(String) g_dgettext(GETTEXT_PACKAGE "-properties",String) +#else +#define P_(String) (String) +#endif + +enum { + PROP_0, +}; + +enum { + CHILD_PROP_0, + CHILD_PROP_Z_POS, + CHILD_PROP_OPACITY +}; + +#define GHB_COMPOSITOR_GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE((obj), GHB_TYPE_COMPOSITOR, GhbCompositorPrivate) + +static void ghb_compositor_finalize (GObject *object); +static void ghb_compositor_realize (GtkWidget *widget); +static void ghb_compositor_unrealize (GtkWidget *widget); +static void ghb_compositor_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void ghb_compositor_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gboolean ghb_compositor_expose (GtkWidget *widget, + GdkEventExpose *event); +static void ghb_compositor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ghb_compositor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void ghb_compositor_add (GtkContainer *container, + GtkWidget *widget); +static void ghb_compositor_remove (GtkContainer *container, + GtkWidget *widget); +static void ghb_compositor_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer data); +static GType ghb_compositor_child_type (GtkContainer *container); +static void ghb_compositor_set_child_property (GtkContainer *container, + GtkWidget *child, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ghb_compositor_get_child_property (GtkContainer *container, + GtkWidget *child, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +G_DEFINE_TYPE (GhbCompositor, ghb_compositor, GTK_TYPE_BIN) + +static void +ghb_compositor_class_init (GhbCompositorClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class); + + gobject_class->finalize = ghb_compositor_finalize; + + gobject_class->set_property = ghb_compositor_set_property; + gobject_class->get_property = ghb_compositor_get_property; + + widget_class->size_request = ghb_compositor_size_request; + widget_class->size_allocate = ghb_compositor_size_allocate; + + widget_class->realize = ghb_compositor_realize; + widget_class->unrealize = ghb_compositor_unrealize; + + widget_class->expose_event = ghb_compositor_expose; + + container_class->add = ghb_compositor_add; + container_class->remove = ghb_compositor_remove; + container_class->forall = ghb_compositor_forall; + container_class->child_type = ghb_compositor_child_type; + container_class->set_child_property = ghb_compositor_set_child_property; + container_class->get_child_property = ghb_compositor_get_child_property; + + gtk_container_class_install_child_property (container_class, + CHILD_PROP_Z_POS, + g_param_spec_uint ("z-pos", + P_("Position in Z-List"), + P_("Sets the blending order of the child."), + 0, 65535, 0, + GTK_PARAM_READWRITE)); + + gtk_container_class_install_child_property (container_class, + CHILD_PROP_OPACITY, + g_param_spec_double ("opacity", + P_("Opacity"), + P_("Sets the opacity of the child."), + 0.0, 1.0, 1.0, + GTK_PARAM_READWRITE)); + +} + +static GType +ghb_compositor_child_type(GtkContainer *container) +{ + return GTK_TYPE_WIDGET; +} + +static void +ghb_compositor_get_property ( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GhbCompositor *compositor; + + compositor = GHB_COMPOSITOR (object); + + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ghb_compositor_set_property ( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GhbCompositor *compositor; + + compositor = GHB_COMPOSITOR (object); + + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gint +zsort(gconstpointer a, gconstpointer b) +{ + GhbCompositorChild *cca, *ccb; + + cca = (GhbCompositorChild*)a; + ccb = (GhbCompositorChild*)b; + + return (cca->z_pos - ccb->z_pos); +} + +static void +ghb_compositor_set_child_property( + GtkContainer *container, + GtkWidget *child, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GhbCompositor *compositor; + GhbCompositorChild *cc; + GList *link; + + compositor = GHB_COMPOSITOR(container); + + for (link = compositor->children; link != NULL; link = link->next) + { + cc = (GhbCompositorChild*)link->data; + if (cc->widget == child) + break; + } + if (link == NULL) + { + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec); + return; + } + + switch (prop_id) + { + case CHILD_PROP_Z_POS: + { + cc->z_pos = g_value_get_uint(value); + compositor->children = g_list_sort(compositor->children, zsort); + } break; + case CHILD_PROP_OPACITY: + { + cc->opacity = g_value_get_double(value); + } break; + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec); + break; + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (compositor)) + gtk_widget_queue_resize (child); + +} + +static void +ghb_compositor_get_child_property( + GtkContainer *container, + GtkWidget *child, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GhbCompositor *compositor; + GhbCompositorChild *cc; + GList *link; + + compositor = GHB_COMPOSITOR(container); + + for (link = compositor->children; link != NULL; link = link->next) + { + cc = (GhbCompositorChild*)link->data; + if (cc->widget == child) + break; + } + if (link == NULL) + { + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec); + return; + } + + switch (prop_id) + { + case CHILD_PROP_Z_POS: + { + g_value_set_uint(value, cc->z_pos); + } break; + case CHILD_PROP_OPACITY: + { + g_value_set_double(value, cc->opacity); + } break; + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(container, prop_id, pspec); + break; + } +} + +static void +ghb_compositor_init (GhbCompositor *compositor) +{ + GTK_WIDGET_UNSET_FLAGS (compositor, GTK_NO_WINDOW); +} + +GtkWidget* +ghb_compositor_new (void) +{ + return GTK_WIDGET(g_object_new (GHB_TYPE_COMPOSITOR, NULL)); +} + +#if 0 +static void +showtype(const gchar *msg, GtkWidget *widget) +{ + GType type; + gchar *str; + + type = GTK_WIDGET_TYPE(widget); + if (type == GTK_TYPE_DRAWING_AREA) + str = "drawing area"; + else if (type == GTK_TYPE_ALIGNMENT) + str = "alignment"; + else if (type == GTK_TYPE_EVENT_BOX) + str = "event box"; + else if (type == GTK_TYPE_EVENT_BOX) + str = "event box"; + else + str = "unknown"; + g_message("%s: %s", msg, str); +} +#endif + +static GList* +find_drawables(GList *drawables, GtkWidget *widget) +{ + if (!GTK_WIDGET_NO_WINDOW(widget)) + { + drawables = g_list_append(drawables, widget); + return drawables; + } + if (GTK_IS_CONTAINER(widget)) + { + GList *children, *link; + + children = gtk_container_get_children(GTK_CONTAINER(widget)); + // Look for a child with a window + for (link = children; link != NULL; link = link->next) + { + if (!GTK_WIDGET_NO_WINDOW(GTK_WIDGET(link->data))) + { + drawables = g_list_append(drawables, link->data); + } + else + { + drawables = find_drawables(drawables, GTK_WIDGET(link->data)); + } + } + } + return drawables; +} + +/** + * ghb_compositor_zlist_insert: + * @compositor: a #GhbCompositor + * @child: widgets to insert + * @z_pos: position + * @opacity: global opacity for this widget + * + * Insert in the given position of the zlist in the compositor. + * All children in the zlist must have associated GdkDrawable's + * This means they must be GtkDrawingArea or GtkEventBox + * + **/ +void +ghb_compositor_zlist_insert ( + GhbCompositor *compositor, + GtkWidget *child, + gint z_pos, + gdouble opacity) +{ + GtkWidget *widget; + GhbCompositorChild *cc; + GdkDisplay *display; + + g_return_if_fail (GHB_IS_COMPOSITOR (compositor)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (child->parent == NULL); + + widget = GTK_WIDGET (compositor); + + cc = g_new(GhbCompositorChild, 1); + cc->widget = child; + cc->z_pos = z_pos; + cc->opacity = opacity; + compositor->children = g_list_insert_sorted( + compositor->children, cc, zsort); + + gtk_widget_set_parent(child, GTK_WIDGET(compositor)); + + display = gtk_widget_get_display (GTK_WIDGET(compositor)); + if (gdk_display_supports_composite(display)) + { + GList *link; + + cc->drawables = find_drawables(NULL, cc->widget); + + for (link = cc->drawables; link != NULL; link = link->next) + { + gtk_widget_realize(GTK_WIDGET(link->data)); + gdk_window_set_composited(GTK_WIDGET(link->data)->window, TRUE); + } + } +} + +static void +ghb_compositor_add(GtkContainer *container, GtkWidget *child) +{ + GhbCompositor *compositor = GHB_COMPOSITOR(container); + GhbCompositorChild *cc; + gint z_pos = 0; + GList *last = g_list_last(compositor->children); + + if (last != NULL) + { + cc = (GhbCompositorChild*)last->data; + z_pos = cc->z_pos + 1; + } + ghb_compositor_zlist_insert(compositor, child, z_pos, 1.0); +} + +static void +ghb_compositor_remove(GtkContainer *container, GtkWidget *child) +{ + GhbCompositor *compositor = GHB_COMPOSITOR(container); + GhbCompositorChild *cc; + GList *link; + + for (link = compositor->children; link != NULL; link = link->next) + { + cc = (GhbCompositorChild*)link->data; + if (cc->widget == child) + { + gboolean was_visible = GTK_WIDGET_VISIBLE( child ); + gtk_widget_unparent(child); + compositor->children = g_list_remove(compositor->children, child); + g_free(child); + + if (was_visible && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize(GTK_WIDGET(container)); + break; + } + } +} + +static void +ghb_compositor_forall( + GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer data) +{ + GhbCompositor *compositor = GHB_COMPOSITOR (container); + GhbCompositorChild *cc; + GList *link; + + for (link = compositor->children; link != NULL; link = link->next) + { + cc = (GhbCompositorChild*)link->data; + (*callback)(cc->widget, data); + } +} + +static void +ghb_compositor_finalize (GObject *object) +{ + GhbCompositor *compositor = GHB_COMPOSITOR (object); + GhbCompositorChild *cc; + GList *link; + + for (link = compositor->children; link != NULL; link = link->next) + { + cc = (GhbCompositorChild*)link->data; + g_list_free(cc->drawables); + g_free(cc); + } + g_list_free(compositor->children); + G_OBJECT_CLASS (ghb_compositor_parent_class)->finalize (object); +} + + +static void +ghb_compositor_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + gint border_width; + gboolean visible_window; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + border_width = GTK_CONTAINER (widget)->border_width; + + attributes.x = widget->allocation.x + border_width; + attributes.y = widget->allocation.y + border_width; + attributes.width = widget->allocation.width - 2*border_width; + attributes.height = widget->allocation.height - 2*border_width; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events (widget) + | GDK_BUTTON_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_EXPOSURE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK; + + visible_window = !GTK_WIDGET_NO_WINDOW (widget); + if (visible_window) + { + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.wclass = GDK_INPUT_OUTPUT; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new(gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + } + else + { + widget->window = gtk_widget_get_parent_window (widget); + g_object_ref (widget->window); + } + + widget->style = gtk_style_attach (widget->style, widget->window); + + if (visible_window) + gtk_style_set_background(widget->style, widget->window, + GTK_STATE_NORMAL); +} + +static void +ghb_compositor_unrealize (GtkWidget *widget) +{ + GTK_WIDGET_CLASS (ghb_compositor_parent_class)->unrealize (widget); +} + +static void +ghb_compositor_size_request( + GtkWidget *widget, + GtkRequisition *requisition) +{ + GhbCompositor *compositor = GHB_COMPOSITOR (widget); + GList *link; + GhbCompositorChild *cc; + gint width = 0, height = 0; + GtkRequisition child_requisition; + + for (link = compositor->children; link != NULL; link = link->next) + { + cc = (GhbCompositorChild*)link->data; + if (GTK_WIDGET_VISIBLE(cc->widget)) + { + gtk_widget_size_request(cc->widget, NULL); + gtk_widget_get_child_requisition(cc->widget, &child_requisition); + width = MAX(child_requisition.width, width); + height = MAX(child_requisition.height, height); + } + } + + requisition->width = width + GTK_CONTAINER (widget)->border_width * 2; + requisition->height = height + GTK_CONTAINER (widget)->border_width * 2; +g_message("request_size %d x %d", requisition->width, requisition->height); +} + +static void +ghb_compositor_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + GhbCompositor *compositor; + GtkAllocation child_allocation; + GhbCompositorChild *cc; + GList *link; + + widget->allocation = *allocation; + compositor = GHB_COMPOSITOR (widget); + + if (GTK_WIDGET_NO_WINDOW (widget)) + { + child_allocation.x = allocation->x + + GTK_CONTAINER(widget)->border_width; + child_allocation.y = allocation->y + + GTK_CONTAINER(widget)->border_width; + } + else + { + child_allocation.x = 0; + child_allocation.y = 0; + } + child_allocation.width = MAX (allocation->width - + GTK_CONTAINER (widget)->border_width * 2, 0); + child_allocation.height = MAX (allocation->height - + GTK_CONTAINER (widget)->border_width * 2, 0); + + if (GTK_WIDGET_REALIZED (widget)) + { + if (!GTK_WIDGET_NO_WINDOW (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x + GTK_CONTAINER (widget)->border_width, + allocation->y + GTK_CONTAINER (widget)->border_width, + child_allocation.width, + child_allocation.height); + } + } + for (link = compositor->children; link != NULL; link = link->next) + { + cc = (GhbCompositorChild*)link->data; + gtk_widget_size_allocate (cc->widget, &child_allocation); + } +} + +static void +ghb_compositor_blend (GtkWidget *widget, GdkEventExpose *event) +{ + GhbCompositor *compositor = GHB_COMPOSITOR (widget); + GList *link, *draw; + GdkRegion *region; + GtkWidget *child; + cairo_t *cr; + GhbCompositorChild *cc; + + /* create a cairo context to draw to the window */ + cr = gdk_cairo_create (widget->window); + + for (link = compositor->children; link != NULL; link = link->next) + { + + cc = (GhbCompositorChild*)link->data; + for (draw = cc->drawables; draw != NULL; draw = draw->next) + { + /* get our child */ + child = GTK_WIDGET(draw->data); + /* the source data is the (composited) event box */ + gdk_cairo_set_source_pixmap (cr, child->window, + child->allocation.x, + child->allocation.y); + /* draw no more than our expose event intersects our child */ + region = gdk_region_rectangle (&child->allocation); + gdk_region_intersect (region, event->region); + gdk_cairo_region (cr, region); + cairo_clip (cr); + /* composite, with an opacity */ + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_paint_with_alpha (cr, cc->opacity); + cairo_reset_clip(cr); + } + } + /* we're done */ + cairo_destroy (cr); +} + +static gboolean +ghb_compositor_expose (GtkWidget *widget, GdkEventExpose *event) +{ + if (GTK_WIDGET_DRAWABLE (widget)) + { + if (!GTK_WIDGET_NO_WINDOW (widget)) + ghb_compositor_blend (widget, event); + + GTK_WIDGET_CLASS( + ghb_compositor_parent_class)->expose_event(widget, event); + } + + return FALSE; +} diff --git a/gtk/src/ghbcompositor.h b/gtk/src/ghbcompositor.h new file mode 100644 index 000000000..2dd62c5f4 --- /dev/null +++ b/gtk/src/ghbcompositor.h @@ -0,0 +1,74 @@ +/* "Borrowed" from: */ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ +#ifndef __GHB_COMPOSITOR_H__ +#define __GHB_COMPOSITOR_H__ + + +#include <gtk/gtkbin.h> + + +G_BEGIN_DECLS + +#define GHB_TYPE_COMPOSITOR (ghb_compositor_get_type ()) +#define GHB_COMPOSITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHB_TYPE_COMPOSITOR, GhbCompositor)) +#define GHB_COMPOSITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GHB_TYPE_COMPOSITOR, GhbCompositorClass)) +#define GHB_IS_COMPOSITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHB_TYPE_COMPOSITOR)) +#define GHB_IS_COMPOSITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHB_TYPE_COMPOSITOR)) +#define GHB_COMPOSITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GHB_TYPE_COMPOSITOR, GhbCompositorClass)) + +typedef struct _GhbCompositor GhbCompositor; +typedef struct _GhbCompositorClass GhbCompositorClass; +typedef struct _GhbCompositorChild GhbCompositorChild; + +struct _GhbCompositor +{ + GtkContainer container; + GList *children; +}; + +struct _GhbCompositorClass +{ + GtkContainerClass parent_class; +}; + +struct _GhbCompositorChild +{ + GtkWidget *widget; + GList *drawables; + guint z_pos; + gdouble opacity; +}; + +GType ghb_compositor_get_type (void) G_GNUC_CONST; +GtkWidget* ghb_compositor_new (void); +void ghb_compositor_zlist_insert (GhbCompositor *compositor, + GtkWidget *child, + gint z_pos, gdouble opacity); + +G_END_DECLS + +#endif /* __GHB_COMPOSITOR_H__ */ diff --git a/gtk/src/main.c b/gtk/src/main.c index d0d020cbb..ebb7348d4 100644 --- a/gtk/src/main.c +++ b/gtk/src/main.c @@ -50,6 +50,7 @@ #include "resources.h" #include "presets.h" #include "preview.h" +#include "ghbcompositor.h" /* @@ -83,18 +84,20 @@ create_builder_or_die(const gchar * name) { guint res = 0; GValue *gval; + GError *error = NULL; const gchar *ghb_ui; const gchar *markup = N_("<b><big>Unable to create %s.</big></b>\n" "\n" - "Internal error. Could not parse UI description.\n"); + "Internal error. Could not parse UI description.\n" + "%s"); g_debug("create_builder_or_die ()\n"); GtkBuilder *xml = gtk_builder_new(); gval = ghb_resource_get("ghb-ui"); ghb_ui = g_value_get_string(gval); if (xml != NULL) - res = gtk_builder_add_from_string(xml, ghb_ui, -1, NULL); + res = gtk_builder_add_from_string(xml, ghb_ui, -1, &error); if (!xml || !res) { GtkWidget *dialog = gtk_message_dialog_new_with_markup(NULL, @@ -102,7 +105,7 @@ create_builder_or_die(const gchar * name) GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _(markup), - name); + name, error->message); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); exit(EXIT_FAILURE); @@ -541,43 +544,27 @@ main (int argc, char *argv[]) watch_volumes (ud); ud->builder = create_builder_or_die (BUILDER_NAME); - GtkWidget *window, *event, *draw; - GdkScreen *screen; - GdkColormap *rgba; + // Set up the "hud" control overlay for the preview window + GtkWidget *window, *eb, *draw, *hud, *blender, *align; GdkColor color; - /* Make the widgets */ - //event = gtk_event_box_new (); - event = GHB_WIDGET(ud->builder, "preview_event_box"); - draw = GHB_WIDGET(ud->builder, "preview_image"); window = GHB_WIDGET(ud->builder, "preview_window"); + align = GHB_WIDGET(ud->builder, "preview_window_alignment"); + draw = GHB_WIDGET(ud->builder, "preview_image"); + hud = GHB_WIDGET(ud->builder, "preview_hud"); + eb = GHB_WIDGET(ud->builder, "preview_event_box"); + + // Set up compositing for hud + blender = ghb_compositor_new(); + gtk_container_add(GTK_CONTAINER(align), blender); + ghb_compositor_zlist_insert(GHB_COMPOSITOR(blender), draw, 1, 1); + ghb_compositor_zlist_insert(GHB_COMPOSITOR(blender), hud, 2, .85); + gtk_widget_show(blender); gdk_color_parse("black", &color); gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color); gdk_color_parse("gray18", &color); - gtk_widget_modify_bg(event, GTK_STATE_NORMAL, &color); - /* Set the colourmap for the event box. - ** Must be done before the event box is realised. - **/ - screen = gtk_widget_get_screen (draw); - rgba = gdk_screen_get_rgba_colormap (screen); - //gtk_widget_set_colormap (draw, rgba); - - gtk_widget_set_colormap (event, rgba); - - /* Set up the compositing handler. - ** Note that we do _after_ so that the normal (red) background is drawn - ** by gtk before our compositing occurs. - **/ - g_signal_connect_after (window, "expose-event", - G_CALLBACK (preview_window_expose_cb), ud); - /* Set the event box GdkWindow to be composited. - ** Obviously must be performed after event box is realised. - **/ - gtk_widget_realize(draw); - gtk_widget_realize(event); - gdk_window_set_composited (draw->window, TRUE); - gdk_window_set_composited (event->window, TRUE); + gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &color); // Redirect stderr to the activity window ghb_preview_init(ud); diff --git a/gtk/src/preview.c b/gtk/src/preview.c index c7e825eac..5b10d9b11 100644 --- a/gtk/src/preview.c +++ b/gtk/src/preview.c @@ -1107,6 +1107,7 @@ settings_configure_cb( return FALSE; } +#if 0 G_MODULE_EXPORT gboolean preview_window_expose_cb( GtkWidget *widget, @@ -1158,3 +1159,4 @@ preview_window_expose_cb( return FALSE; } +#endif |