Skip to content

Commit

Permalink
Fix #239, support theme specific CSS
Browse files Browse the repository at this point in the history
  • Loading branch information
gnunn1 committed Apr 30, 2016
1 parent be97fb3 commit 80331b0
Show file tree
Hide file tree
Showing 14 changed files with 316 additions and 147 deletions.
11 changes: 11 additions & 0 deletions data/resources/css/terminix.Adwaita.scrollbar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* GTK 3.20 */
scrollbar {
background: $TERMINAL_BG;
opacity: $TERMINAL_OPACITY;
}
/* GTK 3.18 */
.scrollbar:not(.slider) {
background: $TERMINAL_BG;
opacity: $TERMINAL_OPACITY;
border-left: 0px;
}
File renamed without changes.
4 changes: 4 additions & 0 deletions data/resources/css/terminix.Ambiance.scrollbar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.scrollbar:not(.slider) {
background: $TERMINAL_BG;
opacity: $TERMINAL_OPACITY;
}
5 changes: 5 additions & 0 deletions data/resources/css/terminix.Lavender.scrollbar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/* GTK 3.20 */
scrollbar {
background: $TERMINAL_BG;
opacity: $TERMINAL_OPACITY;
}
36 changes: 36 additions & 0 deletions data/resources/css/terminix.Radiance.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/** Ambiance specific CSS to fix Ubuntu problems so the rest of us can have nice things **/

/* Fix Ubuntu Popover label borders, see #217 */
GtkBox > .label.separator {
border: 0px;
color: @theme_fg_color;
opacity: 0.4;
}

/* Add background to pane-separator */
.pane-separator {
background-color: @theme_bg_color;
}

/* Attempt to improve scrollbars */
.terminix-terminal-scrollbar:hover:not(.slider),
.terminix-terminal-scrollbar.dragging:not(.slider) {
background-color: alpha(@scrollbar_track_color, 0.4);
}

/* Since .hovering class is not working here, we always use the same radius */
.terminix-terminal-scrollbar.slider.hovering,
.terminix-terminal-scrollbar.slider.dragging {
/*border-radius: 1px;*/
border-left: 0px;
}

.terminix-terminal-scrollbar.vertical:hover:dir(ltr),
.terminix-terminal-scrollbar.vertical.dragging:dir(ltr) {
margin-left: 0px;
}

.terminix-terminal-scrollbar.vertical:hover:dir(rtl),
.terminix-terminal-scrollbar.vertical.dragging:dir(rtl) {
margin-right: 0px;
}
4 changes: 4 additions & 0 deletions data/resources/css/terminix.Radiance.scrollbar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.scrollbar:not(.slider) {
background: $TERMINAL_BG;
opacity: $TERMINAL_OPACITY;
}
File renamed without changes.
9 changes: 7 additions & 2 deletions data/resources/terminix.gresource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
<gresource prefix="/com/gexperts/Terminix">
<file>icons/scalable/actions/terminix-split-tab-right-symbolic.svg</file>
<file>icons/scalable/actions/terminix-split-tab-down-symbolic.svg</file>
<file>css/terminix.adwaita.css</file>
<file>css/terminix.ambiance.css</file>
<file>css/terminix.base.css</file>
<file>css/terminix.Ambiance.css</file>
<file>css/terminix.Radiance.css</file>
<file>css/terminix.Adwaita.scrollbar.css</file>
<file>css/terminix.Lavender.scrollbar.css</file>
<file>css/terminix.Ambiance.scrollbar.css</file>
<file>css/terminix.Radiance.scrollbar.css</file>
<file compressed="true" preprocess="xml-stripblanks">ui/shortcuts.ui</file>
</gresource>
</gresources>
115 changes: 115 additions & 0 deletions source/gx/gtk/resource.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
* distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
module gx.gtk.resource;

import std.array;
import std.conv;
import std.experimental.logger;
import std.file;
import std.format;
import std.path;

import gdk.Screen;

import glib.Bytes;
import glib.GException;
import glib.Util;

import gio.Resource;

import gtk.CssProvider;
import gtk.StyleContext;

import gtkc.giotypes;

/**
* Defined here since not defined in GtkD
*/
enum ProviderPriority : uint {
FALLBACK = 1,
THEME = 200,
SETTINGS = 400,
APPLICATION = 600,
USER = 800
}

