[gnome-flashback] input-sources: generate svg icon instead of pixbuf
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] input-sources: generate svg icon instead of pixbuf
- Date: Wed, 23 Nov 2016 12:04:49 +0000 (UTC)
commit cc1f38fe996fbe8b27a3049b7bea0b36b3d9645b
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Wed Nov 23 13:54:34 2016 +0200
input-sources: generate svg icon instead of pixbuf
...gnome.gnome-flashback.input-sources.gschema.xml | 17 +-
.../libinput-sources/gf-input-sources.c | 420 +++++++++++++++-----
2 files changed, 330 insertions(+), 107 deletions(-)
---
diff --git a/data/schemas/org.gnome.gnome-flashback.input-sources.gschema.xml
b/data/schemas/org.gnome.gnome-flashback.input-sources.gschema.xml
index 37faaeb..48272ca 100644
--- a/data/schemas/org.gnome.gnome-flashback.input-sources.gschema.xml
+++ b/data/schemas/org.gnome.gnome-flashback.input-sources.gschema.xml
@@ -5,17 +5,28 @@
<schema id="org.gnome.gnome-flashback.input-sources.status-icon"
path="/org/gnome/gnome-flashback/input-sources/status-icon/">
<key name="bg-color" type="s">
<default>'#FFFFFF'</default>
- <summary>The background color for the status icon.</summary>
+ <summary>The background color</summary>
</key>
<key name="fg-color" type="s">
<default>'#000000'</default>
- <summary>The foreground color for the status icon.</summary>
+ <summary>The foreground color</summary>
</key>
<key name="font-family" type="s">
<default>'Cantarell'</default>
- <summary>Font family</summary>
+ <summary>The font family</summary>
+ </key>
+
+ <key name="font-weight" type="i">
+ <range min="100" max="1000"/>
+ <default>500</default>
+ <summary>The font weight</summary>
+ </key>
+
+ <key name="symbolic" type="b">
+ <default>false</default>
+ <summary>Symbolic</summary>
</key>
</schema>
</schemalist>
diff --git a/gnome-flashback/libinput-sources/gf-input-sources.c
b/gnome-flashback/libinput-sources/gf-input-sources.c
index 0892274..15546c1 100644
--- a/gnome-flashback/libinput-sources/gf-input-sources.c
+++ b/gnome-flashback/libinput-sources/gf-input-sources.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Alberts Muktupāvels
+ * Copyright (C) 2015-2016 Alberts Muktupāvels
*
* 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
@@ -20,10 +20,8 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <libgnome-desktop/gnome-xkb-info.h>
-#include <pango/pangocairo.h>
-
-#define _XOPEN_SOURCE
-#include <math.h>
+#include <locale.h>
+#include <utime.h>
#include "gf-ibus-manager.h"
#include "gf-input-sources.h"
@@ -41,141 +39,329 @@ struct _GfInputSources
GSettings *status_icon_settings;
+ gchar *icon_theme_path;
+
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)
+static GString *
+cairo_path_to_string (cairo_path_t *path,
+ cairo_matrix_t *matrix)
{
- 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->status_icon_settings, "bg-color");
-
- gdk_rgba_parse (&rgba, color);
- g_free (color);
-
- gdk_cairo_set_source_rgba (cr, &rgba);
- cairo_fill_preserve (cr);
+ gchar *locale;
+ GString *string;
+ gint i;
+
+ locale = g_strdup (setlocale (LC_NUMERIC, NULL));
+ setlocale (LC_NUMERIC, "C");
+
+ string = g_string_new (NULL);
+ for (i = 0; i < path->num_data; i += path->data[i].header.length)
+ {
+ cairo_path_data_t *data;
+ gdouble x1, y1;
+ gdouble x2, y2;
+ gdouble x3, y3;
+
+ data = &path->data[i];
+
+ switch (data->header.type)
+ {
+ case CAIRO_PATH_MOVE_TO:
+ x1 = data[1].point.x;
+ y1 = data[1].point.y;
+
+ cairo_matrix_transform_point (matrix, &x1, &y1);
+
+ g_string_append_printf (string, "M %f,%f ", x1, y1);
+ break;
+
+ case CAIRO_PATH_LINE_TO:
+ x1 = data[1].point.x;
+ y1 = data[1].point.y;
+
+ cairo_matrix_transform_point (matrix, &x1, &y1);
+
+ g_string_append_printf (string, "L %f,%f ", x1, y1);
+ break;
+
+ case CAIRO_PATH_CURVE_TO:
+ x1 = data[1].point.x;
+ y1 = data[1].point.y;
+ x2 = data[2].point.x;
+ y2 = data[2].point.y;
+ x3 = data[3].point.x;
+ y3 = data[3].point.y;
+
+ cairo_matrix_transform_point (matrix, &x1, &y1);
+ cairo_matrix_transform_point (matrix, &x2, &y2);
+ cairo_matrix_transform_point (matrix, &x3, &y3);
+
+ g_string_append_printf (string, "C %f,%f %f,%f %f,%f ",
+ x1, y1, x2, y2, x3, y3);
+ break;
+
+ case CAIRO_PATH_CLOSE_PATH:
+ g_string_append (string, "Z ");
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ setlocale (LC_NUMERIC, locale);
+ g_free (locale);
+
+ return string;
}
-static void
-draw_text (GfInputSources *sources,
- cairo_t *cr,
- gint size)
+static PangoLayout *
+get_pango_layout (const gchar *text,
+ const gchar *font_family,
+ gint font_weight,
+ gint font_size)
{
- gchar *font_name;
+ GdkScreen *screen;
+ PangoContext *context;
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->status_icon_settings, "font-family");
- font_desc = pango_font_description_from_string (font_name);
- g_free (font_name);
- pango_font_description_set_weight (font_desc, PANGO_WEIGHT_MEDIUM);
+ screen = gdk_screen_get_default ();
+ context = gdk_pango_context_get_for_screen (screen);
+ font_desc = pango_font_description_new ();
- font_size = PANGO_SCALE * size * 0.5;
- pango_font_description_set_absolute_size (font_desc, font_size);
+ pango_font_description_set_family (font_desc, font_family);
+ pango_font_description_set_absolute_size (font_desc, font_size * PANGO_SCALE);
+ pango_font_description_set_weight (font_desc, font_weight);
+ pango_font_description_set_stretch (font_desc, PANGO_STRETCH_NORMAL);
+ pango_font_description_set_style (font_desc, PANGO_STYLE_NORMAL);
+ pango_font_description_set_variant (font_desc, PANGO_VARIANT_NORMAL);
- layout = pango_cairo_create_layout (cr);
+ layout = pango_layout_new (context);
+ g_object_unref (context);
+ pango_layout_set_text (layout, text, -1);
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);
+ return layout;
+}
+
+static cairo_path_t *
+get_cairo_path (const gchar *text,
+ const gchar *font_family,
+ gint font_weight,
+ gint font_size,
+ cairo_matrix_t *matrix)
+{
+ PangoLayout *layout;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ gint width;
+ gint height;
+ gdouble scale;
+ cairo_path_t *path;
- pango_layout_get_pixel_size (layout, &text_width, &text_height);
+ layout = get_pango_layout (text, font_family, font_weight, font_size);
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 16, 16);
+ cr = cairo_create (surface);
- factor = MIN ((size - (size * 0.1) * 2) / text_width, 1.0);
- cairo_scale (cr, factor, factor);
+ pango_layout_get_pixel_size (layout, &width, &height);
- center = size / 2.0;
- x = center - text_width * factor / 2.0;
- y = center - text_height * factor / 2.0;
- cairo_move_to (cr, x, y);
+ scale = MIN (1.0, MIN (14.0 / width, 14.0 / height));
+ cairo_scale (cr, scale, scale);
- color = g_settings_get_string (sources->status_icon_settings, "fg-color");
- gdk_rgba_parse (&rgba, color);
- g_free (color);
+ cairo_move_to (cr, (16 - width * scale) / 2.0, (16 - height * scale) / 2.0);
- gdk_cairo_set_source_rgba (cr, &rgba);
+ pango_cairo_layout_path (cr, layout);
+ path = cairo_copy_path (cr);
+ cairo_get_matrix (cr, matrix);
- pango_cairo_show_layout (cr, layout);
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
g_object_unref (layout);
+
+ return path;
+}
+
+static gchar *
+generate_path_description (const gchar *text,
+ const gchar *font_family,
+ gint font_weight,
+ gint font_size)
+{
+ cairo_path_t *path;
+ cairo_matrix_t matrix;
+ GString *string;
+
+ path = get_cairo_path (text, font_family, font_weight, font_size, &matrix);
+ string = cairo_path_to_string (path, &matrix);
+ cairo_path_destroy (path);
+
+ return g_string_free (string, FALSE);
+}
+
+static GString *
+generate_svg (const gchar *text,
+ const gchar *font_family,
+ gint font_weight,
+ gint font_size,
+ const gchar *bg_color,
+ const gchar *fg_color,
+ gboolean symbolic)
+{
+ gchar *path_d;
+ GString *svg;
+
+ path_d = generate_path_description (text, font_family, font_weight, font_size);
+ svg = g_string_new ("<?xml version='1.0' encoding='utf-8' standalone='no'?>");
+
+ g_string_append (svg,
+ "<svg xmlns='http://www.w3.org/2000/svg' "
+ "width='16' height='16' viewBox='0 0 16 16'>");
+
+ if (symbolic)
+ {
+ g_string_append (svg, "<defs><mask id='m'>");
+ g_string_append (svg,
+ "<rect width='16' height='16' "
+ "style='fill:#ffffff!important'/>");
+
+ g_string_append_printf (svg,
+ "<path d='%s' style='fill:#000000!important'/>",
+ path_d);
+
+ g_string_append (svg, "</mask></defs>");
+ }
+
+ g_string_append_printf (svg,
+ "<rect x='0' y='0' width='16' height='16' "
+ "rx='2.0' ry='2.0' mask='%s' style='fill:%s;'/>",
+ symbolic ? "url(#m)" : "none",
+ symbolic ? "#bebebe" : bg_color);
+
+ if (!symbolic)
+ {
+ g_string_append_printf (svg, "<path d='%s' style='fill:%s'/>",
+ path_d, fg_color);
+ }
+
+ g_free (path_d);
+
+ return g_string_append (svg, "</svg>");
}
static void
-update_status_icon_pixbuf (GfInputSources *sources)
+ensure_file_exists (const gchar *icon_theme_path,
+ const gchar *icon_name,
+ const gchar *text,
+ const gchar *font_family,
+ gint font_weight,
+ gint font_size,
+ const gchar *bg_color,
+ const gchar *fg_color,
+ gboolean symbolic)
{
- gint size;
- cairo_surface_t *surface;
- cairo_t *cr;
- GdkPixbuf *pixbuf;
+ gchar *filename;
+ gchar *path;
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS
- size = gtk_status_icon_get_size (sources->status_icon);
- G_GNUC_END_IGNORE_DEPRECATIONS
+ filename = g_strdup_printf ("%s.svg", icon_name);
+ path = g_build_filename (icon_theme_path, "hicolor", "scalable",
+ "status", filename, NULL);
- if (size <= 0)
- return;
+ if (!g_file_test (path, G_FILE_TEST_EXISTS))
+ {
+ GFile *file;
+ GFile *parent;
+ GString *svg;
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, size, size);
- cr = cairo_create (surface);
+ file = g_file_new_for_path (path);
+ parent = g_file_get_parent (file);
+ svg = generate_svg (text, font_family, font_weight, font_size,
+ bg_color, fg_color, symbolic);
- draw_background (sources, cr, size);
- draw_text (sources, cr, size);
+ g_file_make_directory_with_parents (parent, NULL, NULL);
+ g_file_replace_contents (file, svg->str, svg->len, NULL, FALSE,
+ G_FILE_CREATE_NONE, NULL, NULL, NULL);
- cairo_destroy (cr);
+ utime (icon_theme_path, NULL);
+ gtk_icon_theme_rescan_if_needed (gtk_icon_theme_get_default ());
- pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, size, size);
- cairo_surface_destroy (surface);
+ g_string_free (svg, TRUE);
+ g_object_unref (parent);
+ g_object_unref (file);
+ }
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS
- gtk_status_icon_set_from_pixbuf (sources->status_icon, pixbuf);
- G_GNUC_END_IGNORE_DEPRECATIONS
+ g_free (filename);
+ g_free (path);
+}
- g_object_unref (pixbuf);
+static gchar *
+generate_icon_name (const gchar *text,
+ const gchar *font_family,
+ gint font_weight,
+ gint font_size,
+ const gchar *bg_color,
+ const gchar *fg_color,
+ gboolean symbolic)
+{
+ gchar *str;
+ gchar *hash;
+ GString *icon_name;
+
+ str = g_strdup_printf ("%s-%s-%d-%d-%s-%s", text,
+ font_family, font_weight, font_size,
+ bg_color, fg_color);
+
+ hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, str, -1);
+ g_free (str);
+
+ icon_name = g_string_new (hash);
+ g_free (hash);
+
+ if (symbolic)
+ g_string_append (icon_name, "-symbolic");
+
+ return g_string_free (icon_name, FALSE);
+}
+
+static gchar *
+get_icon_name (GfInputSources *sources)
+{
+ const gchar *text;
+ gint font_size;
+ gchar *font_family;
+ gint font_weight;
+ gchar *bg_color;
+ gchar *fg_color;
+ gboolean symbolic;
+ gchar *icon_name;
+
+ text = gf_input_source_get_short_name (sources->current_source);
+ font_size = 8;
+
+ font_family = g_settings_get_string (sources->status_icon_settings, "font-family");
+ font_weight = g_settings_get_int (sources->status_icon_settings, "font-weight");
+ bg_color = g_settings_get_string (sources->status_icon_settings, "bg-color");
+ fg_color = g_settings_get_string (sources->status_icon_settings, "fg-color");
+ symbolic = g_settings_get_boolean (sources->status_icon_settings, "symbolic");
+
+ icon_name = generate_icon_name (text, font_family, font_weight, font_size,
+ bg_color, fg_color, symbolic);
+
+ ensure_file_exists (sources->icon_theme_path, icon_name, text,
+ font_family, font_weight, font_size,
+ bg_color, fg_color, symbolic);
+
+ g_free (font_family);
+ g_free (bg_color);
+ g_free (fg_color);
+
+ return icon_name;
}
static void
@@ -374,6 +560,7 @@ update_status_icon (GfInputSources *sources)
GList *input_sources;
IBusPropList *prop_list;
const gchar *display_name;
+ gchar *icon_name;
manager = sources->input_source_manager;
@@ -414,12 +601,15 @@ update_status_icon (GfInputSources *sources)
}
display_name = gf_input_source_get_display_name (source);
+ icon_name = get_icon_name (sources);
+
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_status_icon_set_title (sources->status_icon, _("Keyboard"));
gtk_status_icon_set_tooltip_text (sources->status_icon, display_name);
+ gtk_status_icon_set_from_icon_name (sources->status_icon, icon_name);
G_GNUC_END_IGNORE_DEPRECATIONS
- update_status_icon_pixbuf (sources);
+ g_free (icon_name);
}
static void
@@ -464,6 +654,18 @@ gf_input_sources_dispose (GObject *object)
}
static void
+gf_input_sources_finalize (GObject *object)
+{
+ GfInputSources *sources;
+
+ sources = GF_INPUT_SOURCES (object);
+
+ g_clear_pointer (&sources->icon_theme_path, g_free);
+
+ G_OBJECT_CLASS (gf_input_sources_parent_class)->finalize (object);
+}
+
+static void
gf_input_sources_class_init (GfInputSourcesClass *sources_class)
{
GObjectClass *object_class;
@@ -471,16 +673,27 @@ 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)
{
+ const gchar *cache_dir;
+
sources->ibus_manager = gf_ibus_manager_new ();
sources->input_source_manager = gf_input_source_manager_new (sources->ibus_manager);
sources->status_icon_settings = g_settings_new (STATUS_ICON_SCHEMA);
+ cache_dir = g_get_user_cache_dir ();
+ sources->icon_theme_path = g_build_filename (cache_dir, "gnome-flashback",
+ "input-sources", "icons",
+ NULL);
+
+ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
+ sources->icon_theme_path);
+
g_signal_connect (sources->input_source_manager, "sources-changed",
G_CALLBACK (sources_changed_cb), sources);
@@ -491,7 +704,6 @@ gf_input_sources_init (GfInputSources *sources)
G_CALLBACK (status_icon_settings_changed_cb), sources);
gf_input_source_manager_reload (sources->input_source_manager);
- update_status_icon (sources);
}
GfInputSources *
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]