Как я могу динамически изменить цвет элемента в изображении SVG в GTK?


Следующие две строки кода загружают изображение из файла SVG и устанавливают его в качестве значка для окна:

GdkPixbuf *icon = gdk_pixbuf_new_from_file("icon.svg", NULL);
gtk_window_set_icon(GTK_WINDOW(win), icon);

Этот файл SVG содержит, среди прочего, прямоугольник, определенный следующим образом:

<rect
   style="fill:#000000"
   id="screen"
   ... />

Я хотел бы динамически изменить цвет этого элемента rect после загрузки файла, но до того, как я установлю его в качестве значка для окна.

Если я вручную изменю атрибут style на этом элементе файла на диске непосредственно перед запуском моей программы, он будет иметь желаемый эффект. Но я хотел бы, чтобы он был установлен самой программой, чтобы соответствовать цвету, который она выбрала.

(это так, чтобы я мог различать несколько похожих окон в меню переключателя окон, среди других мест)

1 2

1 ответ:

Теперь я нашел ответ на этот вопрос, от IRC (#gtk+ on irc.gnome.org), и чтение собственного исходного кода GTK.

Ответ заключается в построении строки, которая задает таблицу стилей и использует xinclude XML для извлечения исходного изображения.

GdkPixbuf *load_icon(char *background)
{
  /* This technique stolen from 
   *   http://git.gnome.org/browse/gtk+/tree/gtk/gtkicontheme.c#n3180
   */

  gchar *str = 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=\"64\"\n"
      "     height=\"64\">\n"
      "  <style type=\"text/css\">\n"
      "    #screen {\n"
      "      fill: ", background, " !important;\n"
      "    }\n"
      "  </style>\n"
      "  <xi:include href=\"" PANGOTERM_SHAREDIR "/pangoterm.svg" "\"/>\n"
      "</svg>",
    NULL);

  GInputStream *stream = g_memory_input_stream_new_from_data(str, -1, g_free);

  GdkPixbuf *ret = gdk_pixbuf_new_from_stream(stream, NULL, NULL);

  g_object_unref(stream);

  return ret;
}