/**
* Find and optionally register a resource
*/
Resource findResource(string resourcePath, bool register = true) {
foreach (path; Util.getSystemDataDirs()) {
auto fullpath = buildPath(path, resourcePath);
trace("looking for resource " ~ fullpath);
if (exists(fullpath)) {
Resource resource = Resource.load(fullpath);
if (register && resource) {
trace("Resource found and registered " ~ fullpath);
Resource.register(resource);
}
return resource;
}
}
error(format("Resource %s could not be found", resourcePath));
return null;
}

CssProvider createCssProvider(string filename, string[string] variables = null) {
try {
CssProvider provider = new CssProvider();
string css = getResource(filename, variables);
if (css.length > 0) {
if (provider.loadFromData(css)) {
return provider;
}
}
} catch (GException ge) {
trace("Unexpected error loading css provider " ~ filename);
trace("Error: " ~ ge.msg);
}
return null;
}

/**
* Adds a CSSProvider to the default screen, if no provider is found it
* returns null
*/
CssProvider addCssProvider(string filename, ProviderPriority priority, string[string] variables = null) {
try {
CssProvider provider = createCssProvider(filename, variables);
if (provider !is null) {
StyleContext.addProviderForScreen(Screen.getDefault(), provider, priority);
return provider;
}
} catch (GException ge) {
trace("Unexpected error loading css provider " ~ filename);
trace("Error: " ~ ge.msg);
}
return null;
}

private:

/**
* Loads a textual resource and performs string subsitution based on key-value pairs
*/
string getResource(string filename, string[string] variables = null) {
Bytes bytes;
try {
bytes = Resource.resourcesLookupData(filename, GResourceLookupFlags.NONE);
} catch (GException ge) {
error("Unexpected error loading resource " ~ filename);
error("Error: " ~ ge.msg);
}
if (bytes is null || bytes.getSize() == 0) return null;
else {
string contents = to!string(cast(char*)bytes.getData());
if (variables !is null) {
foreach(variable; variables.byKeyValue()) {
contents = contents.replace(variable.key, variable.value);
}
}
return contents;
}
}
51 changes: 0 additions & 51 deletions source/gx/gtk/util.d
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,12 @@ module gx.gtk.util;

import std.conv;
import std.experimental.logger;
import std.file;
import std.format;
import std.path;

import gdk.RGBA;
import gdk.Screen;

import gio.File : GFile = File;
import gio.Resource;

import glib.GException;
import glib.ListG;
import glib.Util;

import gobject.ObjectG;
import gobject.Value;
Expand All @@ -28,7 +21,6 @@ import gtk.Box;
import gtk.ComboBox;
import gtk.CellRendererText;
import gtk.Container;
import gtk.CssProvider;
import gtk.Entry;
import gtk.ListStore;
import gtk.MessageDialog;
Expand Down Expand Up @@ -171,17 +163,6 @@ bool showInputDialog(Window parent, out string value, string initialValue = null
}
}

/**
* Defined here since not defined in GtkD
*/
enum ProviderPriority : uint {
FALLBACK = 1,
THEME = 200,
SETTINGS = 400,
APPLICATION = 600,
USER = 800
}

/**
* Defined here since not defined in GtkD
*/
Expand Down Expand Up @@ -253,38 +234,6 @@ string rgbaTo16bitHex(RGBA color, bool includeAlpha = false, bool includeHash =
}
}

Resource findResource(string resourcePath, bool register = true) {
foreach (path; Util.getSystemDataDirs()) {
auto fullpath = buildPath(path, resourcePath);
trace("looking for resource " ~ fullpath);
if (exists(fullpath)) {
Resource resource = Resource.load(fullpath);
if (register && resource) {
trace("Resource found and registered " ~ fullpath);
Resource.register(resource);
}
return resource;
}
}
error(format("Resource %s could not be found", resourcePath));
return null;
}

CssProvider addCssProvider(string filename, ProviderPriority priority) {
try {
CssProvider provider = new CssProvider();
if (provider.loadFromFile(GFile.parseName(filename))) {
StyleContext.addProviderForScreen(Screen.getDefault(), provider, priority);
return provider;
}
}
catch (GException ge) {
error("Unexpected error loading resource " ~ filename);
error("Error: " ~ ge.msg);
}
return null;
}

