[gnome-flashback/wip/segeiger/statusicon: 4/4] input-sources: implement status icon with pango and cairo



commit f72dce4a398343bd59bb0a6e3b176133c12bd078
Author: Sebastian Geiger <sbastig gmx net>
Date:   Wed Sep 30 14:54:55 2015 +0200

    input-sources: implement status icon with pango and cairo

 .../libinput-sources/gf-input-sources.c            |  207 ++++++++++++++++++++
 1 files changed, 207 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..bad5e02 100644
--- a/gnome-flashback/libinput-sources/gf-input-sources.c
+++ b/gnome-flashback/libinput-sources/gf-input-sources.c
@@ -17,9 +17,33 @@
 
 #include "config.h"
 
+#define _XOPEN_SOURCE
+
+#include <gtk/gtk.h>
+
 #include "gf-ibus-manager.h"
 #include "gf-input-sources.h"
 #include "gf-input-source-manager.h"
+#include "gf-input-source.h"
+
+#include <pango/pangocairo.h>
+#include <math.h>
+
+#define INPUT_SOURCES_SCHEMA org.gnome.gnome-flashback.input-sources
+#define SIZE 256
+
+struct IconInfo_
+{
+  gchar   *font_name,
+          *short_name;
+
+  gdouble  font_size;
+
+  GdkRGBA  fg_color,
+           bg_color;
+};
+
+typedef struct IconInfo_ IconInfo;
 
 struct _GfInputSources
 {
@@ -27,10 +51,121 @@ struct _GfInputSources
 
   GfIBusManager        *ibus_manager;
   GfInputSourceManager *input_source_manager;
+
+  GtkStatusIcon        *status_icon;
+
+  IconInfo             *icon_info;
 };
 
 G_DEFINE_TYPE (GfInputSources, gf_input_sources, G_TYPE_OBJECT)
 
+static void draw_short_name (cairo_t *cr, IconInfo *info)
+{
+  gdouble text_width, text_y;
+  gdouble pango_font_size;
+  gdouble baseline;
+  gdouble x, y;
+
+  gint center;
+
+  gchar *short_name, *font_name;
+
+  PangoLayout *layout;
+  PangoFontDescription *font_description;
+  PangoRectangle ink_rect, logical_rect;
+
+  short_name = info->short_name;
+  font_name = info->font_name;
+
+  font_description = pango_font_description_new ();
+  pango_font_description_set_family (font_description, font_name);
+  pango_font_description_set_weight (font_description, PANGO_WEIGHT_BOLD);
+  pango_font_size = SIZE * info->font_size * PANGO_SCALE;
+  pango_font_description_set_absolute_size (font_description,
+                                            pango_font_size);
+
+  layout = pango_cairo_create_layout (cr);
+  pango_layout_set_font_description (layout, font_description);
+  pango_layout_set_text (layout, short_name, -1);
+
+  pango_layout_get_extents (layout, &ink_rect, &logical_rect);
+
+  text_width = ink_rect.width / (gdouble) PANGO_SCALE;
+  text_y = ink_rect.y / (gdouble) PANGO_SCALE;
+
+  baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
+
+  center = SIZE / 2;
+  y = center + baseline / 2.0 - text_y / 2.0;
+  x = (SIZE - text_width) / 2.0 - (ink_rect.x / PANGO_SCALE);
+
+  cairo_set_source_rgb (cr,
+                        info->bg_color.red,
+                        info->bg_color.green,
+                        info->bg_color.blue);
+  cairo_move_to (cr, x, y);
+  pango_cairo_show_layout_line (cr, pango_layout_get_line (layout, 0));
+
+  g_object_unref (layout);
+  pango_font_description_free (font_description);
+}
+
+static void draw_background (cairo_t *cr, IconInfo *info)
+{
+  /* Draw a background */
+  cairo_set_source_rgba (cr,
+                        info->bg_color.red,
+                        info->bg_color.green,
+                        info->bg_color.blue,
+                        0);
+  cairo_rectangle (cr, 0, 0, SIZE, SIZE);
+  cairo_fill (cr);
+}
+
+static void draw_rounded_rectangle (cairo_t *cr, IconInfo *info)
+{
+  double
+    x             = 10,
+    y             = 10,
+    width         = SIZE - 2*x,
+    height        = SIZE - 2*y,
+    aspect        = 1.0,             /* aspect ratio */
+    corner_radius = height / 10.0;   /* and corner curvature radius */
+
+  double radius = corner_radius / aspect;
+  double 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);
+
+  cairo_set_source_rgb (cr,
+                        info->fg_color.red,
+                        info->fg_color.green,
+                        info->fg_color.blue);
+  cairo_fill_preserve (cr);
+}
+
+static GdkPixbuf *get_pixbuf_for_icon_info(IconInfo *info)
+{
+  cairo_surface_t *surface;
+  cairo_t * cr;
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, SIZE, SIZE);
+  cr = cairo_create (surface);
+
+  draw_background (cr, info);
+  draw_rounded_rectangle (cr, info);
+  draw_short_name (cr, info);
+
+  return gdk_pixbuf_get_from_surface (surface, 0, 0, SIZE, SIZE);
+
+}
+
+
 static void
 sources_changed_cb (GfInputSourceManager *manager,
                     gpointer              user_data)
@@ -38,6 +173,48 @@ sources_changed_cb (GfInputSourceManager *manager,
 }
 
 static void
+status_icon_cliced_cb (GtkStatusIcon *icon,
+                       GdkEvent      *event,
+                       gpointer       user_data)
+{
+  g_warning ("NOT IMPLEMENTED: status icon clicked callback");
+}
+
+static void
+current_source_changed_cb (GfInputSourceManager *manager,
+                           GfInputSource        *source,
+                           GfInputSources       *sources)
+{
+  GdkPixbuf *pixbuf;
+  g_message ("current_source_changed");
+
+  gtk_status_icon_set_tooltip_text (sources->status_icon,
+                                    gf_input_source_get_display_name (source));
+
+  sources->icon_info->short_name = g_strdup (gf_input_source_get_short_name (source));
+
+  pixbuf = get_pixbuf_for_icon_info (sources->icon_info);
+
+  gtk_status_icon_set_from_pixbuf (sources->status_icon, pixbuf);
+
+}
+
+static GtkStatusIcon*
+gf_input_sources_init_status_icon (GfInputSources *sources)
+{
+  GtkStatusIcon *status_icon;
+
+  status_icon = gtk_status_icon_new ();
+
+  g_signal_connect (status_icon, "activate",
+                    G_CALLBACK (status_icon_cliced_cb), sources);
+  g_signal_connect (sources->input_source_manager, "current-source-changed",
+  G_CALLBACK (current_source_changed_cb), sources);
+
+  return status_icon;
+}
+
+static void
 gf_input_sources_dispose (GObject *object)
 {
   GfInputSources *sources;
@@ -51,6 +228,16 @@ gf_input_sources_dispose (GObject *object)
 }
 
 static void
+gf_input_sources_finalize (GObject *object)
+{
+  GfInputSources *sources;
+
+  sources = GF_INPUT_SOURCES (object);
+
+  g_free (sources->icon_info);
+}
+
+static void
 gf_input_sources_class_init (GfInputSourcesClass *sources_class)
 {
   GObjectClass *object_class;
@@ -58,13 +245,33 @@ gf_input_sources_class_init (GfInputSourcesClass *sources_class)
   object_class = G_OBJECT_CLASS (sources_class);
 
   object_class->dispose = gf_input_sources_dispose;
+  object_class->finalize= gf_input_sources_finalize;
 }
 
 static void
 gf_input_sources_init (GfInputSources *sources)
 {
+  GdkRGBA fg, bg;
+
   sources->ibus_manager = gf_ibus_manager_new ();
   sources->input_source_manager = gf_input_source_manager_new (sources->ibus_manager);
+  sources->status_icon = gf_input_sources_init_status_icon (sources);
+  sources->icon_info = g_new0 (IconInfo, 1);
+
+  fg.red = 1.0;
+  fg.green= 1.0;
+  fg.blue = 1.0;
+  fg.alpha = 1.0;
+
+  bg.red = 0.0;
+  bg.green= 0.0;
+  bg.blue = 0.0;
+  bg.alpha = 1.0;
+
+  sources->icon_info->font_name = g_strdup ("Ubuntu");
+  sources->icon_info->fg_color = fg;
+  sources->icon_info->bg_color = bg;
+  sources->icon_info->font_size = 0.6;
 
   g_signal_connect (sources->input_source_manager, "sources-changed",
                     G_CALLBACK (sources_changed_cb), sources);


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