[gnome-flashback] input-sources: implement status icon with pango and cairo



commit 5e753cd2929e5f07064e29fa3b9e2e4f9ce67667
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Wed Oct 14 08:44:26 2015 +0300

    input-sources: implement status icon with pango and cairo
    
    Based on a patch by Sebastian Geiger <sbastig gmx net>.

 .../libinput-sources/gf-input-sources.c            |  264 ++++++++++++++++++++
 1 files changed, 264 insertions(+), 0 deletions(-)
---
diff --git a/gnome-flashback/libinput-sources/gf-input-sources.c 
b/gnome-flashback/libinput-sources/gf-input-sources.c
index ce708ad..0632d2c 100644
--- a/gnome-flashback/libinput-sources/gf-input-sources.c
+++ b/gnome-flashback/libinput-sources/gf-input-sources.c
@@ -17,9 +17,19 @@
 
 #include "config.h"
 
+#include <gtk/gtk.h>
+#include <pango/pangocairo.h>
+
+#define _XOPEN_SOURCE
+#include <math.h>
+
 #include "gf-ibus-manager.h"
 #include "gf-input-sources.h"
 #include "gf-input-source-manager.h"
+#include "gf-input-source.h"
+
+#define INPUT_SOURCES_SCHEMA "org.gnome.gnome-flashback.input-sources"
+#define GNOME_DESKTOP_SCHEMA "org.gnome.desktop.interface"
 
 struct _GfInputSources
 {
@@ -27,17 +37,242 @@ struct _GfInputSources
 
   GfIBusManager        *ibus_manager;
   GfInputSourceManager *input_source_manager;
+
+  GSettings            *input_sources_settings;
+  GSettings            *gnome_desktop_settings;
+
+  GfInputSource        *current_source;
+  GtkStatusIcon        *status_icon;
 };
 
 G_DEFINE_TYPE (GfInputSources, gf_input_sources, G_TYPE_OBJECT)
 
 static void
+draw_background (GfInputSources *sources,
+                 cairo_t        *cr,
+                 gint            size)
+{
+  gdouble x;
+  gdouble y;
+  gdouble width;
+  gdouble height;
+  gdouble radius;
+  gdouble degrees;
+  gchar *color;
+  GdkRGBA rgba;
+
+  x = size * 0.04;
+  y = size * 0.04;
+  width = size - x * 2;
+  height = size - y * 2;
+
+  radius = height / 10;
+  degrees = M_PI / 180.0;
+
+  cairo_new_sub_path (cr);
+  cairo_arc (cr, x + width - radius, y + radius,
+             radius, -90 * degrees, 0 * degrees);
+  cairo_arc (cr, x + width - radius, y + height - radius,
+             radius, 0 * degrees, 90 * degrees);
+  cairo_arc (cr, x + radius, y + height - radius,
+             radius, 90 * degrees, 180 * degrees);
+  cairo_arc (cr, x + radius, y + radius,
+             radius, 180 * degrees, 270 * degrees);
+  cairo_close_path (cr);
+
+  color = g_settings_get_string (sources->input_sources_settings,
+                                 "status-icon-bg-color");
+
+  gdk_rgba_parse (&rgba, color);
+  g_free (color);
+
+  gdk_cairo_set_source_rgba (cr, &rgba);
+  cairo_fill_preserve (cr);
+}
+
+static void
+draw_text (GfInputSources *sources,
+           cairo_t        *cr,
+           gint            size)
+{
+  gchar *font_name;
+  PangoFontDescription *font_desc;
+  gdouble font_size;
+  PangoLayout *layout;
+  const gchar *short_name;
+  gint text_width;
+  gint text_height;
+  gdouble factor;
+  gdouble center;
+  gdouble x;
+  gdouble y;
+  gchar *color;
+  GdkRGBA rgba;
+
+  font_name = g_settings_get_string (sources->gnome_desktop_settings,
+                                     "font-name");
+
+  font_desc = pango_font_description_from_string (font_name);
+  g_free (font_name);
+
+  pango_font_description_set_weight (font_desc, PANGO_WEIGHT_MEDIUM);
+
+  font_size = PANGO_SCALE * size * 0.5;
+  pango_font_description_set_absolute_size (font_desc, font_size);
+
+  layout = pango_cairo_create_layout (cr);
+
+  pango_layout_set_font_description (layout, font_desc);
+  pango_font_description_free (font_desc);
+
+  short_name = gf_input_source_get_short_name (sources->current_source);
+  pango_layout_set_text (layout, short_name, -1);
+
+  pango_layout_get_pixel_size (layout, &text_width, &text_height);
+
+  factor = MIN ((size - (size * 0.1) * 2) / text_width, 1.0);
+  cairo_scale (cr, factor, factor);
+
+  center = size / 2.0;
+  x = center - text_width * factor / 2.0;
+  y = center - text_height * factor / 2.0;
+  cairo_move_to (cr, x, y);
+
+  color = g_settings_get_string (sources->input_sources_settings,
+                                 "status-icon-fg-color");
+
+  gdk_rgba_parse (&rgba, color);
+  g_free (color);
+
+  gdk_cairo_set_source_rgba (cr, &rgba);
+
+  pango_cairo_show_layout (cr, layout);
+  g_object_unref (layout);
+}
+
+static void
+update_status_icon_pixbuf (GfInputSources *sources)
+{
+  gint size;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  GdkPixbuf *pixbuf;
+
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+  size = gtk_status_icon_get_size (sources->status_icon);
+  G_GNUC_END_IGNORE_DEPRECATIONS
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, size, size);
+  cr = cairo_create (surface);
+
+  draw_background (sources, cr, size);
+  draw_text (sources, cr, size);
+
+  cairo_destroy (cr);
+
+  pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, size, size);
+  cairo_surface_destroy (surface);
+
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+  gtk_status_icon_set_from_pixbuf (sources->status_icon, pixbuf);
+  G_GNUC_END_IGNORE_DEPRECATIONS
+
+  g_object_unref (pixbuf);
+}
+
+static void
+update_status_icon (GfInputSources *sources)
+{
+  GfInputSourceManager *manager;
+  GfInputSource *source;
+  const gchar *display_name;
+
+  manager = sources->input_source_manager;
+
+  g_clear_object (&sources->current_source);
+  source = gf_input_source_manager_get_current_source (manager);
+
+  if (source == NULL)
+    {
+      g_clear_object (&sources->status_icon);
+      return;
+    }
+
+  sources->current_source = g_object_ref (source);
+
+  if (sources->status_icon == NULL)
+    {
+      G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+      sources->status_icon = gtk_status_icon_new ();
+      G_GNUC_END_IGNORE_DEPRECATIONS
+
+      g_signal_connect_swapped (sources->status_icon, "size-changed",
+                                G_CALLBACK (update_status_icon), sources);
+    }
+
+  display_name = gf_input_source_get_display_name (source);
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+  gtk_status_icon_set_tooltip_text (sources->status_icon, display_name);
+  G_GNUC_END_IGNORE_DEPRECATIONS
+
+  update_status_icon_pixbuf (sources);
+}
+
+static void
 sources_changed_cb (GfInputSourceManager *manager,
                     gpointer              user_data)
 {
 }
 
 static void
