aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2016-02-02 14:42:58 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2016-02-02 17:49:42 +0100
commite768487fe3ef9ec8f94cea11ad6587c49c32422a (patch)
tree2d9b3a6fdea2fc8dc06c4fbd548eee4b9bf95cab
parent8627a00e3b25cdd80d88ddcef9d2d73cc784d571 (diff)
downloadsciteco-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.in13
-rw-r--r--doc/sciteco.7.template48
-rw-r--r--src/interface-gtk/Makefile.am2
-rw-r--r--src/interface-gtk/fallback.css47
-rw-r--r--src/interface-gtk/gtk-info-popup.gob16
-rw-r--r--src/interface-gtk/interface-gtk.cpp120
-rw-r--r--src/interface-gtk/interface-gtk.h6
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;