diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2016-02-02 14:42:58 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2016-02-02 17:49:42 +0100 |
commit | e768487fe3ef9ec8f94cea11ad6587c49c32422a (patch) | |
tree | 2d9b3a6fdea2fc8dc06c4fbd548eee4b9bf95cab /src | |
parent | 8627a00e3b25cdd80d88ddcef9d2d73cc784d571 (diff) | |
download | sciteco-e768487fe3ef9ec8f94cea11ad6587c49c32422a.tar.gz |
Gtk UI: full color scheme support
* implemented by exporting the most important Scintilla STYLEs
as CSS variables and defining named widgets for the main UI
components.
* ~/.teco_css will then apply the Scintilla styles to the
Gtk UI.
This file is also for additional tweaks, e.g. enabling
translucency.
* A fallback.css is provided which does just that and is able
to apply the terminal.tes and solarized.tes color schemes.
* Other important aspects of theming like font sizes and names
have not yet been dealt with.
(We may want to apply the corresponding Scintilla settings
to some widgets...)
Diffstat (limited to 'src')
-rw-r--r-- | src/interface-gtk/Makefile.am | 2 | ||||
-rw-r--r-- | src/interface-gtk/fallback.css | 47 | ||||
-rw-r--r-- | src/interface-gtk/gtk-info-popup.gob | 16 | ||||
-rw-r--r-- | src/interface-gtk/interface-gtk.cpp | 120 | ||||
-rw-r--r-- | src/interface-gtk/interface-gtk.h | 6 |
5 files changed, 173 insertions, 18 deletions
diff --git a/src/interface-gtk/Makefile.am b/src/interface-gtk/Makefile.am index 64b4625..51591e1 100644 --- a/src/interface-gtk/Makefile.am +++ b/src/interface-gtk/Makefile.am @@ -17,6 +17,8 @@ libsciteco_interface_la_SOURCES += gtkflowbox.c gtkflowbox.h endif nodist_libsciteco_interface_la_SOURCES = gtk-info-popup.c +dist_pkgdata_DATA = fallback.css + CLEANFILES = $(BUILT_SOURCES) %.c %.h %-private.h : %.gob diff --git a/src/interface-gtk/fallback.css b/src/interface-gtk/fallback.css new file mode 100644 index 0000000..0482763 --- /dev/null +++ b/src/interface-gtk/fallback.css @@ -0,0 +1,47 @@ +/* + * This CSS will loaded as a fallback if there is no + * $SCITECOCONFIG/.teco_css. + * It tries to apply the current SciTECO color scheme + * by using predefined variables (see sciteco(7)). + * This may cause problems with your current Gtk theme. + * You can copy this file to $SCITECOCONFIG/.teco_css + * to fix it up or add other style customizations. + */ + +/* + * Original STYLE_DEFAULT foregrounds on backgrounds: + */ +#sciteco-cmdline { + color: @sciteco_default_fg_color; + text-shadow: none; + background-color: @sciteco_default_bg_color; + background-image: none; +} + +/* + * Reversed STYLE_DEFAULT colors: + * The "question" class refers to G_MESSAGE_QUESTION. + * This is used for showing user-level messages for the sole + * reason that there is no class for G_MESSAGE_OTHER that + * we could use for styling. + */ +#sciteco-info-bar, +#sciteco-info-bar GtkLabel, +.titlebar, /* info bar in CSD mode */ +#sciteco-message-bar.question { + color: @sciteco_default_bg_color; + text-shadow: none; + background-color: @sciteco_default_fg_color; + background-image: none; +} + +/* + * The popup widget (uses STYLE_CALLTIP) + */ +#sciteco-info-popup, +#sciteco-info-popup GtkLabel { + color: @sciteco_calltip_fg_color; + text-shadow: none; + background-color: @sciteco_calltip_bg_color; + background-image: none; +} diff --git a/src/interface-gtk/gtk-info-popup.gob b/src/interface-gtk/gtk-info-popup.gob index f172de6..6cb1b81 100644 --- a/src/interface-gtk/gtk-info-popup.gob +++ b/src/interface-gtk/gtk-info-popup.gob @@ -44,6 +44,10 @@ enum GTK_INFO_POPUP { DIRECTORY } Gtk:Info:Popup:Entry:Type; +/* + * NOTE: Deriving from GtkEventBox ensures that we can + * set a background on the entire popup widget. + */ class Gtk:Info:Popup from Gtk:Event:Box { public GtkAdjustment *hadjustment; public GtkAdjustment *vadjustment; @@ -92,18 +96,10 @@ class Gtk:Info:Popup from Gtk:Event:Box { gtk_widget_show_all(box); /* - * The top-level widget is a GtkEventBox, so it can have - * a background. We assign a default color since the popup - * will usually be put in an overlay and we don't want it - * to be transparent. - * It can also be styled with rounded corners etc. - * FIXME: This method of setting a background color is - * deprecated. We are supposed to use CSS style providers... + * NOTE: Everything shown except the top-level container. + * Therefore a gtk_widget_show() is enough to show our popup. */ gtk_container_add(GTK_CONTAINER(self), box); - GdkRGBA color = {0.5, 0.5, 0.5, 1.0}; - gtk_widget_override_background_color(GTK_WIDGET(self), GTK_STATE_FLAG_NORMAL, - &color); } /** diff --git a/src/interface-gtk/interface-gtk.cpp b/src/interface-gtk/interface-gtk.cpp index ebd3c91..7938131 100644 --- a/src/interface-gtk/interface-gtk.cpp +++ b/src/interface-gtk/interface-gtk.cpp @@ -25,6 +25,7 @@ #include <glib.h> #include <glib/gprintf.h> +#include <glib/gstdio.h> /* * FIXME: Because of gdk_threads_enter(). @@ -42,11 +43,11 @@ #include <gio/gio.h> -#include "gtk-info-popup.h" - #include <Scintilla.h> #include <ScintillaWidget.h> +#include "gtk-info-popup.h" + #include "sciteco.h" #include "string-utils.h" #include "cmdline.h" @@ -84,7 +85,24 @@ static gboolean sigterm_handler(gpointer user_data) G_GNUC_UNUSED; } /* extern "C" */ -#define UNNAMED_FILE "(Unnamed)" +#define UNNAMED_FILE "(Unnamed)" + +#define USER_CSS_FILE ".teco_css" + +/** printf() format for CSS RGB colors given as guint32 */ +#define CSS_COLOR_FORMAT "#%06" G_GINT32_MODIFIER "X" + +/** + * Convert Scintilla-style BGR color triple to + * RGB. + */ +static inline guint32 +bgr2rgb(guint32 bgr) +{ + return ((bgr & 0x0000FF) << 16) | + ((bgr & 0x00FF00) << 0) | + ((bgr & 0xFF0000) >> 16); +} void ViewGtk::initialize_impl(void) @@ -189,6 +207,7 @@ InterfaceGtk::main_impl(int &argc, char **&argv) * FIXME: At lease on Gtk 3.12 we could disable the subtitle. */ info_bar_widget = gtk_header_bar_new(); + gtk_widget_set_name(info_bar_widget, "sciteco-info-bar"); info_image = gtk_image_new(); gtk_header_bar_pack_start(GTK_HEADER_BAR(info_bar_widget), info_image); if (use_csd) { @@ -214,6 +233,7 @@ InterfaceGtk::main_impl(int &argc, char **&argv) gtk_box_pack_start(GTK_BOX(vbox), overlay_widget, TRUE, TRUE, 0); message_bar_widget = gtk_info_bar_new(); + gtk_widget_set_name(message_bar_widget, "sciteco-message-bar"); message_bar_content = gtk_info_bar_get_content_area(GTK_INFO_BAR(message_bar_widget)); message_widget = gtk_label_new(""); gtk_misc_set_alignment(GTK_MISC(message_widget), 0., 0.); @@ -221,6 +241,7 @@ InterfaceGtk::main_impl(int &argc, char **&argv) gtk_box_pack_start(GTK_BOX(vbox), message_bar_widget, FALSE, FALSE, 0); cmdline_widget = gtk_entry_new(); + gtk_widget_set_name(cmdline_widget, "sciteco-cmdline"); gtk_entry_set_has_frame(GTK_ENTRY(cmdline_widget), FALSE); gtk_editable_set_editable(GTK_EDITABLE(cmdline_widget), FALSE); widget_set_font(cmdline_widget, "Courier"); @@ -236,6 +257,7 @@ InterfaceGtk::main_impl(int &argc, char **&argv) * filling the entire width. */ popup_widget = gtk_info_popup_new(); + gtk_widget_set_name(popup_widget, "sciteco-info-popup"); gtk_overlay_add_overlay(GTK_OVERLAY(overlay_widget), popup_widget); g_signal_connect(overlay_widget, "get-child-position", G_CALLBACK(gtk_info_popup_get_position_in_overlay), NULL); @@ -248,8 +270,13 @@ InterfaceGtk::main_impl(int &argc, char **&argv) void InterfaceGtk::vmsg_impl(MessageType type, const gchar *fmt, va_list ap) { + /* + * The message types are chosen such that there is a CSS class + * for every one of them. GTK_MESSAGE_OTHER does not have + * a CSS class. + */ static const GtkMessageType type2gtk[] = { - /* [MSG_USER] = */ GTK_MESSAGE_OTHER, + /* [MSG_USER] = */ GTK_MESSAGE_QUESTION, /* [MSG_INFO] = */ GTK_MESSAGE_INFO, /* [MSG_WARNING] = */ GTK_MESSAGE_WARNING, /* [MSG_ERROR] = */ GTK_MESSAGE_ERROR @@ -285,7 +312,7 @@ InterfaceGtk::msg_clear(void) gdk_threads_enter(); gtk_info_bar_set_message_type(GTK_INFO_BAR(message_bar_widget), - GTK_MESSAGE_OTHER); + GTK_MESSAGE_QUESTION); gtk_label_set_text(GTK_LABEL(message_widget), ""); gdk_threads_leave(); @@ -482,6 +509,38 @@ InterfaceGtk::widget_set_font(GtkWidget *widget, const gchar *font_name) } void +InterfaceGtk::set_css_variables_from_view(ViewGtk *view) +{ + gchar buffer[256]; + + /* + * Generates a CSS that sets some predefined color variables. + * This effectively "exports" Scintilla styles into the CSS + * world. + * Those colors are used by the fallback.css shipping with SciTECO + * in order to apply the SciTECO-controlled color scheme to all the + * predefined UI elements. + * They can also be used in user-customizations. + */ + g_snprintf(buffer, sizeof(buffer), + "@define-color sciteco_default_fg_color " CSS_COLOR_FORMAT ";" + "@define-color sciteco_default_bg_color " CSS_COLOR_FORMAT ";" + "@define-color sciteco_calltip_fg_color " CSS_COLOR_FORMAT ";" + "@define-color sciteco_calltip_bg_color " CSS_COLOR_FORMAT ";", + bgr2rgb(view->ssm(SCI_STYLEGETFORE, STYLE_DEFAULT)), + bgr2rgb(view->ssm(SCI_STYLEGETBACK, STYLE_DEFAULT)), + bgr2rgb(view->ssm(SCI_STYLEGETFORE, STYLE_CALLTIP)), + bgr2rgb(view->ssm(SCI_STYLEGETBACK, STYLE_CALLTIP))); + + /* + * The GError and return value has been deprecated. + * A CSS parsing error would point to a programming + * error anyway. + */ + gtk_css_provider_load_from_data(css_var_provider, buffer, -1, NULL); +} + +void InterfaceGtk::event_loop_impl(void) { static const gchar *icon_files[] = { @@ -491,6 +550,10 @@ InterfaceGtk::event_loop_impl(void) NULL }; + GdkScreen *default_screen = gdk_screen_get_default(); + GtkCssProvider *user_css_provider; + gchar *config_path, *user_css_file; + GList *icon_list = NULL; GThread *thread; @@ -516,6 +579,41 @@ InterfaceGtk::event_loop_impl(void) refresh_info(); /* + * Initialize the CSS variable provider and the CSS provider + * for the included fallback.css. + * NOTE: The return value of gtk_css_provider_load() is deprecated. + * Instead we could register for the "parsing-error" signal. + * For the time being we just silently ignore parsing errors. + * They will be printed to stderr by Gtk anyway. + */ + css_var_provider = gtk_css_provider_new(); + if (current_view) + /* set CSS variables initially */ + set_css_variables_from_view(current_view); + gtk_style_context_add_provider_for_screen(default_screen, + GTK_STYLE_PROVIDER(css_var_provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + user_css_provider = gtk_css_provider_new(); + /* get path of $SCITECOCONFIG/.teco_css */ + config_path = QRegisters::globals["$SCITECOCONFIG"]->get_string(); + user_css_file = g_build_filename(config_path, USER_CSS_FILE, NIL); + if (g_file_test(user_css_file, G_FILE_TEST_IS_REGULAR)) + /* open user CSS */ + gtk_css_provider_load_from_path(user_css_provider, + user_css_file, NULL); + else + /* use fallback CSS */ + gtk_css_provider_load_from_path(user_css_provider, + SCITECODATADIR G_DIR_SEPARATOR_S + "fallback.css", + NULL); + g_free(user_css_file); + g_free(config_path); + gtk_style_context_add_provider_for_screen(default_screen, + GTK_STYLE_PROVIDER(user_css_provider), + GTK_STYLE_PROVIDER_PRIORITY_USER); + + /* * When changing views, the new widget is not * added immediately to avoid flickering in the GUI. * It is only updated once per key press and only @@ -702,6 +800,12 @@ InterfaceGtk::handle_key_press(bool is_shift, bool is_ctl, guint keyval) } /* + * The styles configured via Scintilla might change + * with every keypress. + */ + set_css_variables_from_view(current_view); + + /* * The info area is updated very often and setting the * window title each time it is updated is VERY costly. * So we set it here once after every keypress even if the @@ -739,8 +843,7 @@ InterfaceGtk::handle_key_press(bool is_shift, bool is_ctl, guint keyval) InterfaceGtk::~InterfaceGtk() { g_free(info_current); - if (popup_widget) - gtk_widget_destroy(popup_widget); + if (window) gtk_widget_destroy(window); @@ -754,6 +857,9 @@ InterfaceGtk::~InterfaceGtk() g_async_queue_unref(event_queue); } + + if (css_var_provider) + g_object_unref(css_var_provider); } /* diff --git a/src/interface-gtk/interface-gtk.h b/src/interface-gtk/interface-gtk.h index 4563d5f..eff4597 100644 --- a/src/interface-gtk/interface-gtk.h +++ b/src/interface-gtk/interface-gtk.h @@ -75,6 +75,8 @@ public: } ViewCurrent; typedef class InterfaceGtk : public Interface<InterfaceGtk, ViewGtk> { + GtkCssProvider *css_var_provider; + GtkWidget *window; GtkWidget *vbox; @@ -102,7 +104,7 @@ typedef class InterfaceGtk : public Interface<InterfaceGtk, ViewGtk> { GAsyncQueue *event_queue; public: - InterfaceGtk() : Interface(), + InterfaceGtk() : css_var_provider(NULL), window(NULL), vbox(NULL), info_type(INFO_TYPE_BUFFER), info_current(NULL), @@ -170,6 +172,8 @@ public: private: static void widget_set_font(GtkWidget *widget, const gchar *font_name); + void set_css_variables_from_view(ViewGtk *view); + void refresh_info(void); void cmdline_insert_chr(gint &pos, gchar chr); } InterfaceCurrent; |