/**
* Appends multiple values to a row in a list store
*/
Expand Down
67 changes: 44 additions & 23 deletions source/gx/terminix/application.d
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import gtk.Widget;
import gtk.Window;

import gx.gtk.actions;
import gx.gtk.resource;
import gx.gtk.util;
import gx.i18n.l10n;
import gx.terminix.appwindow;
Expand All @@ -63,8 +64,20 @@ import gx.terminix.shortcuts;

static import gx.util.array;


/**
* Global variable to application
*/
Terminix terminix;

/**
* Invoked when the GTK theme has changed. While things could
* listen to gtk.Settings.addOnNotify directly, because this is a
* long lived object and GtkD doesn't provide a way to remove
* listeners it will lead to memory leaks so we use this instead
*/
alias OnThemeChanged = void delegate(string theme);

/**
* The GTK Application used by Terminix.
*/
Expand Down Expand Up @@ -97,7 +110,9 @@ private:

bool warnedVTEConfigIssue = false;

CssProvider ambianceProvider;
CssProvider themeCssProvider;

OnThemeChanged[] themeChangedDelegates;

/**
* Load and register binary resource file and add css files as providers
Expand All @@ -106,24 +121,18 @@ private:
//Load resources
if (findResource(APPLICATION_RESOURCES, true)) {
foreach (cssFile; APPLICATION_CSS_RESOURCES) {
string cssURI = buildPath(APPLICATION_RESOURCE_ROOT, cssFile);
string cssURI = APPLICATION_RESOURCE_ROOT ~ "/" ~ cssFile;
if (!addCssProvider(cssURI, ProviderPriority.APPLICATION)) {
error(format("Could not load CSS %s", cssURI));
}
}
}
if (getGtkTheme() == THEME_AMBIANCE) {
loadAmbianceResource();
}
}

void loadAmbianceResource() {
string ambianceURI = buildPath(APPLICATION_RESOURCE_ROOT, APPLICATION_CSS_AMBIANCE);
ambianceProvider = addCssProvider(ambianceURI, ProviderPriority.APPLICATION);
if (!ambianceProvider) {
error(format("Could not load CSS %s", ambianceURI));
} else {
trace("Loaded Terminix Ambiance CSS");
//Check if terminix has a theme specific CSS file to load
string theme = getGtkTheme();
string cssURI = APPLICATION_RESOURCE_ROOT ~ "/css/terminix." ~ theme ~ ".css";
themeCssProvider = addCssProvider(cssURI, ProviderPriority.APPLICATION);
if (!themeCssProvider) {
trace(format("No specific CSS found %s", cssURI));
}
}

Expand Down Expand Up @@ -337,15 +346,19 @@ private:
void onThemeChange(ParamSpec, ObjectG) {
string theme = getGtkTheme();
trace("Theme changed to " ~ theme);
if (theme == THEME_AMBIANCE) {
if (ambianceProvider is null)
loadAmbianceResource();
} else {
if (ambianceProvider !is null) {
StyleContext.removeProviderForScreen(Screen.getDefault(), ambianceProvider);
ambianceProvider = null;
}
}
if (themeCssProvider !is null) {
StyleContext.removeProviderForScreen(Screen.getDefault(), themeCssProvider);
themeCssProvider = null;
}
//Check if terminix has a theme specific CSS file to load
string cssURI = APPLICATION_RESOURCE_ROOT ~ "/css/terminix." ~ theme ~ ".css";
themeCssProvider = addCssProvider(cssURI, ProviderPriority.APPLICATION);
if (!themeCssProvider) {
trace(format("No specific CSS found %s", cssURI));
}
foreach(dlg; themeChangedDelegates) {
dlg(theme);
}
}

void onAppStartup(GApplication) {
Expand Down Expand Up @@ -624,4 +637,12 @@ public:
}
}
}

void addOnThemeChanged(OnThemeChanged dlg) {
themeChangedDelegates ~= dlg;
}

void removeOnThemeChanged(OnThemeChanged dlg) {
gx.util.array.remove(themeChangedDelegates, dlg);
}
}
Loading

0 comments on commit 80331b0

Please sign in to comment.