Replaced the anaconda_lb functions with an AnacondaLightbox class that inherits from GtkWindow. Increased the soversion and the widget package version. Fixed the signal handler usage. --- pyanaconda/ui/gui/__init__.py | 2 +- pyanaconda/ui/gui/tools/run-spoke.py | 2 +- pyanaconda/ui/gui/utils.py | 4 +- scripts/makeupdates | 2 +- widgets/configure.ac | 2 +- widgets/src/Makefile.am | 2 +- widgets/src/lightbox.c | 408 +++++++++++++++++++++++++---------- widgets/src/lightbox.h | 43 +++- 8 files changed, 345 insertions(+), 120 deletions(-)
diff --git a/pyanaconda/ui/gui/__init__.py b/pyanaconda/ui/gui/__init__.py index 803427c..7f18c4b 100644 --- a/pyanaconda/ui/gui/__init__.py +++ b/pyanaconda/ui/gui/__init__.py @@ -559,7 +559,7 @@ class GraphicalUserInterface(UserInterface):
# if there are no actions (not populated yet), we can do nothing if len(self._actions) > 0 and self._currentAction: - lightbox = AnacondaWidgets.lb_show_over(self._currentAction.window) + lightbox = AnacondaWidgets.Lightbox(parent_window=self._currentAction.window) ANACONDA_WINDOW_GROUP.add_window(lightbox) window.main_window.set_transient_for(lightbox)
diff --git a/pyanaconda/ui/gui/tools/run-spoke.py b/pyanaconda/ui/gui/tools/run-spoke.py index d3a83a4..d7101cf 100755 --- a/pyanaconda/ui/gui/tools/run-spoke.py +++ b/pyanaconda/ui/gui/tools/run-spoke.py @@ -20,7 +20,7 @@ if len(sys.argv)<2: sys.exit(1)
# This is a hack to make sure the AnacondaWidgets library gets loaded -ctypes.CDLL("libAnacondaWidgets.so.0", ctypes.RTLD_GLOBAL) +ctypes.CDLL("libAnacondaWidgets.so.1", ctypes.RTLD_GLOBAL)
# Logging always needs to be set up first thing, or there'll be tracebacks. from pyanaconda import anaconda_log diff --git a/pyanaconda/ui/gui/utils.py b/pyanaconda/ui/gui/utils.py index 38e0f4c..aa4078d 100644 --- a/pyanaconda/ui/gui/utils.py +++ b/pyanaconda/ui/gui/utils.py @@ -97,11 +97,11 @@ def enlightbox(mainWindow, dialog): # importing globally would cause a circular dependency from pyanaconda.ui.gui import ANACONDA_WINDOW_GROUP
- lightbox = AnacondaWidgets.lb_show_over(mainWindow) + lightbox = AnacondaWidgets.Lightbox(parent_window=mainWindow) ANACONDA_WINDOW_GROUP.add_window(lightbox) dialog.set_transient_for(lightbox) yield - AnacondaWidgets.lb_destroy(lightbox) + lightbox.destroy()
def ignoreEscape(dlg): """Prevent a dialog from accepting the escape keybinding, which emits a diff --git a/scripts/makeupdates b/scripts/makeupdates index 6e291fd..273428a 100755 --- a/scripts/makeupdates +++ b/scripts/makeupdates @@ -358,7 +358,7 @@ def copyUpdatedWidgets(updates, cwd):
os.system('make')
- files = ["libAnacondaWidgets.so", "libAnacondaWidgets.so.0", "libAnacondaWidgets.so.0.0.0"] + files = ["libAnacondaWidgets.so", "libAnacondaWidgets.so.1", "libAnacondaWidgets.so.1.0.0"] for f in files: path = os.path.normpath(cwd + "/widgets/src/.libs/" + f) if os.path.islink(path) and not os.path.exists(updates + libdir + os.path.basename(path)): diff --git a/widgets/configure.ac b/widgets/configure.ac index b0d5f58..baac242 100644 --- a/widgets/configure.ac +++ b/widgets/configure.ac @@ -20,7 +20,7 @@ #
AC_PREREQ([2.63]) -AC_INIT([AnacondaWidgets], [1.0], [clumens@redhat.com]) +AC_INIT([AnacondaWidgets], [2.0], [clumens@redhat.com]) AM_INIT_AUTOMAKE([foreign]) AM_SILENT_RULES([yes])
diff --git a/widgets/src/Makefile.am b/widgets/src/Makefile.am index 4b3bfde..aaab626 100644 --- a/widgets/src/Makefile.am +++ b/widgets/src/Makefile.am @@ -65,7 +65,7 @@ libAnacondaWidgets_la_CFLAGS = $(GTK_CFLAGS) $(GLADEUI_CFLAGS) $(LIBXKLAVIER_CFL -DWIDGETS_DATADIR=$(WIDGETSDATA)\ -DTZMAP_DATADIR=$(TZMAPDATA) libAnacondaWidgets_la_LIBADD = $(GTK_LIBS) $(GLADEUI_LIBS) $(LIBXKLAVIER_LIBS) -libAnacondaWidgets_la_LDFLAGS = $(LTLIBINTL) +libAnacondaWidgets_la_LDFLAGS = $(LTLIBINTL) -version-info 1:0:0 libAnacondaWidgets_la_SOURCES = $(SOURCES) $(HDRS) \ glade-adaptor.c
diff --git a/widgets/src/lightbox.c b/widgets/src/lightbox.c index 43edeeb..5752e7a 100644 --- a/widgets/src/lightbox.c +++ b/widgets/src/lightbox.c @@ -24,152 +24,338 @@ * @title: Lightbox * @short_description: Functions to draw a window over a shaded background * - * The lightbox is a set of functions used to display one window (a dialog or - * other similar window, typically) over top of the main window in the - * background. The main window is shaded out to make the foreground window - * stand out more, as well as to reinforce to the user that the background - * window may not be interacted with. + * The lightbox is a widget used to display one window (a dialog or other + * similar window, typically) over top of the main window in the background. + * The main window is shaded out to make the foreground window stand out more, + * as well as to reinforce to the user that the background window may not be + * interacted with. + * + * The lightbox window will show as soon as it is created. */
#include <cairo.h> -#include <gdk/gdk.h> #include <gtk/gtk.h>
#include "lightbox.h"
-/* GObject ID for the parent window's configure-event signal handler */ -#define ANACONDA_LB_PARENT_CONFIGURE_EVENT "anaconda-configure-event" +#include "intl.h" + +enum { + PROP_PARENT_WINDOW = 1 +}; + +struct _AnacondaLightboxPrivate { + GtkWindow *transient_parent; + gboolean parent_configure_event_handler_set; + guint parent_configure_event_handler; +}; + +static void anaconda_lightbox_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void anaconda_lightbox_draw_background(GObject *gobject, GParamSpec *psec, gpointer user_data); + +static gboolean anaconda_lb_parent_configure_event(GtkWidget *parent, GdkEvent *event, gpointer lightbox); +static gboolean anaconda_lb_configure_event(GtkWidget *lightbox, GdkEvent *event, gpointer user_data); +static void anaconda_lb_cleanup(GtkWidget *widget, gpointer user_data); + +G_DEFINE_TYPE(AnacondaLightbox, anaconda_lightbox, GTK_TYPE_WINDOW)
-static void anaconda_lb_move_window_to_parent(GtkWidget *parent, - GdkEventConfigure *e, - GtkWindow *window) +static void anaconda_lightbox_class_init(AnacondaLightboxClass *klass) { - GdkWindow *p_window, *w_window; - int pwidth, pheight, width, height, px, py, x, y, nx, ny; + GObjectClass *object_class = G_OBJECT_CLASS(klass);
- if (!GTK_IS_WIDGET(parent) || !GTK_IS_WINDOW(window)) - return; + object_class->set_property = anaconda_lightbox_set_property;
- p_window = gtk_widget_get_window (parent); - w_window = gtk_widget_get_window (GTK_WIDGET(window)); + /** + * AnacondaLightbox:parent-window: + * + * The parent of this window. This value is used as the transient parent + * for this window. + * + * Since: 2.0 + */ + g_object_class_install_property(object_class, + PROP_PARENT_WINDOW, + g_param_spec_object("parent-window", + P_("Parent Window"), + P_("The parent of this window"), + GTK_TYPE_WINDOW, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
- if (!GDK_IS_WINDOW(p_window) || !GDK_IS_WINDOW(w_window)) - return; + g_type_class_add_private(object_class, sizeof(AnacondaLightboxPrivate)); +} + +static void anaconda_lightbox_init(AnacondaLightbox *lightbox) +{ + lightbox->priv = G_TYPE_INSTANCE_GET_PRIVATE(lightbox, + ANACONDA_TYPE_LIGHTBOX, + AnacondaLightboxPrivate + ); + + /* Disable the window decorations on the parent (Gtk.Window) class */ + gtk_container_set_border_width(GTK_CONTAINER(lightbox), 0); + gtk_window_set_decorated(GTK_WINDOW(lightbox), FALSE); + gtk_window_set_has_resize_grip(GTK_WINDOW(lightbox), FALSE); + + /* Indicate we will handle drawing the widget so no theme is applied */ + gtk_widget_set_app_paintable(GTK_WIDGET(lightbox), TRUE); + gtk_window_set_type_hint(GTK_WINDOW(lightbox), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN); + + /* handle restacking events */ + g_signal_connect(lightbox, "configure-event", G_CALLBACK(anaconda_lb_configure_event), NULL); + + /* cleanup */ + g_signal_connect(lightbox, "destroy", G_CALLBACK(anaconda_lb_cleanup), NULL); +} + +static void anaconda_lightbox_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + AnacondaLightbox *lightbox = ANACONDA_LIGHTBOX(object); + AnacondaLightboxPrivate *priv = lightbox->priv; + + switch (prop_id) + { + case PROP_PARENT_WINDOW: + priv->transient_parent = GTK_WINDOW(g_object_ref(g_value_get_object(value))); + /* The property is CONSTRUCT_ONLY, so no point calling notify */ + anaconda_lightbox_draw_background(object, pspec, NULL); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/* + * Adjust the lightbox any time the parent window's size, position or stacking + * changes. Returns FALSE to allow signal processing to continue. + */ +static gboolean anaconda_lb_parent_configure_event( + GtkWidget *parent, + GdkEvent *event, + gpointer lightbox + ) +{ + /* Always return FALSE to continue processing for this signal. */ + GdkWindow *g_parent_window; + GdkWindow *g_lightbox_window;
- pwidth = gdk_window_get_width (p_window); - pheight = gdk_window_get_height (p_window); - gdk_window_get_position(p_window, &px, &py); + if ((event->type != GDK_CONFIGURE) || + !GTK_IS_WIDGET(parent) || + !GTK_IS_WINDOW(lightbox)) + { + return FALSE; + }
- width = gdk_window_get_width (w_window); - height = gdk_window_get_height (w_window); - gdk_window_get_position(w_window, &x, &y); + g_lightbox_window = gtk_widget_get_window(GTK_WIDGET(lightbox)); + if (NULL == g_lightbox_window) + { + /* + * No underlying GdkWindow. This may mean the lightbox is not yet + * realized, but whatever the cause, there's nothing we can do here. + */ + return FALSE; + }
- nx = px + pwidth / 2 - width / 2; - ny = py + pheight / 2 - height / 2; + /* Resize and move the window according to the event data */ + gdk_window_move_resize(g_lightbox_window, + event->configure.x, + event->configure.y, + event->configure.width, + event->configure.height + );
- if (x != nx || y != ny) + g_parent_window = gtk_widget_get_window(parent); + if (NULL == g_parent_window) { - gdk_window_move (w_window, nx, ny); - gdk_window_restack(w_window, p_window, TRUE); + return FALSE; }
- g_object_set_data(G_OBJECT(window), ANACONDA_LB_PARENT_CONFIGURE_EVENT, NULL); + /* Stack the lightbox above the parent */ + gdk_window_restack(g_lightbox_window, g_parent_window, TRUE); + + return FALSE; }
-/** - * anaconda_lb_show_over: - * @window: (in) A #GtkWindow - * - * Show lightbox over window. - * - * Return value: (transfer none): the lightbox widget. - * - * Since: 1.0 + +/* + * Draw the window background. Uses the gobject notify handler signature + * in case we want to allow parent-window to change in the future. */ -GtkWindow *anaconda_lb_show_over(GtkWindow *window) +static void anaconda_lightbox_draw_background( + GObject *gobject, + GParamSpec *psec, + gpointer user_data + ) { - GtkWindow *lightbox; - GdkWindow *w_window; - GdkWindow *l_window; - int width, height; - cairo_t *cr; - cairo_pattern_t *pattern; + AnacondaLightbox *lightbox; + + GdkWindow *g_lightbox_window; + GdkWindow *g_parent_window; cairo_surface_t *surface; - guint signal_handler; - - lightbox = (GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL))); - gtk_window_set_transient_for(lightbox, window); - gtk_window_set_decorated(lightbox, FALSE); - gtk_window_set_has_resize_grip(lightbox, FALSE); - gtk_window_set_position(lightbox, GTK_WIN_POS_CENTER_ON_PARENT); - gtk_window_set_type_hint (lightbox, GDK_WINDOW_TYPE_HINT_SPLASHSCREEN); - gtk_widget_set_app_paintable(GTK_WIDGET(lightbox), TRUE); + cairo_pattern_t *pattern; + cairo_t *cr; + + if (!ANACONDA_IS_LIGHTBOX(gobject)) + { + return; + } + + lightbox = ANACONDA_LIGHTBOX(gobject); + + /* + * Skip the check for whether the value has changed, since we only allow + * it to be set in the constructor + */ + + if (lightbox->priv->transient_parent) + { + gtk_window_set_transient_for(GTK_WINDOW(lightbox), lightbox->priv->transient_parent); + + /* Destroy the lightbox when the parent is destroyed */ + gtk_window_set_destroy_with_parent(GTK_WINDOW(lightbox), TRUE); + + /* Set the initial position to the center of the parent */ + gtk_window_set_position(GTK_WINDOW(lightbox), GTK_WIN_POS_CENTER_ON_PARENT); + + /* Set the lightbox to the parent window's dimensions */ + g_parent_window = gtk_widget_get_window(GTK_WIDGET(lightbox->priv->transient_parent)); + gtk_window_set_default_size(GTK_WINDOW(lightbox), + gdk_window_get_width(g_parent_window), + gdk_window_get_height(g_parent_window) + ); + + /* make the shade move with the parent window */ + /* Add a reference for the lightbox pointer held for the handler */ + g_object_ref(lightbox); + lightbox->priv->parent_configure_event_handler = + g_signal_connect(lightbox->priv->transient_parent, "configure-event", + G_CALLBACK(anaconda_lb_parent_configure_event), lightbox); + lightbox->priv->parent_configure_event_handler_set = TRUE; + + /* + * NB: We should probably be handling the draw signal in order to refresh + * the transparent pattern from the parent window whenver something + * changes, but by the time things get to the signal handler the surface is + * already set up and doesn't support alpha channels and replacing it + * doesn't seem to work quite right. Besides, none of these windows are + * supposed to move anyway. + */ + + /* Realize the window to initialize the Gdk objects */ + if (!gtk_widget_get_realized(GTK_WIDGET(lightbox))) + { + gtk_widget_realize(GTK_WIDGET(lightbox)); + } + g_lightbox_window = gtk_widget_get_window(GTK_WIDGET(lightbox)); + + /* Create a new surface that supports alpha content */ + surface = gdk_window_create_similar_surface(g_lightbox_window, + CAIRO_CONTENT_COLOR_ALPHA, + gdk_window_get_width(g_parent_window), + gdk_window_get_height(g_parent_window)); + cr = cairo_create(surface); + + /* Use the parent window as a pattern and paint it on the surface */ + gdk_cairo_set_source_window(cr, g_parent_window, 0, 0); + cairo_paint(cr); + + /* Paint a black, 50% transparent shade */ + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.5); + cairo_paint(cr); + + cairo_destroy(cr); + + /* Use the surface we painted as the window background */ + pattern = cairo_pattern_create_for_surface(surface); + gdk_window_set_background_pattern(g_lightbox_window, pattern); + cairo_pattern_destroy(pattern); + }
- w_window = gtk_widget_get_window (GTK_WIDGET(window)); - width = gdk_window_get_width(w_window); - height = gdk_window_get_height(w_window); - gtk_window_set_default_size(lightbox, width, height); - gtk_widget_realize(GTK_WIDGET(lightbox)); - l_window = gtk_widget_get_window (GTK_WIDGET(lightbox)); - gdk_window_set_background_pattern (l_window, NULL); gtk_widget_show(GTK_WIDGET(lightbox)); - surface = gdk_window_create_similar_surface(l_window, - CAIRO_CONTENT_COLOR_ALPHA, - width, height); - - cr = cairo_create (surface); - gdk_cairo_set_source_window(cr, w_window, 0, 0); - cairo_paint(cr); - cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.5); - cairo_paint(cr); - cairo_destroy(cr); - - pattern = cairo_pattern_create_for_surface (surface); - gdk_window_set_background_pattern(l_window, pattern); - cairo_pattern_destroy (pattern); - - /* make the shade move with the parent window */ - signal_handler = g_signal_connect(window, "configure-event", - G_CALLBACK (anaconda_lb_move_window_to_parent), lightbox); - - /* Save the signal handler in the lightbox so we can remove it later */ - g_object_set_data(G_OBJECT(lightbox), ANACONDA_LB_PARENT_CONFIGURE_EVENT, - GUINT_TO_POINTER(signal_handler)); - - return lightbox; }
-/** - * anaconda_lb_destroy: - * @lightbox: a #GtkWindow - * - * Destroys the previously used lightbox. - * - * Since: 1.0 +/* + * Restack the lightbox and its parent any time we receive a configure-event + * on the lightbox */ -void anaconda_lb_destroy(GtkWindow *lightbox) +static gboolean anaconda_lb_configure_event( + GtkWidget *lightbox, + GdkEvent *event, + gpointer user_data + ) { - GtkWindow *window; - gpointer p_signal_handler; + GtkWindow *parent; + GdkWindow *g_parent_window; + GdkWindow *g_lightbox_window;
- /* Disconnect the configure-event from the contained window */ - if (GTK_IS_WINDOW(lightbox)) + if ((event->type != GDK_CONFIGURE) || !ANACONDA_IS_LIGHTBOX(lightbox)) { - window = gtk_window_get_transient_for(GTK_WINDOW(lightbox)); + return FALSE; + }
- p_signal_handler = g_object_get_data(G_OBJECT(lightbox), - ANACONDA_LB_PARENT_CONFIGURE_EVENT); - if ((NULL != p_signal_handler) && GTK_IS_WINDOW(window)) - { - /* XXX HAAAAAAACK: - * If the configure-event signal handler for the contained window - * hasn't fired yet, do it now. - */ - g_signal_emit_by_name(window, "configure-event", window); + parent = ANACONDA_LIGHTBOX(lightbox)->priv->transient_parent; + if (!GTK_IS_WINDOW(parent)) + { + return FALSE; + } + + g_lightbox_window = gtk_widget_get_window(lightbox); + if (NULL == g_lightbox_window) + { + return FALSE; + } + + g_parent_window = gtk_widget_get_window(GTK_WIDGET(parent)); + if (NULL == g_parent_window) + { + return FALSE; + } + + gdk_window_restack(g_lightbox_window, g_parent_window, TRUE); + return FALSE; +} + +/* Clean up references to lightbox held by the parent window */ +static void anaconda_lb_cleanup(GtkWidget *widget, gpointer user_data) +{ + AnacondaLightbox *lightbox;
- g_signal_handler_disconnect(window, GPOINTER_TO_UINT(p_signal_handler)); + /* Remove the signal handlers set on the parent window */ + if (ANACONDA_IS_LIGHTBOX(widget)) + { + lightbox = ANACONDA_LIGHTBOX(widget); + + if (lightbox->priv->parent_configure_event_handler_set) + { + g_signal_handler_disconnect(lightbox->priv->transient_parent, + lightbox->priv->parent_configure_event_handler); + lightbox->priv->parent_configure_event_handler_set = FALSE; + g_object_unref(lightbox); } + + /* Drop the reference for the parent window */ + g_object_unref(lightbox->priv->transient_parent); + lightbox->priv->transient_parent = NULL; } +} + +/** + * anaconda_lightbox_new: + * @parent: The parent for this window + * + * Creates a new #AnacondaLightbox, which is a top-level, undecorated window + * that uses a shaded version of its parent window's background as its own + * background. + * + * Returns: the new lightbox as a #GtkWidget + */ +GtkWidget* anaconda_lightbox_new(GtkWindow *parent) +{ + AnacondaLightbox *lightbox; + + lightbox = ANACONDA_LIGHTBOX(g_object_new(ANACONDA_TYPE_LIGHTBOX, + "parent-window", parent, + NULL));
- gtk_widget_destroy(GTK_WIDGET(lightbox)); + return GTK_WIDGET(lightbox); } diff --git a/widgets/src/lightbox.h b/widgets/src/lightbox.h index 3a97010..7e645e2 100644 --- a/widgets/src/lightbox.h +++ b/widgets/src/lightbox.h @@ -22,7 +22,46 @@
#include <gtk/gtk.h>
-GtkWindow *anaconda_lb_show_over(GtkWindow *window); -void anaconda_lb_destroy(GtkWindow *lightbox); +G_BEGIN_DECLS + +#define ANACONDA_TYPE_LIGHTBOX (anaconda_lightbox_get_type()) +#define ANACONDA_LIGHTBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANACONDA_TYPE_LIGHTBOX, AnacondaLightbox)) +#define ANACONDA_LIGHTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANACONDA_TYPE_LIGHTBOX, AnacondaLightboxClass)) +#define ANACONDA_IS_LIGHTBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANACONDA_TYPE_LIGHTBOX)) +#define ANACONDA_IS_LIGHTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANACONDA_TYPE_LIGHTBOX)) +#define ANACONDA_LIGHTBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANACONDA_TYPE_LIGHTBOX, AnacondaLightboxClass)) + +typedef struct _AnacondaLightbox AnacondaLightbox; +typedef struct _AnacondaLightboxClass AnacondaLightboxClass; +typedef struct _AnacondaLightboxPrivate AnacondaLightboxPrivate; + +/** + * AnacondaLightbox: + * + * The AnacondaLightbox struct contains only private fields and should not + * be directly accessed. + */ +struct _AnacondaLightbox { + GtkWindow parent; + + /*< private >*/ + AnacondaLightboxPrivate *priv; +}; + +/** + * AnacondaLightboxClass: + * @parent_class: The object class structure needs to be the first element in + * the widget class structure in order for the class mechanism + * to work correctly. This allows a AnacondaLightbox + * pointer to be cast to a #GtkWindow pointer. + */ +struct _AnacondaLightboxClass { + GtkWindowClass parent_class; +}; + +GType anaconda_lightbox_get_type(void); +GtkWidget *anaconda_lightbox_new(GtkWindow *parent); + +G_END_DECLS
#endif
Since Lightbox is now a proper GtkWidget (horaaay!!!), it should live in a properly named file keeping the same convention as the rest of our widgets.
Signed-off-by: Vratislav Podzimek vpodzime@redhat.com --- widgets/src/Lightbox.c | 361 ++++++++++++++++++++++++++++++++++++++++++++++++ widgets/src/Lightbox.h | 67 +++++++++ widgets/src/Makefile.am | 4 +- widgets/src/lightbox.c | 361 ------------------------------------------------ widgets/src/lightbox.h | 67 --------- 5 files changed, 430 insertions(+), 430 deletions(-) create mode 100644 widgets/src/Lightbox.c create mode 100644 widgets/src/Lightbox.h delete mode 100644 widgets/src/lightbox.c delete mode 100644 widgets/src/lightbox.h
diff --git a/widgets/src/Lightbox.c b/widgets/src/Lightbox.c new file mode 100644 index 0000000..5752e7a --- /dev/null +++ b/widgets/src/Lightbox.c @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + * Author: Ales Kozumplik akozumpl@redhat.com + */ + +/* based on an example by Ray Strode rstrode@redhat.com */ + +/** + * SECTION: lightbox + * @title: Lightbox + * @short_description: Functions to draw a window over a shaded background + * + * The lightbox is a widget used to display one window (a dialog or other + * similar window, typically) over top of the main window in the background. + * The main window is shaded out to make the foreground window stand out more, + * as well as to reinforce to the user that the background window may not be + * interacted with. + * + * The lightbox window will show as soon as it is created. + */ + +#include <cairo.h> +#include <gtk/gtk.h> + +#include "lightbox.h" + +#include "intl.h" + +enum { + PROP_PARENT_WINDOW = 1 +}; + +struct _AnacondaLightboxPrivate { + GtkWindow *transient_parent; + gboolean parent_configure_event_handler_set; + guint parent_configure_event_handler; +}; + +static void anaconda_lightbox_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void anaconda_lightbox_draw_background(GObject *gobject, GParamSpec *psec, gpointer user_data); + +static gboolean anaconda_lb_parent_configure_event(GtkWidget *parent, GdkEvent *event, gpointer lightbox); +static gboolean anaconda_lb_configure_event(GtkWidget *lightbox, GdkEvent *event, gpointer user_data); +static void anaconda_lb_cleanup(GtkWidget *widget, gpointer user_data); + +G_DEFINE_TYPE(AnacondaLightbox, anaconda_lightbox, GTK_TYPE_WINDOW) + +static void anaconda_lightbox_class_init(AnacondaLightboxClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + object_class->set_property = anaconda_lightbox_set_property; + + /** + * AnacondaLightbox:parent-window: + * + * The parent of this window. This value is used as the transient parent + * for this window. + * + * Since: 2.0 + */ + g_object_class_install_property(object_class, + PROP_PARENT_WINDOW, + g_param_spec_object("parent-window", + P_("Parent Window"), + P_("The parent of this window"), + GTK_TYPE_WINDOW, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + g_type_class_add_private(object_class, sizeof(AnacondaLightboxPrivate)); +} + +static void anaconda_lightbox_init(AnacondaLightbox *lightbox) +{ + lightbox->priv = G_TYPE_INSTANCE_GET_PRIVATE(lightbox, + ANACONDA_TYPE_LIGHTBOX, + AnacondaLightboxPrivate + ); + + /* Disable the window decorations on the parent (Gtk.Window) class */ + gtk_container_set_border_width(GTK_CONTAINER(lightbox), 0); + gtk_window_set_decorated(GTK_WINDOW(lightbox), FALSE); + gtk_window_set_has_resize_grip(GTK_WINDOW(lightbox), FALSE); + + /* Indicate we will handle drawing the widget so no theme is applied */ + gtk_widget_set_app_paintable(GTK_WIDGET(lightbox), TRUE); + gtk_window_set_type_hint(GTK_WINDOW(lightbox), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN); + + /* handle restacking events */ + g_signal_connect(lightbox, "configure-event", G_CALLBACK(anaconda_lb_configure_event), NULL); + + /* cleanup */ + g_signal_connect(lightbox, "destroy", G_CALLBACK(anaconda_lb_cleanup), NULL); +} + +static void anaconda_lightbox_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + AnacondaLightbox *lightbox = ANACONDA_LIGHTBOX(object); + AnacondaLightboxPrivate *priv = lightbox->priv; + + switch (prop_id) + { + case PROP_PARENT_WINDOW: + priv->transient_parent = GTK_WINDOW(g_object_ref(g_value_get_object(value))); + /* The property is CONSTRUCT_ONLY, so no point calling notify */ + anaconda_lightbox_draw_background(object, pspec, NULL); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/* + * Adjust the lightbox any time the parent window's size, position or stacking + * changes. Returns FALSE to allow signal processing to continue. + */ +static gboolean anaconda_lb_parent_configure_event( + GtkWidget *parent, + GdkEvent *event, + gpointer lightbox + ) +{ + /* Always return FALSE to continue processing for this signal. */ + GdkWindow *g_parent_window; + GdkWindow *g_lightbox_window; + + if ((event->type != GDK_CONFIGURE) || + !GTK_IS_WIDGET(parent) || + !GTK_IS_WINDOW(lightbox)) + { + return FALSE; + } + + g_lightbox_window = gtk_widget_get_window(GTK_WIDGET(lightbox)); + if (NULL == g_lightbox_window) + { + /* + * No underlying GdkWindow. This may mean the lightbox is not yet + * realized, but whatever the cause, there's nothing we can do here. + */ + return FALSE; + } + + /* Resize and move the window according to the event data */ + gdk_window_move_resize(g_lightbox_window, + event->configure.x, + event->configure.y, + event->configure.width, + event->configure.height + ); + + g_parent_window = gtk_widget_get_window(parent); + if (NULL == g_parent_window) + { + return FALSE; + } + + /* Stack the lightbox above the parent */ + gdk_window_restack(g_lightbox_window, g_parent_window, TRUE); + + return FALSE; +} + + +/* + * Draw the window background. Uses the gobject notify handler signature + * in case we want to allow parent-window to change in the future. + */ +static void anaconda_lightbox_draw_background( + GObject *gobject, + GParamSpec *psec, + gpointer user_data + ) +{ + AnacondaLightbox *lightbox; + + GdkWindow *g_lightbox_window; + GdkWindow *g_parent_window; + cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_t *cr; + + if (!ANACONDA_IS_LIGHTBOX(gobject)) + { + return; + } + + lightbox = ANACONDA_LIGHTBOX(gobject); + + /* + * Skip the check for whether the value has changed, since we only allow + * it to be set in the constructor + */ + + if (lightbox->priv->transient_parent) + { + gtk_window_set_transient_for(GTK_WINDOW(lightbox), lightbox->priv->transient_parent); + + /* Destroy the lightbox when the parent is destroyed */ + gtk_window_set_destroy_with_parent(GTK_WINDOW(lightbox), TRUE); + + /* Set the initial position to the center of the parent */ + gtk_window_set_position(GTK_WINDOW(lightbox), GTK_WIN_POS_CENTER_ON_PARENT); + + /* Set the lightbox to the parent window's dimensions */ + g_parent_window = gtk_widget_get_window(GTK_WIDGET(lightbox->priv->transient_parent)); + gtk_window_set_default_size(GTK_WINDOW(lightbox), + gdk_window_get_width(g_parent_window), + gdk_window_get_height(g_parent_window) + ); + + /* make the shade move with the parent window */ + /* Add a reference for the lightbox pointer held for the handler */ + g_object_ref(lightbox); + lightbox->priv->parent_configure_event_handler = + g_signal_connect(lightbox->priv->transient_parent, "configure-event", + G_CALLBACK(anaconda_lb_parent_configure_event), lightbox); + lightbox->priv->parent_configure_event_handler_set = TRUE; + + /* + * NB: We should probably be handling the draw signal in order to refresh + * the transparent pattern from the parent window whenver something + * changes, but by the time things get to the signal handler the surface is + * already set up and doesn't support alpha channels and replacing it + * doesn't seem to work quite right. Besides, none of these windows are + * supposed to move anyway. + */ + + /* Realize the window to initialize the Gdk objects */ + if (!gtk_widget_get_realized(GTK_WIDGET(lightbox))) + { + gtk_widget_realize(GTK_WIDGET(lightbox)); + } + g_lightbox_window = gtk_widget_get_window(GTK_WIDGET(lightbox)); + + /* Create a new surface that supports alpha content */ + surface = gdk_window_create_similar_surface(g_lightbox_window, + CAIRO_CONTENT_COLOR_ALPHA, + gdk_window_get_width(g_parent_window), + gdk_window_get_height(g_parent_window)); + cr = cairo_create(surface); + + /* Use the parent window as a pattern and paint it on the surface */ + gdk_cairo_set_source_window(cr, g_parent_window, 0, 0); + cairo_paint(cr); + + /* Paint a black, 50% transparent shade */ + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.5); + cairo_paint(cr); + + cairo_destroy(cr); + + /* Use the surface we painted as the window background */ + pattern = cairo_pattern_create_for_surface(surface); + gdk_window_set_background_pattern(g_lightbox_window, pattern); + cairo_pattern_destroy(pattern); + } + + gtk_widget_show(GTK_WIDGET(lightbox)); +} + +/* + * Restack the lightbox and its parent any time we receive a configure-event + * on the lightbox + */ +static gboolean anaconda_lb_configure_event( + GtkWidget *lightbox, + GdkEvent *event, + gpointer user_data + ) +{ + GtkWindow *parent; + GdkWindow *g_parent_window; + GdkWindow *g_lightbox_window; + + if ((event->type != GDK_CONFIGURE) || !ANACONDA_IS_LIGHTBOX(lightbox)) + { + return FALSE; + } + + parent = ANACONDA_LIGHTBOX(lightbox)->priv->transient_parent; + if (!GTK_IS_WINDOW(parent)) + { + return FALSE; + } + + g_lightbox_window = gtk_widget_get_window(lightbox); + if (NULL == g_lightbox_window) + { + return FALSE; + } + + g_parent_window = gtk_widget_get_window(GTK_WIDGET(parent)); + if (NULL == g_parent_window) + { + return FALSE; + } + + gdk_window_restack(g_lightbox_window, g_parent_window, TRUE); + return FALSE; +} + +/* Clean up references to lightbox held by the parent window */ +static void anaconda_lb_cleanup(GtkWidget *widget, gpointer user_data) +{ + AnacondaLightbox *lightbox; + + /* Remove the signal handlers set on the parent window */ + if (ANACONDA_IS_LIGHTBOX(widget)) + { + lightbox = ANACONDA_LIGHTBOX(widget); + + if (lightbox->priv->parent_configure_event_handler_set) + { + g_signal_handler_disconnect(lightbox->priv->transient_parent, + lightbox->priv->parent_configure_event_handler); + lightbox->priv->parent_configure_event_handler_set = FALSE; + g_object_unref(lightbox); + } + + /* Drop the reference for the parent window */ + g_object_unref(lightbox->priv->transient_parent); + lightbox->priv->transient_parent = NULL; + } +} + +/** + * anaconda_lightbox_new: + * @parent: The parent for this window + * + * Creates a new #AnacondaLightbox, which is a top-level, undecorated window + * that uses a shaded version of its parent window's background as its own + * background. + * + * Returns: the new lightbox as a #GtkWidget + */ +GtkWidget* anaconda_lightbox_new(GtkWindow *parent) +{ + AnacondaLightbox *lightbox; + + lightbox = ANACONDA_LIGHTBOX(g_object_new(ANACONDA_TYPE_LIGHTBOX, + "parent-window", parent, + NULL)); + + return GTK_WIDGET(lightbox); +} diff --git a/widgets/src/Lightbox.h b/widgets/src/Lightbox.h new file mode 100644 index 0000000..7e645e2 --- /dev/null +++ b/widgets/src/Lightbox.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + * Author: Ales Kozumplik akozumpl@redhat.com + */ + +#ifndef LIGHTBOX_H +#define LIGHTBOX_H + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define ANACONDA_TYPE_LIGHTBOX (anaconda_lightbox_get_type()) +#define ANACONDA_LIGHTBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANACONDA_TYPE_LIGHTBOX, AnacondaLightbox)) +#define ANACONDA_LIGHTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANACONDA_TYPE_LIGHTBOX, AnacondaLightboxClass)) +#define ANACONDA_IS_LIGHTBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANACONDA_TYPE_LIGHTBOX)) +#define ANACONDA_IS_LIGHTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANACONDA_TYPE_LIGHTBOX)) +#define ANACONDA_LIGHTBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANACONDA_TYPE_LIGHTBOX, AnacondaLightboxClass)) + +typedef struct _AnacondaLightbox AnacondaLightbox; +typedef struct _AnacondaLightboxClass AnacondaLightboxClass; +typedef struct _AnacondaLightboxPrivate AnacondaLightboxPrivate; + +/** + * AnacondaLightbox: + * + * The AnacondaLightbox struct contains only private fields and should not + * be directly accessed. + */ +struct _AnacondaLightbox { + GtkWindow parent; + + /*< private >*/ + AnacondaLightboxPrivate *priv; +}; + +/** + * AnacondaLightboxClass: + * @parent_class: The object class structure needs to be the first element in + * the widget class structure in order for the class mechanism + * to work correctly. This allows a AnacondaLightbox + * pointer to be cast to a #GtkWindow pointer. + */ +struct _AnacondaLightboxClass { + GtkWindowClass parent_class; +}; + +GType anaconda_lightbox_get_type(void); +GtkWidget *anaconda_lightbox_new(GtkWindow *parent); + +G_END_DECLS + +#endif diff --git a/widgets/src/Makefile.am b/widgets/src/Makefile.am index aaab626..689207e 100644 --- a/widgets/src/Makefile.am +++ b/widgets/src/Makefile.am @@ -34,7 +34,7 @@ GISOURCES = BaseWindow.c \ StandaloneWindow.c \ TimezoneMap.c \ LayoutIndicator.c \ - lightbox.c + Lightbox.c
GIHDRS = BaseWindow.h \ DiskOverview.h \ @@ -45,7 +45,7 @@ GIHDRS = BaseWindow.h \ StandaloneWindow.h \ TimezoneMap.h \ LayoutIndicator.h \ - lightbox.h + Lightbox.h
NONGISOURCES = tz.c
diff --git a/widgets/src/lightbox.c b/widgets/src/lightbox.c deleted file mode 100644 index 5752e7a..0000000 --- a/widgets/src/lightbox.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright (C) 2011 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - * Author: Ales Kozumplik akozumpl@redhat.com - */ - -/* based on an example by Ray Strode rstrode@redhat.com */ - -/** - * SECTION: lightbox - * @title: Lightbox - * @short_description: Functions to draw a window over a shaded background - * - * The lightbox is a widget used to display one window (a dialog or other - * similar window, typically) over top of the main window in the background. - * The main window is shaded out to make the foreground window stand out more, - * as well as to reinforce to the user that the background window may not be - * interacted with. - * - * The lightbox window will show as soon as it is created. - */ - -#include <cairo.h> -#include <gtk/gtk.h> - -#include "lightbox.h" - -#include "intl.h" - -enum { - PROP_PARENT_WINDOW = 1 -}; - -struct _AnacondaLightboxPrivate { - GtkWindow *transient_parent; - gboolean parent_configure_event_handler_set; - guint parent_configure_event_handler; -}; - -static void anaconda_lightbox_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void anaconda_lightbox_draw_background(GObject *gobject, GParamSpec *psec, gpointer user_data); - -static gboolean anaconda_lb_parent_configure_event(GtkWidget *parent, GdkEvent *event, gpointer lightbox); -static gboolean anaconda_lb_configure_event(GtkWidget *lightbox, GdkEvent *event, gpointer user_data); -static void anaconda_lb_cleanup(GtkWidget *widget, gpointer user_data); - -G_DEFINE_TYPE(AnacondaLightbox, anaconda_lightbox, GTK_TYPE_WINDOW) - -static void anaconda_lightbox_class_init(AnacondaLightboxClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->set_property = anaconda_lightbox_set_property; - - /** - * AnacondaLightbox:parent-window: - * - * The parent of this window. This value is used as the transient parent - * for this window. - * - * Since: 2.0 - */ - g_object_class_install_property(object_class, - PROP_PARENT_WINDOW, - g_param_spec_object("parent-window", - P_("Parent Window"), - P_("The parent of this window"), - GTK_TYPE_WINDOW, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); - - g_type_class_add_private(object_class, sizeof(AnacondaLightboxPrivate)); -} - -static void anaconda_lightbox_init(AnacondaLightbox *lightbox) -{ - lightbox->priv = G_TYPE_INSTANCE_GET_PRIVATE(lightbox, - ANACONDA_TYPE_LIGHTBOX, - AnacondaLightboxPrivate - ); - - /* Disable the window decorations on the parent (Gtk.Window) class */ - gtk_container_set_border_width(GTK_CONTAINER(lightbox), 0); - gtk_window_set_decorated(GTK_WINDOW(lightbox), FALSE); - gtk_window_set_has_resize_grip(GTK_WINDOW(lightbox), FALSE); - - /* Indicate we will handle drawing the widget so no theme is applied */ - gtk_widget_set_app_paintable(GTK_WIDGET(lightbox), TRUE); - gtk_window_set_type_hint(GTK_WINDOW(lightbox), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN); - - /* handle restacking events */ - g_signal_connect(lightbox, "configure-event", G_CALLBACK(anaconda_lb_configure_event), NULL); - - /* cleanup */ - g_signal_connect(lightbox, "destroy", G_CALLBACK(anaconda_lb_cleanup), NULL); -} - -static void anaconda_lightbox_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - AnacondaLightbox *lightbox = ANACONDA_LIGHTBOX(object); - AnacondaLightboxPrivate *priv = lightbox->priv; - - switch (prop_id) - { - case PROP_PARENT_WINDOW: - priv->transient_parent = GTK_WINDOW(g_object_ref(g_value_get_object(value))); - /* The property is CONSTRUCT_ONLY, so no point calling notify */ - anaconda_lightbox_draw_background(object, pspec, NULL); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/* - * Adjust the lightbox any time the parent window's size, position or stacking - * changes. Returns FALSE to allow signal processing to continue. - */ -static gboolean anaconda_lb_parent_configure_event( - GtkWidget *parent, - GdkEvent *event, - gpointer lightbox - ) -{ - /* Always return FALSE to continue processing for this signal. */ - GdkWindow *g_parent_window; - GdkWindow *g_lightbox_window; - - if ((event->type != GDK_CONFIGURE) || - !GTK_IS_WIDGET(parent) || - !GTK_IS_WINDOW(lightbox)) - { - return FALSE; - } - - g_lightbox_window = gtk_widget_get_window(GTK_WIDGET(lightbox)); - if (NULL == g_lightbox_window) - { - /* - * No underlying GdkWindow. This may mean the lightbox is not yet - * realized, but whatever the cause, there's nothing we can do here. - */ - return FALSE; - } - - /* Resize and move the window according to the event data */ - gdk_window_move_resize(g_lightbox_window, - event->configure.x, - event->configure.y, - event->configure.width, - event->configure.height - ); - - g_parent_window = gtk_widget_get_window(parent); - if (NULL == g_parent_window) - { - return FALSE; - } - - /* Stack the lightbox above the parent */ - gdk_window_restack(g_lightbox_window, g_parent_window, TRUE); - - return FALSE; -} - - -/* - * Draw the window background. Uses the gobject notify handler signature - * in case we want to allow parent-window to change in the future. - */ -static void anaconda_lightbox_draw_background( - GObject *gobject, - GParamSpec *psec, - gpointer user_data - ) -{ - AnacondaLightbox *lightbox; - - GdkWindow *g_lightbox_window; - GdkWindow *g_parent_window; - cairo_surface_t *surface; - cairo_pattern_t *pattern; - cairo_t *cr; - - if (!ANACONDA_IS_LIGHTBOX(gobject)) - { - return; - } - - lightbox = ANACONDA_LIGHTBOX(gobject); - - /* - * Skip the check for whether the value has changed, since we only allow - * it to be set in the constructor - */ - - if (lightbox->priv->transient_parent) - { - gtk_window_set_transient_for(GTK_WINDOW(lightbox), lightbox->priv->transient_parent); - - /* Destroy the lightbox when the parent is destroyed */ - gtk_window_set_destroy_with_parent(GTK_WINDOW(lightbox), TRUE); - - /* Set the initial position to the center of the parent */ - gtk_window_set_position(GTK_WINDOW(lightbox), GTK_WIN_POS_CENTER_ON_PARENT); - - /* Set the lightbox to the parent window's dimensions */ - g_parent_window = gtk_widget_get_window(GTK_WIDGET(lightbox->priv->transient_parent)); - gtk_window_set_default_size(GTK_WINDOW(lightbox), - gdk_window_get_width(g_parent_window), - gdk_window_get_height(g_parent_window) - ); - - /* make the shade move with the parent window */ - /* Add a reference for the lightbox pointer held for the handler */ - g_object_ref(lightbox); - lightbox->priv->parent_configure_event_handler = - g_signal_connect(lightbox->priv->transient_parent, "configure-event", - G_CALLBACK(anaconda_lb_parent_configure_event), lightbox); - lightbox->priv->parent_configure_event_handler_set = TRUE; - - /* - * NB: We should probably be handling the draw signal in order to refresh - * the transparent pattern from the parent window whenver something - * changes, but by the time things get to the signal handler the surface is - * already set up and doesn't support alpha channels and replacing it - * doesn't seem to work quite right. Besides, none of these windows are - * supposed to move anyway. - */ - - /* Realize the window to initialize the Gdk objects */ - if (!gtk_widget_get_realized(GTK_WIDGET(lightbox))) - { - gtk_widget_realize(GTK_WIDGET(lightbox)); - } - g_lightbox_window = gtk_widget_get_window(GTK_WIDGET(lightbox)); - - /* Create a new surface that supports alpha content */ - surface = gdk_window_create_similar_surface(g_lightbox_window, - CAIRO_CONTENT_COLOR_ALPHA, - gdk_window_get_width(g_parent_window), - gdk_window_get_height(g_parent_window)); - cr = cairo_create(surface); - - /* Use the parent window as a pattern and paint it on the surface */ - gdk_cairo_set_source_window(cr, g_parent_window, 0, 0); - cairo_paint(cr); - - /* Paint a black, 50% transparent shade */ - cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.5); - cairo_paint(cr); - - cairo_destroy(cr); - - /* Use the surface we painted as the window background */ - pattern = cairo_pattern_create_for_surface(surface); - gdk_window_set_background_pattern(g_lightbox_window, pattern); - cairo_pattern_destroy(pattern); - } - - gtk_widget_show(GTK_WIDGET(lightbox)); -} - -/* - * Restack the lightbox and its parent any time we receive a configure-event - * on the lightbox - */ -static gboolean anaconda_lb_configure_event( - GtkWidget *lightbox, - GdkEvent *event, - gpointer user_data - ) -{ - GtkWindow *parent; - GdkWindow *g_parent_window; - GdkWindow *g_lightbox_window; - - if ((event->type != GDK_CONFIGURE) || !ANACONDA_IS_LIGHTBOX(lightbox)) - { - return FALSE; - } - - parent = ANACONDA_LIGHTBOX(lightbox)->priv->transient_parent; - if (!GTK_IS_WINDOW(parent)) - { - return FALSE; - } - - g_lightbox_window = gtk_widget_get_window(lightbox); - if (NULL == g_lightbox_window) - { - return FALSE; - } - - g_parent_window = gtk_widget_get_window(GTK_WIDGET(parent)); - if (NULL == g_parent_window) - { - return FALSE; - } - - gdk_window_restack(g_lightbox_window, g_parent_window, TRUE); - return FALSE; -} - -/* Clean up references to lightbox held by the parent window */ -static void anaconda_lb_cleanup(GtkWidget *widget, gpointer user_data) -{ - AnacondaLightbox *lightbox; - - /* Remove the signal handlers set on the parent window */ - if (ANACONDA_IS_LIGHTBOX(widget)) - { - lightbox = ANACONDA_LIGHTBOX(widget); - - if (lightbox->priv->parent_configure_event_handler_set) - { - g_signal_handler_disconnect(lightbox->priv->transient_parent, - lightbox->priv->parent_configure_event_handler); - lightbox->priv->parent_configure_event_handler_set = FALSE; - g_object_unref(lightbox); - } - - /* Drop the reference for the parent window */ - g_object_unref(lightbox->priv->transient_parent); - lightbox->priv->transient_parent = NULL; - } -} - -/** - * anaconda_lightbox_new: - * @parent: The parent for this window - * - * Creates a new #AnacondaLightbox, which is a top-level, undecorated window - * that uses a shaded version of its parent window's background as its own - * background. - * - * Returns: the new lightbox as a #GtkWidget - */ -GtkWidget* anaconda_lightbox_new(GtkWindow *parent) -{ - AnacondaLightbox *lightbox; - - lightbox = ANACONDA_LIGHTBOX(g_object_new(ANACONDA_TYPE_LIGHTBOX, - "parent-window", parent, - NULL)); - - return GTK_WIDGET(lightbox); -} diff --git a/widgets/src/lightbox.h b/widgets/src/lightbox.h deleted file mode 100644 index 7e645e2..0000000 --- a/widgets/src/lightbox.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2011 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - * Author: Ales Kozumplik akozumpl@redhat.com - */ - -#ifndef LIGHTBOX_H -#define LIGHTBOX_H - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define ANACONDA_TYPE_LIGHTBOX (anaconda_lightbox_get_type()) -#define ANACONDA_LIGHTBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANACONDA_TYPE_LIGHTBOX, AnacondaLightbox)) -#define ANACONDA_LIGHTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANACONDA_TYPE_LIGHTBOX, AnacondaLightboxClass)) -#define ANACONDA_IS_LIGHTBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANACONDA_TYPE_LIGHTBOX)) -#define ANACONDA_IS_LIGHTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANACONDA_TYPE_LIGHTBOX)) -#define ANACONDA_LIGHTBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANACONDA_TYPE_LIGHTBOX, AnacondaLightboxClass)) - -typedef struct _AnacondaLightbox AnacondaLightbox; -typedef struct _AnacondaLightboxClass AnacondaLightboxClass; -typedef struct _AnacondaLightboxPrivate AnacondaLightboxPrivate; - -/** - * AnacondaLightbox: - * - * The AnacondaLightbox struct contains only private fields and should not - * be directly accessed. - */ -struct _AnacondaLightbox { - GtkWindow parent; - - /*< private >*/ - AnacondaLightboxPrivate *priv; -}; - -/** - * AnacondaLightboxClass: - * @parent_class: The object class structure needs to be the first element in - * the widget class structure in order for the class mechanism - * to work correctly. This allows a AnacondaLightbox - * pointer to be cast to a #GtkWindow pointer. - */ -struct _AnacondaLightboxClass { - GtkWindowClass parent_class; -}; - -GType anaconda_lightbox_get_type(void); -GtkWidget *anaconda_lightbox_new(GtkWindow *parent); - -G_END_DECLS - -#endif
On 09/11/2013 04:05 AM, Vratislav Podzimek wrote:
#include "lightbox.h"
This needs to be Lightbox.h now.
lightbox.c also needs to change in po/POTFILES.in. I also attached a patch to widgets/doc/AnacondaWidgets-docs.xml to put the Lightbox with the other window classes since I probably should have done that yesterday. Otherwise, Ack :-)
On Wed, 2013-09-11 at 08:58 -0400, David Shea wrote:
On 09/11/2013 04:05 AM, Vratislav Podzimek wrote:
#include "lightbox.h"
This needs to be Lightbox.h now.
lightbox.c also needs to change in po/POTFILES.in. I also attached a patch to widgets/doc/AnacondaWidgets-docs.xml to put the Lightbox with the other window classes since I probably should have done that yesterday. Otherwise, Ack :-)
Good catches, thanks! I'll fix it locally and squash it with your patch to widgets/doc/AnacondaWidgets-docs.xml
anaconda-patches@lists.fedorahosted.org