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 | |
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...)
-rw-r--r-- | doc/sciteco.1.in | 13 | ||||
-rw-r--r-- | doc/sciteco.7.template | 48 | ||||
-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 |
7 files changed, 234 insertions, 18 deletions
diff --git a/doc/sciteco.1.in b/doc/sciteco.1.in index 1d21ecf..0a96cab 100644 --- a/doc/sciteco.1.in +++ b/doc/sciteco.1.in @@ -314,6 +314,19 @@ standard library \fBsession.tes\fP macros. When the \(lqsession.vcs\(rq macro is used, these files will also be created in the roots of Git, Mercurial and Subversion repositories or working copies. +.TP +.B $SCITECOCONFIG/.teco_css +When using the Gtk UI, this will be the location of a +CSS file that can be used to apply \*(ST color schemes +to the entire UI and to do other style customizations. +.TP +.B @pkgdatadir@/fallback.css +When using the Gtk UI, this is a fallback stylesheet +in case +.B $SCITECOCONFIG/.teco_css +does not exist. +It may also be used as a template for +.BR $SCITECOCONFIG/.teco_css . . . .SH SEE ALSO diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template index bdb25bc..9f3ba8f 100644 --- a/doc/sciteco.7.template +++ b/doc/sciteco.7.template @@ -688,6 +688,48 @@ macro or \fBED\fP hook (for syntax highlighting). \*(ST ships with a standard library with color schemes and lexer configurations for a wide range of languages. . +.SS Gtk CSS Styling +. +While the tools mentioned above are sufficient for +Curses UIs, the Gtk+ 3 UI has many more styling possibilities. +The basic color scheme will be automatically effective for +the buffer view since this is handled by Scintilla. +In order to apply the color scheme to the other UI components, +a CSS file must be provided that overrides certain styling +settings of the Gtk theme. +.LP +Therefore \*(ST automatically exports the following Gtk +CSS variables that can be referred to by user-provided +CSS files: +.TP +.B @sciteco_default_fg_color +The foreground color of Scintilla's \fBSTYLE_DEFAULT\fP. +.TP +.B @sciteco_default_bg_color +The background color of Scintilla's \fBSTYLE_DEFAULT\fP. +.TP +.B @sciteco_calltip_fg_color +The foreground color of Scintilla's \fBSTYLE_CALLTIP\fP. +.TP +.B @sciteco_calltip_bg_color +The background color of Scintilla's \fBSTYLE_CALLTIP\fP. +.LP +Furthermore, \*(ST defines the following named widgets for its +main UI components: \fB#sciteco-info-bar\fP, \fB#sciteco-message-bar\fP, +\fB#sciteco-cmdline\fP and \fB#sciteco-info-popup\fP. +.LP +The CSS file is loaded from +.B $SCITECOCONFIG/.teco_css +if it is existing. +Else, \*(ST loads the fallback CSS at +.BR @pkgdatadir@/fallback.css , +which can also be used as a template when writing \fB.teco_css\fP. +The CSS file can be written such that it works for any +\*(ST color scheme and may also be used to tweak other +aspects of \*(ST's user interface. +Please refer to the Gtk documentation for more details on +CSS theming. +. . .SH ARITHMETICS AND EXPRESSIONS . @@ -1792,6 +1834,12 @@ Scinterm manual, documenting the mapping of .UR http://foicica.com/scinterm/manual.html Scinterm manual .UE +.TP +Gtk+ 3 documentation, containg details about +its CSS support and syntax: +.UR https://developer.gnome.org/gtk3/stable/GtkCssProvider.html +GtkCssProvider +.UE . . .SH AUTHOR 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; |