aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--matchbox-panel/Makefile.am4
-rw-r--r--matchbox-panel/mb-panel-scaling-image2.c449
-rw-r--r--matchbox-panel/mb-panel-scaling-image2.h64
3 files changed, 515 insertions, 2 deletions
diff --git a/matchbox-panel/Makefile.am b/matchbox-panel/Makefile.am
index 67e0756..a102402 100644
--- a/matchbox-panel/Makefile.am
+++ b/matchbox-panel/Makefile.am
@@ -7,11 +7,11 @@ AM_CFLAGS = $(WARN_CFLAGS)
matchbox_panelincdir = $(pkgincludedir)
-matchbox_panelinc_HEADERS = mb-panel.h mb-panel-scaling-image.h
+matchbox_panelinc_HEADERS = mb-panel.h mb-panel-scaling-image.h mb-panel-scaling-image2.h
bin_PROGRAMS = matchbox-panel
-matchbox_panel_SOURCES = mb-panel.c mb-panel-scaling-image.c
+matchbox_panel_SOURCES = mb-panel.c mb-panel-scaling-image.c mb-panel-scaling-image2.c
matchbox_panel_LDADD = $(MATCHBOX_PANEL_LIBS)
diff --git a/matchbox-panel/mb-panel-scaling-image2.c b/matchbox-panel/mb-panel-scaling-image2.c
new file mode 100644
index 0000000..5692ce1
--- /dev/null
+++ b/matchbox-panel/mb-panel-scaling-image2.c
@@ -0,0 +1,449 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * (C) 2013 Intel Corp
+ *
+ * Author: Ross Burton <ross.burton@intel.com>
+ *
+ * Licensed under the GPL v2 or greater.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <gtk/gtk.h>
+
+#include "mb-panel-scaling-image2.h"
+
+struct _MBPanelScalingImage2Private {
+ GtkOrientation orientation;
+ char *icon;
+ int size;
+ GtkIconTheme *icon_theme;
+ guint icon_theme_changed_id;
+ GdkPixbuf *pixbuf;
+};
+
+enum {
+ PROP_0,
+ PROP_ORIENTATION,
+ PROP_ICON,
+};
+
+G_DEFINE_TYPE (MBPanelScalingImage2,
+ mb_panel_scaling_image2,
+ GTK_TYPE_DRAWING_AREA);
+
+static void
+mb_panel_scaling_image2_init (MBPanelScalingImage2 *image)
+{
+ image->priv = G_TYPE_INSTANCE_GET_PRIVATE (image,
+ MB_PANEL_TYPE_SCALING_IMAGE2,
+ MBPanelScalingImage2Private);
+
+ image->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
+
+ image->priv->icon = NULL;
+
+ image->priv->pixbuf = NULL;
+}
+
+static void
+mb_panel_scaling_image2_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MBPanelScalingImage2 *image;
+
+ image = MB_PANEL_SCALING_IMAGE2 (object);
+
+ switch (property_id) {
+ case PROP_ORIENTATION:
+ image->priv->orientation = g_value_get_enum (value);
+ break;
+ case PROP_ICON:
+ mb_panel_scaling_image2_set_icon (image,
+ g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+mb_panel_scaling_image2_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MBPanelScalingImage2 *image;
+
+ image = MB_PANEL_SCALING_IMAGE2 (object);
+
+ switch (property_id) {
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, image->priv->orientation);
+ break;
+ case PROP_ICON:
+ g_value_set_string (value, image->priv->icon);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+mb_panel_scaling_image2_dispose (GObject *object)
+{
+ MBPanelScalingImage2 *image;
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (mb_panel_scaling_image2_parent_class);
+ image = MB_PANEL_SCALING_IMAGE2 (object);
+
+ if (image->priv->icon_theme_changed_id) {
+ g_signal_handler_disconnect
+ (image->priv->icon_theme,
+ image->priv->icon_theme_changed_id);
+ image->priv->icon_theme_changed_id = 0;
+ }
+
+ object_class->dispose (object);
+}
+
+static void
+mb_panel_scaling_image2_finalize (GObject *object)
+{
+ MBPanelScalingImage2 *image;
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (mb_panel_scaling_image2_parent_class);
+ image = MB_PANEL_SCALING_IMAGE2 (object);
+
+ g_free (image->priv->icon);
+
+ object_class->finalize (object);
+}
+
+/* Strips extension off filename */
+static char *
+strip_extension (const char *file)
+{
+ char *stripped, *p;
+
+ stripped = g_strdup (file);
+
+ p = strrchr (stripped, '.');
+ if (p &&
+ (!strcmp (p, ".png") ||
+ !strcmp (p, ".svg") ||
+ !strcmp (p, ".xpm")))
+ *p = 0;
+
+ return stripped;
+}
+
+/* Find icon filename */
+/* This follows the same logic as gnome-panel. This should hopefully
+ * ensure correct behaviour. */
+static char *
+find_icon (GtkIconTheme *icon_theme,
+ const char *icon,
+ int size)
+{
+ GtkIconInfo *info;
+ char *new_icon, *stripped, *prefixed;
+
+ if (g_path_is_absolute (icon)) {
+ if (g_file_test (icon, G_FILE_TEST_EXISTS))
+ return g_strdup (icon);
+ else
+ new_icon = g_path_get_basename (icon);
+ } else
+ new_icon = (char *) icon;
+
+ stripped = strip_extension (new_icon);
+
+ if (new_icon != icon)
+ g_free (new_icon);
+
+ prefixed = g_strconcat ("panel-", stripped, NULL);
+
+ info = gtk_icon_theme_lookup_icon (icon_theme,
+ prefixed,
+ size,
+ 0);
+
+ if (info == NULL) {
+ info = gtk_icon_theme_lookup_icon (icon_theme,
+ stripped,
+ size,
+ 0);
+ }
+
+ g_free (stripped);
+ g_free (prefixed);
+
+ if (info) {
+ char *file;
+
+ file = g_strdup (gtk_icon_info_get_filename (info));
+
+ gtk_icon_info_free (info);
+
+ return file;
+ } else
+ return NULL;
+}
+
+/* Reload the specified icon */
+static void
+reload_icon (MBPanelScalingImage2 *image, gboolean force)
+{
+ GtkAllocation alloc;
+ int size;
+ char *file;
+ GError *error;
+ GdkPixbuf *pixbuf;
+
+ /* Determine the required icon size */
+ gtk_widget_get_allocation (GTK_WIDGET (image), &alloc);
+ size = image->priv->orientation == GTK_ORIENTATION_HORIZONTAL
+ ? alloc.height : alloc.width;
+
+ if (!force && size == image->priv->size) {
+ return;
+ }
+
+ image->priv->size = size;
+
+ if (!image->priv->icon) {
+ g_clear_object (&image->priv->pixbuf);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (image), NULL);
+ gtk_widget_queue_resize (GTK_WIDGET (image));
+ return;
+ }
+
+ file = find_icon (image->priv->icon_theme,
+ image->priv->icon,
+ size);
+ if (!file) {
+ g_warning ("Icon \"%s\" not found", image->priv->icon);
+
+ return;
+ }
+
+ error = NULL;
+ pixbuf = gdk_pixbuf_new_from_file_at_scale (file, size, size, TRUE, &error);
+ g_free (file);
+
+ g_clear_object (&image->priv->pixbuf);
+ if (pixbuf) {
+ image->priv->pixbuf = pixbuf;
+ } else {
+ g_warning ("No pixbuf found: %s", error->message);
+ g_error_free (error);
+ }
+
+ gtk_widget_queue_resize (GTK_WIDGET (image));
+}
+
+/* Icon theme changed */
+static void
+icon_theme_changed_cb (GtkIconTheme *icon_theme,
+ MBPanelScalingImage2 *image)
+{
+ GtkWidget *widget = GTK_WIDGET (image);
+
+ if (gtk_widget_get_realized (widget)) {
+ reload_icon (image, TRUE);
+ }
+}
+
+static void
+mb_panel_scaling_image2_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ MBPanelScalingImage2 *image = MB_PANEL_SCALING_IMAGE2 (widget);
+ GtkWidgetClass *widget_class;
+
+ widget_class = GTK_WIDGET_CLASS (mb_panel_scaling_image2_parent_class);
+ widget_class->size_allocate (widget, allocation);
+
+ if (gtk_widget_get_realized (widget)) {
+ reload_icon (image, FALSE);
+ }
+}
+
+static void
+mb_panel_scaling_image2_realize (GtkWidget *widget)
+{
+ GtkWidgetClass *widget_class;
+
+ reload_icon (MB_PANEL_SCALING_IMAGE2 (widget), TRUE);
+
+ widget_class = GTK_WIDGET_CLASS (mb_panel_scaling_image2_parent_class);
+ widget_class->realize (widget);
+}
+
+static void
+mb_panel_scaling_image2_screen_changed (GtkWidget *widget,
+ GdkScreen *old_screen)
+{
+ MBPanelScalingImage2 *image;
+ GdkScreen *screen;
+ GtkIconTheme *new_icon_theme;
+
+ if (GTK_WIDGET_CLASS (mb_panel_scaling_image2_parent_class)->screen_changed)
+ GTK_WIDGET_CLASS (mb_panel_scaling_image2_parent_class)->screen_changed (widget, old_screen);
+
+ image = MB_PANEL_SCALING_IMAGE2 (widget);
+ screen = gtk_widget_get_screen (widget);
+ new_icon_theme = gtk_icon_theme_get_for_screen (screen);
+ if (image->priv->icon_theme == new_icon_theme)
+ return;
+
+ if (image->priv->icon_theme_changed_id) {
+ g_signal_handler_disconnect
+ (image->priv->icon_theme,
+ image->priv->icon_theme_changed_id);
+ }
+
+ image->priv->icon_theme = new_icon_theme;
+
+ image->priv->icon_theme_changed_id =
+ g_signal_connect (image->priv->icon_theme,
+ "changed",
+ G_CALLBACK (icon_theme_changed_cb),
+ image);
+
+ if (gtk_widget_get_realized (widget)) {
+ reload_icon (MB_PANEL_SCALING_IMAGE2 (widget), TRUE);
+ }
+}
+static gboolean
+mb_panel_scaling_image2_draw (GtkWidget *widget, cairo_t *cr)
+{
+ MBPanelScalingImage2 *image = MB_PANEL_SCALING_IMAGE2 (widget);
+
+ gdk_cairo_set_source_pixbuf (cr, image->priv->pixbuf, 0.0, 0.0);
+ cairo_paint (cr);
+ return TRUE;
+}
+
+static void
+mb_panel_scaling_image2_get_preferred_width (GtkWidget *widget, int *minimum_width, int *natural_width)
+{
+ MBPanelScalingImage2 *image = MB_PANEL_SCALING_IMAGE2 (widget);
+
+ if (image->priv->pixbuf) {
+ *minimum_width = *natural_width = gdk_pixbuf_get_width (image->priv->pixbuf);
+ } else {
+ *minimum_width = *natural_width = 1;
+ }
+}
+
+static void
+mb_panel_scaling_image2_class_init (MBPanelScalingImage2Class *klass)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = mb_panel_scaling_image2_set_property;
+ object_class->get_property = mb_panel_scaling_image2_get_property;
+ object_class->dispose = mb_panel_scaling_image2_dispose;
+ object_class->finalize = mb_panel_scaling_image2_finalize;
+
+ widget_class = GTK_WIDGET_CLASS (klass);
+ widget_class->size_allocate = mb_panel_scaling_image2_size_allocate;
+ widget_class->realize = mb_panel_scaling_image2_realize;
+ widget_class->screen_changed = mb_panel_scaling_image2_screen_changed;
+ /* TODO: respect orientation and switch to height-for-width in vertical mode */
+ widget_class->get_preferred_width = mb_panel_scaling_image2_get_preferred_width;
+ widget_class->draw = mb_panel_scaling_image2_draw;
+
+ g_type_class_add_private (klass, sizeof (MBPanelScalingImage2Private));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_ORIENTATION,
+ g_param_spec_enum
+ ("orientation",
+ "orientation",
+ "The containing panels orientation.",
+ GTK_TYPE_ORIENTATION,
+ GTK_ORIENTATION_HORIZONTAL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_ICON,
+ g_param_spec_string
+ ("icon",
+ "icon",
+ "The loaded icon.",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB));
+}
+
+/**
+ * mb_panel_scaling_image2_new
+ * @orientation: The orientation of the containing panel.
+ * @icon: The icon to display. This can be an absolute path, or a name
+ * of an icon theme icon.
+ *
+ * Return value: A new #MBPanelScalingImage2 object displaying @icon.
+ **/
+GtkWidget *
+mb_panel_scaling_image2_new (GtkOrientation orientation,
+ const char *icon)
+{
+ return g_object_new (MB_PANEL_TYPE_SCALING_IMAGE2,
+ "orientation", orientation,
+ "icon", icon,
+ NULL);
+}
+
+/**
+ * mb_panel_scaling_image2_set_icon
+ * @image: A #MBPanelScalingImage2
+ * @icon: The icon to display. This can be an absolute path, or a name
+ * of an icon theme icon.
+ *
+ * Displays @icon in @image.
+ **/
+void
+mb_panel_scaling_image2_set_icon (MBPanelScalingImage2 *image,
+ const char *icon)
+{
+ g_return_if_fail (MB_PANEL_IS_SCALING_IMAGE2 (image));
+
+ g_free (image->priv->icon);
+ image->priv->icon = g_strdup (icon);
+
+ if (!gtk_widget_get_realized (GTK_WIDGET (image)))
+ return;
+
+ reload_icon (image, TRUE);
+}
+
+/**
+ * mb_panel_scaling_image2_get_icon
+ * @image: A #MBPanelScalingImage2
+ *
+ * Return value: The displayed icon. This string should not be freed.
+ **/
+const char *
+mb_panel_scaling_image2_get_icon (MBPanelScalingImage2 *image)
+{
+ g_return_val_if_fail (MB_PANEL_IS_SCALING_IMAGE2 (image), NULL);
+
+ return image->priv->icon;
+}
diff --git a/matchbox-panel/mb-panel-scaling-image2.h b/matchbox-panel/mb-panel-scaling-image2.h
new file mode 100644
index 0000000..5c0dd76
--- /dev/null
+++ b/matchbox-panel/mb-panel-scaling-image2.h
@@ -0,0 +1,64 @@
+/*
+ * (C) 2013 Intel Corp
+ *
+ * Author: Ross Burton <ross.burton@intel.com>
+ *
+ * Licensed under the GPL v2 or greater.
+ */
+
+#ifndef __MB_PANEL_SCALING_IMAGE2_H__
+#define __MB_PANEL_SCALING_IMAGE2_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define MB_PANEL_TYPE_SCALING_IMAGE2 \
+ (mb_panel_scaling_image2_get_type ())
+#define MB_PANEL_SCALING_IMAGE2(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ MB_PANEL_TYPE_SCALING_IMAGE2, \
+ MBPanelScalingImage2))
+#define MB_PANEL_SCALING_IMAGE2_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ MB_PANEL_TYPE_SCALING_IMAGE2, \
+ MBPanelScalingImage2Class))
+#define MB_PANEL_IS_SCALING_IMAGE2(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ MB_PANEL_TYPE_SCALING_IMAGE2))
+#define MB_PANEL_IS_SCALING_IMAGE2_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ MB_PANEL_TYPE_SCALING_IMAGE2))
+#define MB_PANEL_SCALING_IMAGE2_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ MB_PANEL_TYPE_SCALING_IMAGE2, \
+ MBPanelScalingImage2Class))
+
+typedef struct _MBPanelScalingImage2Private MBPanelScalingImage2Private;
+
+typedef struct {
+ GtkDrawingArea parent;
+ MBPanelScalingImage2Private *priv;
+} MBPanelScalingImage2;
+
+typedef struct {
+ GtkDrawingAreaClass parent_class;
+} MBPanelScalingImage2Class;
+
+GType
+mb_panel_scaling_image2_get_type (void) G_GNUC_CONST;
+
+GtkWidget *
+mb_panel_scaling_image2_new (GtkOrientation orientation,
+ const char *icon);
+
+void
+mb_panel_scaling_image2_set_icon (MBPanelScalingImage2 *image,
+ const char *icon);
+
+const char *
+mb_panel_scaling_image2_get_icon (MBPanelScalingImage2 *image);
+
+G_END_DECLS
+
+#endif /* __MB_PANEL_SCALING_IMAGE_H__ */