summaryrefslogtreecommitdiffstats
path: root/src/ui/themes.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:24:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:24:48 +0000
commitcca66b9ec4e494c1d919bff0f71a820d8afab1fa (patch)
tree146f39ded1c938019e1ed42d30923c2ac9e86789 /src/ui/themes.cpp
parentInitial commit. (diff)
downloadinkscape-cca66b9ec4e494c1d919bff0f71a820d8afab1fa.tar.xz
inkscape-cca66b9ec4e494c1d919bff0f71a820d8afab1fa.zip
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/ui/themes.cpp')
-rw-r--r--src/ui/themes.cpp546
1 files changed, 546 insertions, 0 deletions
diff --git a/src/ui/themes.cpp b/src/ui/themes.cpp
new file mode 100644
index 0000000..bb58245
--- /dev/null
+++ b/src/ui/themes.cpp
@@ -0,0 +1,546 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * Gtk <themes> helper code.
+ */
+/*
+ * Authors:
+ * Jabiertxof
+ * Martin Owens
+ *
+ * Copyright (C) 2017-2021 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "themes.h"
+#include "preferences.h"
+#include "io/resource.h"
+#include "svg/svg-color.h"
+#include <cstring>
+#include <gio/gio.h>
+#include <glibmm.h>
+#include <gtkmm.h>
+#include <map>
+#include <utility>
+#include <vector>
+#include <regex>
+#include "svg/css-ostringstream.h"
+
+namespace Inkscape {
+namespace UI {
+
+ThemeContext::ThemeContext()
+{
+}
+
+/**
+ * Inkscape fill gtk, taken from glib/gtk code with our own checks.
+ */
+void
+ThemeContext::inkscape_fill_gtk(const gchar *path, gtkThemeList &themes)
+{
+ const gchar *dir_entry;
+ GDir *dir = g_dir_open(path, 0, nullptr);
+ if (!dir)
+ return;
+ while ((dir_entry = g_dir_read_name(dir))) {
+ gchar *filename = g_build_filename(path, dir_entry, "gtk-3.0", "gtk.css", nullptr);
+ bool has_prefer_dark = false;
+
+ Glib::ustring theme = dir_entry;
+ gchar *filenamedark = g_build_filename(path, dir_entry, "gtk-3.0", "gtk-dark.css", nullptr);
+ if (g_file_test(filenamedark, G_FILE_TEST_IS_REGULAR))
+ has_prefer_dark = true;
+ if (themes.find(theme) != themes.end() && !has_prefer_dark) {
+ continue;
+ }
+ if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
+ themes[theme] = has_prefer_dark;
+ }
+ g_free(filename);
+ g_free(filenamedark);
+ }
+
+ g_dir_close(dir);
+}
+
+/**
+ * Get available themes based on locations of gtk directories.
+ */
+std::map<Glib::ustring, bool>
+ThemeContext::get_available_themes()
+{
+ gtkThemeList themes;
+ Glib::ustring theme = "";
+ gchar *path;
+ gchar **builtin_themes;
+ guint i, j;
+ const gchar *const *dirs;
+
+ /* Builtin themes */
+ builtin_themes = g_resources_enumerate_children("/org/gtk/libgtk/theme", G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
+ for (i = 0; builtin_themes[i] != NULL; i++) {
+ if (g_str_has_suffix(builtin_themes[i], "/")) {
+ theme = builtin_themes[i];
+ theme.resize(theme.size() - 1);
+ Glib::ustring theme_path = "/org/gtk/libgtk/theme";
+ theme_path += "/" + theme;
+ gchar **builtin_themes_files =
+ g_resources_enumerate_children(theme_path.c_str(), G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
+ bool has_prefer_dark = false;
+ if (builtin_themes_files != NULL) {
+ for (j = 0; builtin_themes_files[j] != NULL; j++) {
+ Glib::ustring file = builtin_themes_files[j];
+ if (file == "gtk-dark.css") {
+ has_prefer_dark = true;
+ }
+ }
+ }
+ g_strfreev(builtin_themes_files);
+ themes[theme] = has_prefer_dark;
+ }
+ }
+
+ g_strfreev(builtin_themes);
+
+ path = g_build_filename(g_get_user_data_dir(), "themes", nullptr);
+ inkscape_fill_gtk(path, themes);
+ g_free(path);
+
+ path = g_build_filename(g_get_home_dir(), ".themes", nullptr);
+ inkscape_fill_gtk(path, themes);
+ g_free(path);
+
+ dirs = g_get_system_data_dirs();
+ for (i = 0; dirs[i]; i++) {
+ path = g_build_filename(dirs[i], "themes", nullptr);
+ inkscape_fill_gtk(path, themes);
+ g_free(path);
+ }
+ return themes;
+}
+
+Glib::ustring
+ThemeContext::get_symbolic_colors()
+{
+ Glib::ustring css_str;
+ gchar colornamed[64];
+ gchar colornamedsuccess[64];
+ gchar colornamedwarning[64];
+ gchar colornamederror[64];
+ gchar colornamed_inverse[64];
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Glib::ustring themeiconname = prefs->getString("/theme/iconTheme", prefs->getString("/theme/defaultIconTheme", ""));
+ guint32 colorsetbase = 0x2E3436ff;
+ guint32 colorsetbase_inverse;
+ guint32 colorsetsuccess = 0x4AD589ff;
+ guint32 colorsetwarning = 0xF57900ff;
+ guint32 colorseterror = 0xCC0000ff;
+ colorsetbase = prefs->getUInt("/theme/" + themeiconname + "/symbolicBaseColor", colorsetbase);
+ colorsetsuccess = prefs->getUInt("/theme/" + themeiconname + "/symbolicSuccessColor", colorsetsuccess);
+ colorsetwarning = prefs->getUInt("/theme/" + themeiconname + "/symbolicWarningColor", colorsetwarning);
+ colorseterror = prefs->getUInt("/theme/" + themeiconname + "/symbolicErrorColor", colorseterror);
+ sp_svg_write_color(colornamed, sizeof(colornamed), colorsetbase);
+ sp_svg_write_color(colornamedsuccess, sizeof(colornamedsuccess), colorsetsuccess);
+ sp_svg_write_color(colornamedwarning, sizeof(colornamedwarning), colorsetwarning);
+ sp_svg_write_color(colornamederror, sizeof(colornamederror), colorseterror);
+ colorsetbase_inverse = colorsetbase ^ 0xffffff00;
+ sp_svg_write_color(colornamed_inverse, sizeof(colornamed_inverse), colorsetbase_inverse);
+ css_str += "@define-color warning_color " + Glib::ustring(colornamedwarning) + ";\n";
+ css_str += "@define-color error_color " + Glib::ustring(colornamederror) + ";\n";
+ css_str += "@define-color success_color " + Glib::ustring(colornamedsuccess) + ";\n";
+ /* ":not(.rawstyle) > image" works only on images in first level of widget container
+ if in the future we use a complex widget with more levels and we dont want to tweak the color
+ here, retaining default we can add more lines like ":not(.rawstyle) > > image"
+ if we not override the color we use defautt theme colors*/
+ bool overridebasecolor = !prefs->getBool("/theme/symbolicDefaultBaseColors", true);
+ if (overridebasecolor) {
+ css_str += "#InkRuler,";
+ css_str += ":not(.rawstyle) > image";
+ css_str += "{color:";
+ css_str += colornamed;
+ css_str += ";}";
+ }
+ css_str += ".dark .forcebright :not(.rawstyle) > image,";
+ css_str += ".dark .forcebright image:not(.rawstyle),";
+ css_str += ".bright .forcedark :not(.rawstyle) > image,";
+ css_str += ".bright .forcedark image:not(.rawstyle),";
+ css_str += ".dark :not(.rawstyle) > image.forcebright,";
+ css_str += ".dark image.forcebright:not(.rawstyle),";
+ css_str += ".bright :not(.rawstyle) > image.forcedark,";
+ css_str += ".bright image.forcedark:not(.rawstyle),";
+ css_str += ".inverse :not(.rawstyle) > image,";
+ css_str += ".inverse image:not(.rawstyle)";
+ css_str += "{color:";
+ if (overridebasecolor) {
+ css_str += colornamed_inverse;
+ } else {
+ // we override base color in this special cases using inverse color
+ css_str += "@theme_bg_color";
+ }
+ css_str += ";}";
+ return css_str;
+}
+
+std::string sp_tweak_background_colors(std::string cssstring, double crossfade, double contrast, bool dark)
+{
+ static std::regex re_no_affect("(inherit|unset|initial|none|url)");
+ static std::regex re_color("background-color( ){0,3}:(.*?);");
+ static std::regex re_image("background-image( ){0,3}:(.*?\\)) *?;");
+ std::string sub = "";
+ std::smatch m;
+ std::regex_search(cssstring, m, re_no_affect);
+ if (m.size() == 0) {
+ if (cssstring.find("background-color") != std::string::npos) {
+ sub = "background-color:shade($2," + Glib::ustring::format(crossfade) + ");";
+ cssstring = std::regex_replace(cssstring, re_color, sub);
+ } else if (cssstring.find("background-image") != std::string::npos) {
+ if (dark) {
+ contrast = std::clamp((int)((contrast) * 27), 0, 100);
+ sub = "background-image:cross-fade(" + Glib::ustring::format(contrast) + "% image(rgb(255,255,255)), image($2));";
+ } else {
+ contrast = std::clamp((int)((contrast) * 90), 0 , 100);
+ sub = "background-image:cross-fade(" + Glib::ustring::format(contrast) + "% image(rgb(0,0,0)), image($2));";
+ }
+ cssstring = std::regex_replace(cssstring, re_image, sub);
+ }
+ } else {
+ cssstring = "";
+ }
+ return cssstring;
+}
+
+static void
+show_parsing_error(const Glib::RefPtr<const Gtk::CssSection>& section, const Glib::Error& error)
+{
+#ifndef NDEBUG
+ g_warning("There is a warning parsing theme CSS:: %s", error.what().c_str());
+#endif
+}
+
+// callback for a "narrow spinbutton" preference change
+struct NarrowSpinbuttonObserver : Preferences::Observer {
+ NarrowSpinbuttonObserver(const char* path, Glib::RefPtr<Gtk::CssProvider> provider):
+ Preferences::Observer(path), _provider(std::move(provider)) {}
+
+ void notify(Preferences::Entry const& new_val) override {
+ auto screen = Gdk::Screen::get_default();
+ if (new_val.getBool()) {
+ Gtk::StyleContext::add_provider_for_screen(screen, _provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ }
+ else {
+ Gtk::StyleContext::remove_provider_for_screen(screen, _provider);
+ }
+ }
+
+ Glib::RefPtr<Gtk::CssProvider> _provider;
+};
+
+/**
+ * \brief Add our CSS style sheets
+ * @param only_providers: Apply only the providers part, from inkscape preferences::theme change, no need to reaply
+ */
+void ThemeContext::add_gtk_css(bool only_providers, bool cached)
+{
+ using namespace Inkscape::IO::Resource;
+ // Add style sheet (GTK3)
+ auto const screen = Gdk::Screen::get_default();
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gchar *gtkThemeName = nullptr;
+ gchar *gtkIconThemeName = nullptr;
+ Glib::ustring themeiconname;
+ gboolean gtkApplicationPreferDarkTheme;
+ GtkSettings *settings = gtk_settings_get_default();
+ if (settings && !only_providers) {
+ g_object_get(settings, "gtk-icon-theme-name", &gtkIconThemeName, nullptr);
+ g_object_get(settings, "gtk-theme-name", &gtkThemeName, nullptr);
+ g_object_get(settings, "gtk-application-prefer-dark-theme", &gtkApplicationPreferDarkTheme, nullptr);
+ prefs->setBool("/theme/defaultPreferDarkTheme", gtkApplicationPreferDarkTheme);
+ prefs->setString("/theme/defaultGtkTheme", Glib::ustring(gtkThemeName));
+ prefs->setString("/theme/defaultIconTheme", Glib::ustring(gtkIconThemeName));
+ Glib::ustring gtkthemename = prefs->getString("/theme/gtkTheme");
+ if (gtkthemename != "") {
+ g_object_set(settings, "gtk-theme-name", gtkthemename.c_str(), nullptr);
+ }
+ bool preferdarktheme = prefs->getBool("/theme/preferDarkTheme", false);
+ g_object_set(settings, "gtk-application-prefer-dark-theme", preferdarktheme, nullptr);
+ themeiconname = prefs->getString("/theme/iconTheme");
+ if (themeiconname != "") {
+ g_object_set(settings, "gtk-icon-theme-name", themeiconname.c_str(), nullptr);
+ }
+ }
+
+ g_free(gtkThemeName);
+ g_free(gtkIconThemeName);
+
+ int themecontrast = prefs->getInt("/theme/contrast", 10);
+ if (!_contrastthemeprovider) {
+ _contrastthemeprovider = Gtk::CssProvider::create();
+ // We can uncomment this line to remove warnings and errors on the theme
+ _contrastthemeprovider->signal_parsing_error().connect(sigc::ptr_fun(show_parsing_error));
+ }
+ static std::string cssstringcached = "";
+ // we use contrast only if is setup (!= 10)
+ if (themecontrast < 10) {
+ Glib::ustring css_contrast = "";
+ double contrast = (10 - themecontrast) / 30.0;
+ double shade = 1 - contrast;
+ const gchar *variant = nullptr;
+ if (prefs->getBool("/theme/preferDarkTheme", false)) {
+ variant = "dark";
+ }
+ bool dark = prefs->getBool("/theme/darkTheme", false);
+ if (dark) {
+ contrast *= 2.5;
+ shade = 1 + contrast;
+ }
+ Glib::ustring current_theme = prefs->getString("/theme/gtkTheme", prefs->getString("/theme/defaultGtkTheme", ""));
+
+ std::string cssstring = "";
+ if (cached && !cssstringcached.empty()) {
+ cssstring = cssstringcached;
+ } else {
+ GtkCssProvider *current_themeprovider = gtk_css_provider_get_named(current_theme.c_str(), variant);
+ cssstring = gtk_css_provider_to_string(current_themeprovider);
+ }
+ if (contrast) {
+ std::string cssdefined = "";
+ // we do this way to fix issue Inkscape#2345
+ // windows seem crash if text length > 2000;
+
+ std::istringstream f(cssstring);
+ std::string line;
+ while (std::getline(f, line)) {
+ // here we ignore most of class to parse because is in additive mode
+ // so stiles not applied are set on previous context style
+ if (line.find(";") != std::string::npos &&
+ line.find("background-image") == std::string::npos &&
+ line.find("background-color") == std::string::npos)
+ {
+ continue;
+ }
+ cssdefined += sp_tweak_background_colors(line, shade, contrast, dark);
+ cssdefined += "\n";
+ if (!cached) {
+ cssstringcached += line;
+ cssstringcached += "\n";
+ }
+ }
+ if (!cached) {
+ // Split on curly brackets. Even tokens are selectors, odd are values.
+ std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("[}{]", cssstringcached);
+ cssstringcached = "";
+ for (unsigned i = 0; i < tokens.size() - 1; i += 2) {
+ Glib::ustring selector = tokens[i];
+ Glib::ustring properties = "";
+ if ((i + 1) < tokens.size()) {
+ properties = tokens[i + 1];
+ }
+ if (properties.find(";") != Glib::ustring::npos) {
+ cssstringcached += selector;
+ cssstringcached += "{\n";
+ cssstringcached += properties;
+ cssstringcached += "}\n";
+ }
+ }
+ }
+ cssstring = cssdefined;
+ }
+ if (!cssstring.empty()) {
+ // Use c format allow parse with errors or warnings
+ gtk_css_provider_load_from_data (_contrastthemeprovider->gobj(), cssstring.c_str(), -1, nullptr);
+ Gtk::StyleContext::add_provider_for_screen(screen, _contrastthemeprovider, GTK_STYLE_PROVIDER_PRIORITY_SETTINGS);
+ }
+ } else {
+ cssstringcached = "";
+ if (_contrastthemeprovider) {
+ Gtk::StyleContext::remove_provider_for_screen(screen, _contrastthemeprovider);
+ }
+ }
+ Glib::ustring style = get_filename(UIS, "style.css");
+ if (!style.empty()) {
+ if (_styleprovider) {
+ Gtk::StyleContext::remove_provider_for_screen(screen, _styleprovider);
+ }
+ if (!_styleprovider) {
+ _styleprovider = Gtk::CssProvider::create();
+ }
+ try {
+ _styleprovider->load_from_path(style);
+ } catch (const Gtk::CssProviderError &ex) {
+ g_critical("CSSProviderError::load_from_path(): failed to load '%s'\n(%s)", style.c_str(),
+ ex.what().c_str());
+ }
+ Gtk::StyleContext::add_provider_for_screen(screen, _styleprovider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ }
+ // load small CSS snippet to style spinbuttons by removing excessive padding
+ if (!_spinbuttonprovider) {
+ _spinbuttonprovider = Gtk::CssProvider::create();
+ Glib::ustring style = get_filename(UIS, "spinbutton.css");
+ if (!style.empty()) {
+ try {
+ _spinbuttonprovider->load_from_path(style);
+ } catch (const Gtk::CssProviderError &ex) {
+ g_critical("CSSProviderError::load_from_path(): failed to load '%s'\n(%s)", style.c_str(), ex.what().c_str());
+ }
+ }
+ }
+ _spinbutton_observer = std::make_unique<NarrowSpinbuttonObserver>("/theme/narrowSpinButton", _spinbuttonprovider);
+ // note: ideally we should remove the callback during destruction, but ThemeContext is never deleted
+ prefs->addObserver(*_spinbutton_observer);
+ // establish default value, so both this setting here and checkbox in preferences are in sync
+ if (!prefs->getEntry(_spinbutton_observer->observed_path).isValid()) {
+ prefs->setBool(_spinbutton_observer->observed_path, true);
+ }
+ _spinbutton_observer->notify(prefs->getEntry(_spinbutton_observer->observed_path));
+
+ Glib::ustring gtkthemename = prefs->getString("/theme/gtkTheme", prefs->getString("/theme/defaultGtkTheme", ""));
+ gtkthemename += ".css";
+ style = get_filename(UIS, gtkthemename.c_str(), false, true);
+ if (!style.empty()) {
+ if (_themeprovider) {
+ Gtk::StyleContext::remove_provider_for_screen(screen, _themeprovider);
+ }
+ if (!_themeprovider) {
+ _themeprovider = Gtk::CssProvider::create();
+ }
+ try {
+ _themeprovider->load_from_path(style);
+ } catch (const Gtk::CssProviderError &ex) {
+ g_critical("CSSProviderError::load_from_path(): failed to load '%s'\n(%s)", style.c_str(),
+ ex.what().c_str());
+ }
+ Gtk::StyleContext::add_provider_for_screen(screen, _themeprovider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ }
+
+ if (!_colorizeprovider) {
+ _colorizeprovider = Gtk::CssProvider::create();
+ }
+ Glib::ustring css_str = "";
+ if (prefs->getBool("/theme/symbolicIcons", false)) {
+ css_str = get_symbolic_colors();
+ }
+ try {
+ _colorizeprovider->load_from_data(css_str);
+ } catch (const Gtk::CssProviderError &ex) {
+ g_critical("CSSProviderError::load_from_data(): failed to load '%s'\n(%s)", css_str.c_str(), ex.what().c_str());
+ }
+ Gtk::StyleContext::add_provider_for_screen(screen, _colorizeprovider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+#if __APPLE__
+ Glib::ustring macstyle = get_filename(UIS, "mac.css");
+ if (!macstyle.empty()) {
+ if (_macstyleprovider) {
+ Gtk::StyleContext::remove_provider_for_screen(screen, _macstyleprovider);
+ }
+ if (!_macstyleprovider) {
+ _macstyleprovider = Gtk::CssProvider::create();
+ }
+ try {
+ _macstyleprovider->load_from_path(macstyle);
+ } catch (const Gtk::CssProviderError &ex) {
+ g_critical("CSSProviderError::load_from_path(): failed to load '%s'\n(%s)", macstyle.c_str(),
+ ex.what().c_str());
+ }
+ Gtk::StyleContext::add_provider_for_screen(screen, _macstyleprovider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ }
+#endif
+}
+
+/**
+ * Check if current applied theme is dark or not by looking at style context.
+ * This is important to check system default theme is dark or not
+ * It only return True for dark and False for Bright. It does not apply any
+ * property other than preferDarkTheme, so theme should be set before calling
+ * this function as it may otherwise return outdated result.
+ */
+bool ThemeContext::isCurrentThemeDark(Gtk::Container *window)
+{
+ bool dark = false;
+ if (window) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Glib::ustring current_theme =
+ prefs->getString("/theme/gtkTheme", prefs->getString("/theme/defaultGtkTheme", ""));
+ auto settings = Gtk::Settings::get_default();
+ if (settings) {
+ settings->property_gtk_application_prefer_dark_theme() = prefs->getBool("/theme/preferDarkTheme", false);
+ }
+ dark = current_theme.find(":dark") != std::string::npos;
+ // if theme is dark or we use contrast slider feature and have set preferDarkTheme we force the theme dark
+ // and avoid color check, this fix a issue with low contrast themes bad switch of dark theme toggle
+ dark = dark || (prefs->getInt("/theme/contrast", 10) != 10 && prefs->getBool("/theme/preferDarkTheme", false));
+ if (!dark) {
+ Glib::RefPtr<Gtk::StyleContext> stylecontext = window->get_style_context();
+ Gdk::RGBA rgba;
+ bool background_set = stylecontext->lookup_color("theme_bg_color", rgba);
+ if (background_set && (0.299 * rgba.get_red() + 0.587 * rgba.get_green() + 0.114 * rgba.get_blue()) < 0.5) {
+ dark = true;
+ }
+ }
+ }
+ return dark;
+}
+
+/**
+ * Load the highlight colours from the current theme. If the theme changes
+ * you can call this function again to refresh the list.
+ */
+std::vector<guint32> ThemeContext::getHighlightColors(Gtk::Window *window)
+{
+ std::vector<guint32> colors;
+ if (!window) return colors;
+
+ Glib::ustring name = "highlight-color-";
+
+ for (int i = 1; i <= 8; ++i) {
+ auto context = Gtk::StyleContext::create();
+
+ // The highlight colors will be attached to a GtkWidget
+ // but it isn't neccessary to use this in the .css file.
+ auto path = window->get_style_context()->get_path();
+ path.path_append_type(Gtk::Widget::get_type());
+ path.iter_add_class(-1, name + Glib::ustring::format(i));
+ context->set_path(path);
+
+ // Get the color from the new context
+ auto color = context->get_color();
+ guint32 rgba =
+ gint32(0xff * color.get_red()) << 24 |
+ gint32(0xff * color.get_green()) << 16 |
+ gint32(0xff * color.get_blue()) << 8 |
+ gint32(0xff * color.get_alpha());
+ colors.push_back(rgba);
+ }
+ return colors;
+}
+
+void ThemeContext::adjust_global_font_scale(double factor) {
+ if (factor < 0.1 || factor > 10) {
+ g_warning("Invalid font scaling factor %f in ThemeContext::adjust_global_font_scale", factor);
+ return;
+ }
+
+ auto screen = Gdk::Screen::get_default();
+ Gtk::StyleContext::remove_provider_for_screen(screen, _fontsizeprovider);
+
+ Inkscape::CSSOStringStream os;
+ os.precision(3);
+ os << "widget, menuitem, popover { font-size: " << factor << "rem; }";
+ _fontsizeprovider->load_from_data(os.str());
+
+ // note: priority set to APP - 1 to make sure styles.css take precedence over generic font-size
+ Gtk::StyleContext::add_provider_for_screen(screen, _fontsizeprovider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION - 1);
+}
+
+} // UI
+} // Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :