From 6b973bc70b6118c1d904d6d21626843b5e70beaa Mon Sep 17 00:00:00 2001 From: Matthew Brush Date: Fri, 12 Jan 2018 12:46:50 -0800 Subject: [PATCH] Theme improvements (#1382) * Improve GTK+3 theme loading - Merge geany-3.0.css into geany.css - Load geany-3.20.css to override if runtime version dictates - Load geany.css from app->configdir if it exists. * Add initial documentation for GTK+ CSS theming * Add geany.css file to the `Tools->Configuration Files` menu Also mark such config files as changed if they don't already exist to force the user to save or discard any newly created config files. * Allow customizing message window using GTK+ themes * Improve GTK+3 CSS docs a bit State which classes are meant to be overridden by themes. * Go back to conditionally loading geany-3.0.css It can't be merged into geany.css since GTK+ CSS parser doesn't ignore invalid properties when prefixed with vendor extension (ie. -Gtk). * Don't mark unedited config files as changed They probably should be marked as changed since they don't exist on disk yet, but for the time being leave it how it was. * Fix misuse of CSS ID vs class in manual * Minor colour value tweaks Based on feedback from @b4n --- data/geany-3.0.css | 2 - data/geany-3.20.css | 2 - data/geany.css | 11 +++++ data/geany.gtkrc | 17 ++++++++ doc/geany.txt | 21 +++++++++ src/msgwindow.c | 53 ++++++++++++++++++---- src/ui_utils.c | 104 +++++++++++++++++++++++++++++--------------- 7 files changed, 164 insertions(+), 46 deletions(-) diff --git a/data/geany-3.0.css b/data/geany-3.0.css index 54209745..b4252547 100644 --- a/data/geany-3.0.css +++ b/data/geany-3.0.css @@ -1,5 +1,3 @@ -@import "geany.css"; - /* make close button on the editor's tabs smaller */ #geany-close-tab-button { -GtkWidget-focus-padding: 0; diff --git a/data/geany-3.20.css b/data/geany-3.20.css index 5cbde300..7d3a7028 100644 --- a/data/geany-3.20.css +++ b/data/geany-3.20.css @@ -1,5 +1,3 @@ -@import "geany.css"; - /* make close button on the editor's tabs smaller */ #geany-close-tab-button { outline-offset: 0; diff --git a/data/geany.css b/data/geany.css index 1c1f4cf9..f4e9f0b6 100644 --- a/data/geany.css +++ b/data/geany.css @@ -36,6 +36,17 @@ color: #007f00; } +/* compiler message colors */ +#geany-compiler-error { + color: #ff0000; +} +#geany-compiler-context { + color: #7f0000; +} +#geany-compiler-message { + color: #0000D0; +} + /* red "Terminal" label when terminal dirty */ #geany-terminal-dirty { color: #ff0000; diff --git a/data/geany.gtkrc b/data/geany.gtkrc index 28a07812..15add701 100644 --- a/data/geany.gtkrc +++ b/data/geany.gtkrc @@ -50,5 +50,22 @@ widget "*.geany-document-status-changed" style "geany-document-status-changed-st widget "*.geany-document-status-disk-changed" style "geany-document-status-disk-changed-style" widget "*.geany-document-status-readonly" style "geany-document-status-readonly-style" +# compiler message colors +style "geany-compiler-error-style" { + fg[NORMAL] = "#ffff00000000" + fg[ACTIVE] = "#ffff00000000" +} +style "geany-compiler-context-style" { + fg[NORMAL] = "#7f7f00000000" + fg[ACTIVE] = "#7f7f00000000" +} +style "geany-compiler-message-style" { + fg[NORMAL] = "#00000000D000" + fg[ACTIVE] = "#00000000D000" +} +widget "*.geany-compiler-error" style "geany-compiler-error-style" +widget "*.geany-compiler-context" style "geany-compiler-context-style" +widget "*.geany-compiler-message" style "geany-compiler-message-style" + # red "Terminal" label when terminal dirty widget "*.geany-terminal-dirty" style "geany-document-status-changed-style" diff --git a/doc/geany.txt b/doc/geany.txt index a0a6ca29..b0601378 100644 --- a/doc/geany.txt +++ b/doc/geany.txt @@ -494,6 +494,27 @@ An example of a simple ``.gtkrc-2.0``:: widget "GeanyPrefsDialog" style "geanyStyle" +Customizing Geany's appearance using GTK+ 3 CSS +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To override GTK+ CSS styles, you can use traditional mechanisms or you +can create a file named ``geany.css`` in the user configuration directory +(usually ``~/.config/geany``) which will be loaded after other CSS styles +are applied to allow overriding the default styles. + +Geany offers a number of CSS IDs which can be used to taylor its +appearence. Among the more interesting include: + +* ``geany-compiler-context`` - the style used for build command output surrounding errors +* ``geany-compiler-error`` - the style used for build command errors +* ``geany-compiler-message`` - the style other output encountered while running build command +* ``geany-document-status-changed`` - the style for document tab labels when the document is changed +* ``geany-document-status-disk-changed`` - the style for document tab labels when the file on disk has changed +* ``geany-document-status-readyonly``` - the style for document tab labels when the document is read-only +* ``geany-search-entry-no-match`` - the style of find/replace diaog entries when no match is found +* ``geany-terminal-dirty`` - the style for the message window Terminal tab label when the terminal output has changed. + + Documents --------- diff --git a/src/msgwindow.c b/src/msgwindow.c index 3a5e2c40..dd73d615 100644 --- a/src/msgwindow.c +++ b/src/msgwindow.c @@ -83,6 +83,11 @@ enum }; +static GdkColor color_error = {0, 0xFFFF, 0, 0}; +static GdkColor color_context = {0, 0x7FFF, 0, 0}; +static GdkColor color_message = {0, 0, 0, 0xD000}; + + static void prepare_msg_tree_view(void); static void prepare_status_tree_view(void); static void prepare_compiler_tree_view(void); @@ -112,6 +117,40 @@ void msgwin_set_messages_dir(const gchar *messages_dir) } +GdkColor load_color(gchar *color_name) { + GdkColor color; + +#if GTK_CHECK_VERSION(3, 0, 0) + GdkRGBA rgba_color; + GtkWidgetPath *path = gtk_widget_path_new(); + GtkStyleContext *ctx = gtk_style_context_new(); + + gtk_widget_path_append_type(path, GTK_TYPE_WINDOW); + gtk_widget_path_iter_set_name(path, -1, color_name); + gtk_style_context_set_screen(ctx, gdk_screen_get_default()); + gtk_style_context_set_path(ctx, path); + gtk_style_context_get_color(ctx, gtk_style_context_get_state(ctx), &rgba_color); + + color.red = 0xffff * rgba_color.red; + color.green = 0xffff * rgba_color.green; + color.blue = 0xffff * rgba_color.blue; + + gtk_widget_path_unref(path); + g_object_unref(ctx); +#else + gchar *path = g_strconcat("*.", color_name, NULL); + + GtkSettings *settings = gtk_settings_get_default(); + GtkStyle *style = gtk_rc_get_style_by_paths(settings, path, NULL, GTK_TYPE_WIDGET); + color = style->fg[GTK_STATE_NORMAL]; + + g_free(path); +#endif + + return color; +} + + void msgwin_init(void) { msgwindow.notebook = ui_lookup_widget(main_widgets.window, "notebook_info"); @@ -130,6 +169,10 @@ void msgwin_init(void) ui_widget_modify_font_from_string(msgwindow.scribble, interface_prefs.msgwin_font); g_signal_connect(msgwindow.scribble, "populate-popup", G_CALLBACK(on_scribble_populate), NULL); + + color_error = load_color("geany-compiler-error"); + color_context = load_color("geany-compiler-context"); + color_message = load_color("geany-compiler-message"); } @@ -262,19 +305,13 @@ static void prepare_compiler_tree_view(void) /*g_signal_connect(selection, "changed", G_CALLBACK(on_msg_tree_selection_changed), NULL);*/ } - -static const GdkColor color_error = {0, 65535, 0, 0}; - static const GdkColor *get_color(gint msg_color) { - static const GdkColor dark_red = {0, 65535 / 2, 0, 0}; - static const GdkColor blue = {0, 0, 0, 0xD000}; /* not too bright ;-) */ - switch (msg_color) { case COLOR_RED: return &color_error; - case COLOR_DARK_RED: return &dark_red; - case COLOR_BLUE: return &blue; + case COLOR_DARK_RED: return &color_context; + case COLOR_BLUE: return &color_message; default: return NULL; } } diff --git a/src/ui_utils.c b/src/ui_utils.c index 30aab27c..bcecfa33 100644 --- a/src/ui_utils.c +++ b/src/ui_utils.c @@ -2492,53 +2492,85 @@ void ui_init_builder(void) } -static void init_custom_style(void) -{ #if GTK_CHECK_VERSION(3, 0, 0) - const struct { - guint version; - const gchar *file; - } css_files[] = { - /* - * Keep these from newest to oldest, - * and make sure 0 remains last - */ - { 20, "geany-3.20.css" }, - { 0, "geany-3.0.css" }, - }; - guint gtk_version = gtk_get_minor_version(); - gsize i = 0; - gchar *css_file; - GtkCssProvider *css = gtk_css_provider_new(); +static void load_css_theme(const gchar *fn, guint priority) +{ + GtkCssProvider *provider = gtk_css_provider_new(); GError *error = NULL; - /* gtk_version will never be smaller than 0 */ - while (css_files[i].version > gtk_version) - ++i; - - css_file = g_build_filename(app->datadir, css_files[i].file, NULL); - if (! gtk_css_provider_load_from_path(css, css_file, &error)) + if (! gtk_css_provider_load_from_path(provider, fn, &error)) { g_warning("Failed to load custom CSS: %s", error->message); g_error_free(error); - } - else - { - gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), - GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + return; } - g_object_unref(css); - g_free(css_file); -#else - /* see setup_gtk2_styles() in main.c */ -#endif + gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), + GTK_STYLE_PROVIDER(provider), priority); + geany_debug("Loaded GTK+ CSS theme '%s'", fn); + + g_object_unref(provider); } +// see setup_gtk2_styles() in libmain.c for GTK+ 2-specific theme initialization +static void init_css_styles(void) +{ + gchar *theme_fn; + + // load the main geany.css file from system data dir + theme_fn = g_build_filename(app->datadir, "geany.css", NULL); + load_css_theme(theme_fn, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_free(theme_fn); + + // load themes to handle breakage between various GTK+ versions + const struct + { + guint min_version; + guint max_version; + const gchar *file; + } + css_files[] = + { + { 20, G_MAXUINT, "geany-3.20.css" }, + { 0, 19, "geany-3.0.css" }, + }; + + guint gtk_version = gtk_get_minor_version(); + for (guint i = 0; i < G_N_ELEMENTS(css_files); i++) + { + if (gtk_version >= css_files[i].min_version && + gtk_version <= css_files[i].max_version) + { + theme_fn = g_build_filename(app->datadir, css_files[i].file, NULL); + load_css_theme(theme_fn, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_free(theme_fn); + } + } + + // if the user provided a geany.css file in their config dir, try and load that + theme_fn = g_build_filename(app->configdir, "geany.css", NULL); + if (g_file_test(theme_fn, G_FILE_TEST_EXISTS)) + load_css_theme(theme_fn, GTK_STYLE_PROVIDER_PRIORITY_USER); + g_free(theme_fn); +} + + +static void add_css_config_file_item(void) +{ + gchar *theme_fn; + theme_fn = g_build_filename(app->configdir, "geany.css", NULL); + ui_add_config_file_menu_item(theme_fn, NULL, NULL); + g_free(theme_fn); +} +#endif // GTK3 + + void ui_init(void) { - init_custom_style(); +#if GTK_CHECK_VERSION(3, 0, 0) + init_css_styles(); +#endif init_recent_files(); @@ -2585,7 +2617,11 @@ void ui_init(void) ui_init_toolbar_widgets(); init_document_widgets(); + create_config_files_menu(); +#if GTK_CHECK_VERSION(3, 0, 0) + add_css_config_file_item(); +#endif }