+current_source_changed_cb (GfInputSourceManager *manager,
+                           GfInputSource        *old_source,
+                           gpointer              user_data)
+{
+  GfInputSources *sources;
+
+  sources = GF_INPUT_SOURCES (user_data);
+
+  update_status_icon (sources);
+}
+
+static void
+status_icon_bg_color_changed_cb (GSettings *settings,
+                                 gchar     *key,
+                                 gpointer   user_data)
+{
+  GfInputSources *sources;
+
+  sources = GF_INPUT_SOURCES (user_data);
+
+  update_status_icon (sources);
+}
+
+static void
+status_icon_fg_color_changed_cb (GSettings *settings,
+                                 gchar     *key,
+                                 gpointer   user_data)
+{
+  GfInputSources *sources;
+
+  sources = GF_INPUT_SOURCES (user_data);
+
+  update_status_icon (sources);
+}
+
+static void
+font_name_changed_cb (GSettings *settings,
+                      gchar     *key,
+                      gpointer   user_data)
+{
+  GfInputSources *sources;
+
+  sources = GF_INPUT_SOURCES (user_data);
+
+  update_status_icon (sources);
+}
+
+static void
 gf_input_sources_dispose (GObject *object)
 {
   GfInputSources *sources;
@@ -47,6 +282,12 @@ gf_input_sources_dispose (GObject *object)
   g_clear_object (&sources->ibus_manager);
   g_clear_object (&sources->input_source_manager);
 
+  g_clear_object (&sources->input_sources_settings);
+  g_clear_object (&sources->gnome_desktop_settings);
+
+  g_clear_object (&sources->current_source);
+  g_clear_object (&sources->status_icon);
+
   G_OBJECT_CLASS (gf_input_sources_parent_class)->dispose (object);
 }
 
@@ -66,9 +307,32 @@ gf_input_sources_init (GfInputSources *sources)
   sources->ibus_manager = gf_ibus_manager_new ();
   sources->input_source_manager = gf_input_source_manager_new (sources->ibus_manager);
 
+  sources->input_sources_settings = g_settings_new (INPUT_SOURCES_SCHEMA);
+  sources->gnome_desktop_settings = g_settings_new (GNOME_DESKTOP_SCHEMA);
+
   g_signal_connect (sources->input_source_manager, "sources-changed",
                     G_CALLBACK (sources_changed_cb), sources);
 
+  g_signal_connect (sources->input_source_manager, "current-source-changed",
+                    G_CALLBACK (current_source_changed_cb), sources);
+
+  {
+    g_signal_connect (sources->input_sources_settings,
+                      "changed::status-icon-bg-color",
+                      G_CALLBACK (status_icon_bg_color_changed_cb),
+                      sources);
+
+    g_signal_connect (sources->input_sources_settings,
+                      "changed::status-icon-fg-color",
+                      G_CALLBACK (status_icon_fg_color_changed_cb),
+                      sources);
+
+    g_signal_connect (sources->gnome_desktop_settings, "changed::font-name",
+                      G_CALLBACK (font_name_changed_cb), sources);
+
+    update_status_icon (sources);
+  }
+
   gf_input_source_manager_reload (sources->input_source_manager);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]