summaryrefslogtreecommitdiff
path: root/gtk-themes/ContrastHigh/create-contrasthigh.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk-themes/ContrastHigh/create-contrasthigh.c')
-rw-r--r--gtk-themes/ContrastHigh/create-contrasthigh.c381
1 files changed, 381 insertions, 0 deletions
diff --git a/gtk-themes/ContrastHigh/create-contrasthigh.c b/gtk-themes/ContrastHigh/create-contrasthigh.c
new file mode 100644
index 00000000..4902d076
--- /dev/null
+++ b/gtk-themes/ContrastHigh/create-contrasthigh.c
@@ -0,0 +1,381 @@
+#include <cairo/cairo.h>
+#include <gio/gio.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdk.h>
+#include <glib.h>
+#include <string.h>
+#include <math.h>
+
+GFile *gnome_dir = NULL;
+GFile *hc_dir = NULL;
+
+static const gint icon_sizes[] = {
+ 16, 22, 24, 32, 48, 256
+};
+
+static char *
+replace_str (char *str,
+ const char *substr,
+ const char *new_substr)
+{
+ static char buf[4096];
+ char *ptr;
+
+ /* if we didn't find the substring, return */
+ if (!(ptr = (char*)strstr (str, substr)))
+ return str;
+
+ /* copy up to the substring */
+ strncpy (buf, str, ptr - str);
+ buf[ptr - str] = '\0';
+
+ if (strlen (substr) >=strlen (new_substr))
+ {
+ sprintf (buf + (ptr - str), "%s%s", new_substr, ptr + strlen (substr));
+ }
+ else
+ {
+ static char buf2[4096];
+
+ strncpy (buf2, str, ptr - str + strlen (substr));
+ buf2[ptr - str + strlen (substr)] = '\0';
+
+ sprintf (buf2 + (ptr - str), "%s%s", new_substr, ptr + strlen (substr));
+ strncpy (buf, buf2, strlen (buf));
+ }
+
+ return buf;
+}
+
+static gchar *
+ensure_dest_path (GFile *file,
+ gint icon_size)
+{
+ gchar *str, *str2, *size_string, *dest_path;
+ GFile *dest_file, *dest_dir, *tmp;
+
+ str = g_file_get_relative_path (gnome_dir, file);
+ tmp = g_file_resolve_relative_path (hc_dir, str);
+ g_free (str);
+
+ str = g_file_get_path (tmp);
+ size_string = g_strdup_printf ("%dx%d", icon_size, icon_size);
+ str2 = replace_str (str, "-symbolic.svg", ".png");
+ dest_path = replace_str (str2, "scalable", size_string);
+
+ dest_file = g_file_new_for_path (dest_path);
+ dest_dir = g_file_get_parent (dest_file);
+
+ g_file_make_directory_with_parents (dest_dir, NULL, NULL);
+
+ g_object_unref (dest_file);
+ g_object_unref (dest_dir);
+ g_object_unref (tmp);
+ g_free (str);
+ g_free (size_string);
+
+ return dest_path;
+}
+
+static void
+optimize_png (const gchar *png_path)
+{
+ gchar *cmd = g_strconcat ("optipng -quiet", " ", png_path, NULL);
+ g_spawn_command_line_async (cmd, NULL);
+ g_free (cmd);
+}
+
+static GdkPixbuf *
+get_recolored_svg (GFile *file,
+ gint icon_size)
+{
+ gchar *data, *str;
+ GdkPixbuf *pixbuf;
+ GInputStream *stream;
+
+ str = g_file_get_path (file);
+ data = g_strconcat ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ "<svg version=\"1.1\"\n"
+ " xmlns=\"http://www.w3.org/2000/svg\"\n"
+ " xmlns:xi=\"http://www.w3.org/2001/XInclude\"\n"
+ " width=\"16\"\n"
+ " height=\"16\">\n"
+ " <style type=\"text/css\">\n"
+ " rect,path {\n"
+ " fill: black !important;\n"
+ " }\n"
+ " .warning {\n"
+ " fill: #f57900 !important;\n"
+ " }\n"
+ " .error {\n"
+ " fill: #cc0000 !important;\n"
+ " }\n"
+ " .success {\n"
+ " fill: #4e9a06 !important;\n"
+ " }\n"
+ " </style>\n"
+ " <xi:include href=\"", str, "\"/>\n"
+ "</svg>",
+ NULL);
+
+ stream = g_memory_input_stream_new_from_data (data, -1, g_free);
+ pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream,
+ icon_size, icon_size,
+ TRUE, NULL, NULL);
+ g_object_unref (stream);
+ g_free (str);
+
+ return pixbuf;
+}
+
+/* taken from gdkcairo.c */
+static gboolean
+_gdk_cairo_surface_extents (cairo_surface_t *surface,
+ GdkRectangle *extents)
+{
+ double x1, x2, y1, y2;
+ cairo_t *cr;
+
+ g_return_val_if_fail (surface != NULL, FALSE);
+ g_return_val_if_fail (extents != NULL, FALSE);
+
+ cr = cairo_create (surface);
+ cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
+ cairo_destroy (cr);
+
+ x1 = floor (x1);
+ y1 = floor (y1);
+ x2 = ceil (x2);
+ y2 = ceil (y2);
+ x2 -= x1;
+ y2 -= y1;
+
+ if (x1 < G_MININT || x1 > G_MAXINT ||
+ y1 < G_MININT || y1 > G_MAXINT ||
+ x2 > G_MAXINT || y2 > G_MAXINT)
+ {
+ extents->x = extents->y = extents->width = extents->height = 0;
+ return FALSE;
+ }
+
+ extents->x = x1;
+ extents->y = y1;
+ extents->width = x2;
+ extents->height = y2;
+
+ return TRUE;
+}
+
+/* This function originally from Jean-Edouard Lachand-Robert, and
+ * available at www.codeguru.com. Simplified for our needs, not sure
+ * how much of the original code left any longer. Now handles just
+ * one-bit deep bitmaps (in Window parlance, ie those that GDK calls
+ * bitmaps (and not pixmaps), with zero pixels being transparent.
+ *
+ * Changed again here from the GDK version to use an 8-bit surface instead
+ * of a 1-bit bitmap.
+ */
+static cairo_region_t *
+_gdk_cairo_region_create_from_surface (cairo_surface_t *surface)
+{
+ cairo_region_t *region;
+ GdkRectangle extents, rect;
+ cairo_surface_t *image;
+ cairo_t *cr;
+ gint x, y, stride;
+ guchar *data;
+
+ _gdk_cairo_surface_extents (surface, &extents);
+
+ if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR)
+ return cairo_region_create_rectangle (&extents);
+
+ if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_IMAGE ||
+ cairo_image_surface_get_format (surface) != CAIRO_FORMAT_A8)
+ {
+ /* coerce to an A8 image */
+ image = cairo_image_surface_create (CAIRO_FORMAT_A8,
+ extents.width, extents.height);
+ cr = cairo_create (image);
+ cairo_set_source_surface (cr, surface, -extents.x, -extents.y);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ }
+ else
+ image = cairo_surface_reference (surface);
+
+ data = cairo_image_surface_get_data (image);
+ stride = cairo_image_surface_get_stride (image);
+
+ region = cairo_region_create ();
+
+ for (y = 0; y < extents.height; y++)
+ {
+ for (x = 0; x < extents.width; x++)
+ {
+ /* Search for a continuous range of "non transparent pixels"*/
+ gint x0 = x;
+ while (x < extents.width)
+ {
+ guint8 alpha = data[x];
+ if (alpha < 24)
+ /* This pixel is "transparent"*/
+ break;
+ x++;
+ }
+
+ if (x > x0)
+ {
+ /* Add the pixels (x0, y) to (x, y+1) as a new rectangle
+ * in the region
+ */
+ rect.x = x0;
+ rect.width = x - x0;
+ rect.y = y;
+ rect.height = 1;
+
+ cairo_region_union_rectangle (region, &rect);
+ }
+ }
+ data += stride;
+ }
+
+ cairo_surface_destroy (image);
+
+ cairo_region_translate (region, extents.x, extents.y);
+
+ return region;
+}
+
+static void
+write_png_theme (GList *svg_files,
+ gint icon_size)
+{
+ GList *l;
+
+ g_print ("Writing size: %dx%d\n", icon_size, icon_size);
+
+ for (l = svg_files; l != NULL; l = l->next)
+ {
+ GFile *file;
+ gchar *dest_path;
+ GdkPixbuf *pixbuf;
+ gint border_offset;
+ cairo_surface_t *surface;
+ cairo_region_t *region;
+ cairo_t *cr;
+
+ file = l->data;
+ border_offset = (gint) floor (icon_size / 16);
+ pixbuf = get_recolored_svg (file, icon_size - 2.0 * border_offset);
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ icon_size, icon_size);
+ cr = cairo_create (surface);
+
+ gdk_cairo_set_source_pixbuf (cr, pixbuf,
+ border_offset, border_offset);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ region = _gdk_cairo_region_create_from_surface (surface);
+ cairo_surface_destroy (surface);
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ icon_size, icon_size);
+ cr = cairo_create (surface);
+
+ cairo_save (cr);
+ gdk_cairo_region (cr, region);
+
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
+ cairo_set_line_width (cr, 2.0 * border_offset);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ gdk_cairo_set_source_pixbuf (cr, pixbuf,
+ border_offset, border_offset);
+ cairo_paint (cr);
+
+ dest_path = ensure_dest_path (file, icon_size);
+ cairo_surface_write_to_png (surface, dest_path);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+ cairo_region_destroy (region);
+ g_object_unref (pixbuf);
+
+ optimize_png (dest_path);
+ }
+}
+
+static void
+process (int argc,
+ char **argv)
+{
+ GList *svg_files = NULL;
+ GQueue *descend_into_files;
+ GFile *current_dir, *symbolic_theme, *file;
+ gchar *str;
+ gint idx;
+
+ str = g_get_current_dir ();
+ current_dir = g_file_new_for_path (str);
+ g_free (str);
+
+ symbolic_theme = g_file_new_for_commandline_arg (argv[1]);
+ gnome_dir = g_file_resolve_relative_path (symbolic_theme, "gnome");
+ hc_dir = g_file_resolve_relative_path (current_dir, "icons");
+ g_object_unref (symbolic_theme);
+
+ descend_into_files = g_queue_new ();
+ g_queue_push_tail (descend_into_files, g_object_ref (gnome_dir));
+ while ((file = g_queue_pop_head (descend_into_files)) != NULL)
+ {
+ GFileInfo *child_info;
+ GFileEnumerator *enumerator =
+ g_file_enumerate_children (file, "standard::name,standard::type,standard::content-type",
+ G_FILE_QUERY_INFO_NONE, NULL, NULL);
+
+ while ((child_info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL)
+ {
+ if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY)
+ g_queue_push_tail (descend_into_files, g_file_resolve_relative_path (file, g_file_info_get_name (child_info)));
+ else if (g_content_type_is_a (g_file_info_get_content_type (child_info), "image/svg+xml"))
+ svg_files = g_list_prepend (svg_files, g_file_resolve_relative_path (file, g_file_info_get_name (child_info)));
+
+ g_object_unref (child_info);
+ }
+
+ g_object_unref (enumerator);
+ g_object_unref (file);
+ }
+
+ for (idx = 0; idx < G_N_ELEMENTS (icon_sizes); idx++)
+ write_png_theme (svg_files, icon_sizes[idx]);
+
+ g_list_free_full (svg_files, g_object_unref);
+ g_queue_free (descend_into_files);
+ g_clear_object (&gnome_dir);
+ g_clear_object (&hc_dir);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ if (argc == 1)
+ {
+ g_critical ("Location of gnome-icon-theme-symbolic repo must be given");
+ return 0;
+ }
+
+ g_type_init ();
+ process (argc, argv);
+ g_spawn_command_line_async ("./create-makefiles.sh", NULL);
+
+ return 0;
+}