Back to index

libindicator  12.10.0
indicator-image-helper.c
Go to the documentation of this file.
00001 /*
00002 A little helper to make a themed image with fallbacks that
00003 is only constrained in the vertical dimention.
00004 
00005 Copyright 2010 Canonical Ltd.
00006 
00007 Authors:
00008     Ted Gould <ted@canonical.com>
00009 
00010 This library is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 version 3.0 as published by the Free Software Foundation.
00013 
00014 This library is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 GNU General Public License version 3.0 for more details.
00018 
00019 You should have received a copy of the GNU General Public
00020 License along with this library. If not, see
00021 <http://www.gnu.org/licenses/>.
00022 */
00023 
00024 #include <math.h>
00025 #include "indicator-image-helper.h"
00026 
00027 const gchar * INDICATOR_NAMES_DATA = "indicator-names-data";
00028 
00029 static void
00030 refresh_image (GtkImage * image)
00031 {
00032        g_return_if_fail(GTK_IS_IMAGE(image));
00033        const gchar * icon_filename = NULL;
00034        GtkIconInfo * icon_info = NULL;
00035        gint icon_size = 22;
00036 
00037        GIcon * icon_names = (GIcon *)g_object_get_data(G_OBJECT(image), INDICATOR_NAMES_DATA);
00038        g_return_if_fail(icon_names != NULL);
00039 
00040        /* Get the default theme */
00041        GtkIconTheme * default_theme = gtk_icon_theme_get_default();
00042        g_return_if_fail(default_theme != NULL);
00043 
00044        /* Look through the themes for that icon */
00045        icon_info = gtk_icon_theme_lookup_by_gicon(default_theme, icon_names, icon_size, 0);
00046        if (icon_info == NULL) {
00047               /* Maybe the icon was just added to the theme, see if a rescan helps */
00048               gtk_icon_theme_rescan_if_needed(default_theme);
00049               icon_info = gtk_icon_theme_lookup_by_gicon(default_theme, icon_names, icon_size, 0);
00050        }
00051        if (icon_info == NULL) {
00052               /* Try using the second item in the names, which should be the original filename supplied */
00053               const gchar * const * names = g_themed_icon_get_names(G_THEMED_ICON( icon_names ));
00054               if (names) {
00055                      icon_filename = names[1];
00056               } else {
00057                      g_warning("Unable to find icon\n");
00058                      gtk_image_clear(image);
00059                      return;
00060               }
00061        } else {
00062               /* Grab the filename */
00063               icon_filename = gtk_icon_info_get_filename(icon_info);
00064        }
00065        g_return_if_fail(icon_filename != NULL); /* An error because we don't have a filename */
00066 
00067        /* Build a pixbuf */
00068        GError * error = NULL;
00069        GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file(icon_filename, &error);
00070 
00071        if (icon_info != NULL) {
00072               gtk_icon_info_free(icon_info);
00073        }
00074 
00075        if (pixbuf == NULL) {
00076               g_warning("Unable to load icon from file '%s' because: %s", icon_filename, error == NULL ? "I don't know" : error->message);
00077               g_clear_error (&error);
00078               gtk_image_clear(image);
00079               return;
00080        }
00081 
00082        /* Scale icon if all we get is something too big. */
00083        if (gdk_pixbuf_get_height(pixbuf) > icon_size) {
00084               gfloat scale = (gfloat)icon_size / (gfloat)gdk_pixbuf_get_height(pixbuf);
00085               gint width = round(gdk_pixbuf_get_width(pixbuf) * scale);
00086 
00087               GdkPixbuf * scaled = gdk_pixbuf_scale_simple(pixbuf, width, icon_size, GDK_INTERP_BILINEAR);
00088               g_object_unref(G_OBJECT(pixbuf));
00089               pixbuf = scaled;
00090        }
00091 
00092        /* Put the pixbuf on the image */
00093        gtk_image_set_from_pixbuf(image, pixbuf);
00094        g_object_unref(G_OBJECT(pixbuf));
00095 
00096        return;
00097 }
00098 
00099 /* Handles the theme changed signal to refresh the icon to make
00100    sure that it changes appropriately */
00101 static void
00102 theme_changed_cb (GtkIconTheme * theme, gpointer user_data)
00103 {
00104        GtkImage * image = GTK_IMAGE(user_data);
00105        refresh_image(image);
00106        return;
00107 }
00108 
00109 /* Removes the signal on the theme that was calling update on this
00110    image. */
00111 static void
00112 image_destroyed_cb (GtkImage * image, gpointer user_data)
00113 {
00114        g_signal_handlers_disconnect_by_func(gtk_icon_theme_get_default(), theme_changed_cb, image);
00115        return;
00116 }
00117 
00118 /* Catch the style changing on the image to make sure
00119    we've got the latest. */
00120 static void
00121 image_style_change_cb (GtkImage * image, GtkStyle * previous_style, gpointer user_data)
00122 {
00123        refresh_image(image);
00124        return;
00125 }
00126 
00127 /* Builds an image with the name and fallbacks and all kinds of fun
00128    stuff . */
00129 GtkImage *
00130 indicator_image_helper (const gchar * name)
00131 {
00132        /* Build us an image */
00133        GtkImage * image = GTK_IMAGE(gtk_image_new());
00134 
00135        indicator_image_helper_update(image, name);
00136 
00137        return image;
00138 }
00139 
00140 /* Updates and image with all the fun stuff */
00141 void
00142 indicator_image_helper_update (GtkImage * image, const gchar * name)
00143 {
00144        g_return_if_fail(name != NULL);
00145        g_return_if_fail(name[0] != '\0');
00146        g_return_if_fail(GTK_IS_IMAGE(image));
00147        gboolean seen_previously = FALSE;
00148 
00149        /* Build us a GIcon */
00150        GIcon * icon_names = g_themed_icon_new_with_default_fallbacks(name);
00151        g_warn_if_fail(icon_names != NULL);
00152        g_return_if_fail(icon_names != NULL);
00153 
00154        seen_previously = (g_object_get_data(G_OBJECT(image), INDICATOR_NAMES_DATA) != NULL);
00155 
00156        /* Attach our names to the image */
00157        g_object_set_data_full(G_OBJECT(image), INDICATOR_NAMES_DATA, icon_names, g_object_unref);
00158 
00159        /* Put the pixbuf in */
00160        refresh_image(image);
00161 
00162        /* Connect to all changes */
00163        if (!seen_previously) {
00164               g_signal_connect(G_OBJECT(gtk_icon_theme_get_default()), "changed", G_CALLBACK(theme_changed_cb), image);
00165               g_signal_connect(G_OBJECT(image), "destroy", G_CALLBACK(image_destroyed_cb), NULL);
00166               g_signal_connect(G_OBJECT(image), "style-set", G_CALLBACK(image_style_change_cb), NULL);
00167        }
00168 
00169        return;
00170 }