I’m working on a script to edit gnome-shell theme colors. It works … at least with this slightly modified gnome-shell.css (the one used on the picture below, still half blue, half green now).
Here’s the script, a “simple” bash script, using yad* to draw the form.
#! /bin/bash
#
#: Title : gstheme
#: Date Created : Fri Dec 23 20:18:34 PST 2011
#: Last Edit : Fri Dec 23 20:18:34 PST 2011
#: Author : Agnelo de la Crotche (please_try_again)
#: Version : 1.0
#: Description : Edit Gnome-shell colors
#: Syntax : gsthemes
#: Options : none
themedir_def=/usr/share/gnome-shell/themes
# to use another theme directory, uncomment this line and specify a path
#themedir=/usr/local/share/gnome-shell/themes
# this is just for me.
function localtheme {
which lsb_release &>/dev/null && DIST=`$(which lsb_release) -si | tr -d " " | sed 's|SUSELINUX|openSUSE|;s|MandrivaLinux|Mandriva|'`
if [ "x$DIST" == "xn/a" ] ; then
[ -f /etc/lsb-release ] && DIST=$(awk -F "=" '/DISTRIB/ { print $2 }' /etc/lsb-release | tr -d " \"")
elif [ "x$DIST" == "x" ] ; then
if [ -f /etc/SuSE-release ] ; then
DIST=openSUSE
elif [ -f /etc/fedora-release ] ; then
DIST=Fedora
elif [ -f /etc/mandriva-release ] ; then
DIST=Mandriva
elif [ -f /etc/lsb-release ] ; then
DIST=$(awk -F "=" '/DISTRIB/ { print $2 }' /etc/lsb-release | tr -d " \"")
fi
fi
echo $DIST
}
which yad &>/dev/null || exec echo "yad not installed."
#localethemedir=/usr/local/config/themes/niglo-$(localtheme)/gnome-shell
#themedir=${localethemedir:-$themedir}
themedir=${themedir:-$themedir_def}
[ -d $themedir ] || themedir=$themedir_def
themecss=$themedir/gnome-shell.css
title="gnome-shellColors"
colorItems=(
'StScrollBar_StButton#vhandle@background-color' \
'StScrollBar_StButton#hhandle@background-color' \
'StScrollBar_StButton#vhandle:hover@background-color' \
'.popup-menu-boxpointer@-arrow-border-color' \
'.popup-menu@color' \
'.popup-menu-item:active@background-color' \
'.popup-separator-menu-item@-gradient-end' \
'.popup-slider-menu-item@-slider-background-color' \
'.popup-slider-menu-item@-slider-active-background-color' \
'.modal-dialog-button@background-gradient-start' \
'.modal-dialog-button@background-gradient-end' \
'.modal-dialog-button:hover@background-gradient-start' \
'.modal-dialog-button:hover@background-gradient-end' \
'.modal-dialog-button:pressed@background-gradient-start' \
'.modal-dialog-button:pressed@background-gradient-end' \
'.panel-button@color' \
'.panel-button:hover@color' \
'.panel-button:focus@color' \
'.window-caption@color' \
'.workspace-thumbnail-indicator@outline' \
'#searchEntry@color' \
'#searchEntry:hover@color' \
'#searchEntry:hover@background-gradient-start' \
'#searchEntry:hover@background-gradient-end' \
'#searchEntry:focus@color' \
'#searchEntry:focus@background-gradient-start' \
'#searchEntry:focus@background-gradient-end' \
'.search-entry-icon@color' \
'.view-tab-title@color' \
'.view-tab-title:hover@color' \
'.view-tab-title:selected@color' \
'.view-tab-title:selected@background-color' \
'.app-filter@color' \
'.app-filter:hover@color' \
'.contact:selected@background-color' \
'.search-result-content:hover___.overview-icon@background-color' \
'.search-result-content:hover___.overview-icon@color' \
'.calendar-vertical-separator@-stipple-color' \
'.calendar-month-label@color' \
'.calendar-change-month-back:hover@background-color' \
'.calendar-change-month-back:active@background-color' \
'.calendar-change-month-forward:hover@background-color' \
'.calendar-change-month-forward:active@background-color' \
'.calendar-day-base:hover@color' \
'.calendar-day-base:hover@background-color' \
'.calendar-day-base:active@background-color' \
'.calendar-day-heading@color' \
'.calendar-day-with-events@color' \
'.events-day-header@color' \
'.events-day-task@color' \
'.switcher-list@background' \
'.switcher-list@border' \
'.switcher-list_.item-box:selected@background' \
'.workspace-switcher-container@background' \
'.ws-switcher-active-up@background' \
'.ws-switcher-active-down@background' \
'.modal-dialog@border' \
'.modal-dialog@color' \
'.run-dialog-label@color' \
'.run-dialog-error-label@color' \
'.polkit-dialog-password-entry@background-gradient-start' \
'.polkit-dialog-password-entry@background-gradient-end' \
'.polkit-dialog-password-entry@border' \
'.polkit-dialog-password-entry:focus@border' \
)
colors=""
ncolors=""
sedcmd=""
[ "$themecss" ] || { echo "No Theme css defined."; exit 3; }
[ -f $themecss ] || { echo "Theme css not found."; exit 1; }
[ -w $themecss ] || { echo "Theme css not writable."; exit 2;}
for I in ${colorItems[li]} ; do
[/li] class=${I%@*} ; Class=${class//_/ } ; Class=${Class/ / > }
color=${I#*@} ; Color=${color//-/_}
clr="$class\\
$color"
rgb=$(sed = $themecss | sed 'N;s/
/ /' | sed 's/\([0-9]*\) \(.*\)/\2 |\1/' | sed -n "/$Class *{* *|.*$/,/}/p" | sed "s|$color|$Color|;s|^[ ]*||" | sed -n "/^$Color *:/p" | awk '{ print $NF, $(NF-1)}' | sed 's/|\([0-9]*\) \(.*\);/\1s|\2/')
ncolors=(${ncolors[li]} $rgb)
[/li] colors="$colors --field=$clr:CLR \"${rgb#*|}\""
done
rcolors=(`eval $(echo yad --form $colors --title="$title" --columns=4) | sed 's/|/| /g;s/\([0-9a-fA-F]\{2\}\)[0-9a-fA-F]\{2\}/\1/g'`)
if [ ${#ncolors[li]} -eq ${#rcolors[*]} ] ; then
[/li] i=0
while [ $i -lt ${#ncolors[li]} ] ; do
[/li] sedcmd="$sedcmd${ncolors[$i]}|${rcolors[$i]};"
let i++
done
cp $themecss{,.orig}
eval $(echo sed -i -e "'$sedcmd'" $themecss)
else
echo "index out of range."
exit 4
fi
You can easily add or remove classes/properties in the array colorItems to change other elements.
After changing one or more colors and presssing OK, the CSS file (which path can be defined in the script) gets rewritten with the new color values. In order to reload the theme, I have to fire up the Gnome-shell prompt (ALT-F2) and type: rt. Hence my question, if somebody knows the answer: How can I reload the gnome-shell theme from my script in order to reflect the changes immediately? Is there an equivalent to “metacity-message reload-theme” in Gnome-shell or “ALT-F2 … rt” in the command line? I tried to use dbus-monitor, dconf watch and the Gnome shell’s Looking Glass, but ALT-F2 prompt isn’t caught by anyone and I could not figure out which command it sends when typing “rt” (most likely standing for “reload theme”).
I googled for a couple hours but couldn’t find the answer.
I’m sorry I can’t help you find the answer to the issue at hand. I do have a couple questions if you don’t mind. I’m familiar with CSS from building many websites of my own. Nice work! Does this file replace a Gnome CSS file somewhere or is it in addition? I’d love to implement this. Secondly, a bit off topic, what is the stats app you have running on the right side of the display? Love that!
The script just reads and writes color properties from a CSS file (in this case gnome-shell.css). But you could use it for any CSS file in theory (depends how it is written though since the script has to parse it).
Well, it’s a kind of quick an dirty bash script that I wrote to save me time by editing 4 or 5 gnome-shell themes. But it’s not really appropriate for huge CSS files for the stupid reason that I can not resize the form to make it smaller (only larger but it wouldn’t help on a small resolution). There must be better ways to view and replace colors in a large number of CSS files, such as PHP, Python or Java scripts (which would let you scroll up and down in a browser). I’m sure those apps exist or HTML editors have this feature.
I just discovered yad recently while trying to do something that wasn’t possible with zenity, of which yad is a fork. For example, the following in a bash script:
myColor=$(yad --color)
displays the color selection dialog and returns the color in the variable $myColor. This can be very useful to set colors from shell scripts.
Looking for " rt " in the gnome-shell source, I found the function used to load/reload a theme: Main.loadTheme(). Typing Main.loadTheme() in Gnome-shell js console (LookingGlass) does indeed reload the theme. So basically, I would have to be able to execute this function in a terminal (or from a script) rather than in Looking Glass (which doesn’t help me in a script). I also found that the java script interpreter in Gnome-shell context is called gjs](http://live.gnome.org/Gjs) and I was able to use it with some hello.world program as argument. To use Main.loadTheme() in a java script or as a string passed to gjs, I need to import ui.main (just like the user theme extension does), but as soon as I do that, I get an error about Meta and missing TypeLib.
/tmp>** # gjs -c "Main.loadTheme();"**
JS ERROR: !!! Exception was: ReferenceError: Main is not defined
JS ERROR: !!! lineNumber = '1'
JS ERROR: !!! fileName = '"<command line>"'
JS ERROR: !!! stack = '"@<command line>:1
"'
JS ERROR: !!! message = '"Main is not defined"'
ReferenceError: Main is not defined
/tmp> **#gjs -c "const Main = imports.ui.main ; Main.loadTheme();"**
JS ERROR: !!! Exception was: Error: No JS module 'ui' found in search path
JS ERROR: !!! lineNumber = '0'
JS ERROR: !!! fileName = '"gjs_throw"'
JS ERROR: !!! stack = '"("No JS module 'ui' found in search path")@gjs_throw:0
@<command line>:1
"'
JS ERROR: !!! message = '"No JS module 'ui' found in search path"'
Error: No JS module 'ui' found in search path
/tmp> **#gjs -I /usr/share/gnome-shell/js -c "const Main = imports.ui.main ; Main.loadTheme();"**
JS ERROR: !!! Exception was: Error: Requiring Meta, version none: Typelib file for namespace 'Meta' (any version) not found
JS ERROR: !!! lineNumber = '0'
JS ERROR: !!! fileName = '"gjs_throw"'
JS ERROR: !!! stack = '"("Requiring Meta, version none: Typelib file for namespace 'Meta' (any version) not found")@gjs_throw:0
@/usr/share/gnome-shell/js/ui/main.js:11
"'
JS ERROR: !!! message = '"Requiring Meta, version none: Typelib file for namespace 'Meta' (any version) not found"'
JS ERROR: !!! Exception was: Error: Requiring Meta, version none: Typelib file for namespace 'Meta' (any version) not found
JS ERROR: !!! lineNumber = '0'
JS ERROR: !!! fileName = '"gjs_throw"'
JS ERROR: !!! stack = '"("Requiring Meta, version none: Typelib file for namespace 'Meta' (any version) not found")@gjs_throw:0
@/usr/share/gnome-shell/js/ui/main.js:11
"'
JS ERROR: !!! message = '"Requiring Meta, version none: Typelib file for namespace 'Meta' (any version) not found"'
Error: Requiring Meta, version none: Typelib file for namespace 'Meta' (any version) not found
# sed -n '11p' /usr/share/gnome-shell/js/ui/main.js
const Meta = imports.gi.Meta;
Does anyone know how I could possibly execute “Main.loadTheme();” on the command line or in a mini java script? Actually I’m not able to launch any gnome-shell extension from the command line either.
I added a “Refresh” button that writes the changed colors to the CSS file and restarts the script (to draw the new colors). Until I find how to refresh the theme in the script, you have to press ALT-F2 ant enter rt to reload the theme after each refresh.
Also added an “Edit” button to open the CSS file in an editor (default is gvim but you can change that) and couple classes for the Looking Glass.
#! /bin/bash
#
#: Title : gstheme
#: Date Created : Fri Dec 23 20:18:34 PST 2011
#: Last Edit : Sun Dec 25 06:31:12 PST 2011
#: Author : Agnelo de la Crotche (please_try_again)
#: Version : 1.2
#: Description : Edit Gnome-shell colors
#: Syntax : gstheme
#: Options : none
themedir_def=/usr/share/gnome-shell/themes
editor=gvim
# to use another theme directory, uncomment this line and specify a path
#themedir=/usr/local/share/gnome-shell/themes
# this is just for me.
function localtheme {
which lsb_release &>/dev/null && DIST=`$(which lsb_release) -si | tr -d " " | sed 's|SUSELINUX|openSUSE|;s|MandrivaLinux|Mandriva|'`
if [ "x$DIST" == "xn/a" ] ; then
[ -f /etc/lsb-release ] && DIST=$(awk -F "=" '/DISTRIB/ { print $2 }' /etc/lsb-release | tr -d " \"")
elif [ "x$DIST" == "x" ] ; then
if [ -f /etc/SuSE-release ] ; then
DIST=openSUSE
elif [ -f /etc/fedora-release ] ; then
DIST=Fedora
elif [ -f /etc/mandriva-release ] ; then
DIST=Mandriva
elif [ -f /etc/lsb-release ] ; then
DIST=$(awk -F "=" '/DISTRIB/ { print $2 }' /etc/lsb-release | tr -d " \"")
fi
fi
echo $DIST
}
which yad &>/dev/null || exec echo "yad not installed."
localethemedir=/usr/local/config/themes/niglo-$(localtheme)/gnome-shell
themedir=${localethemedir:-$themedir}
themedir=${themedir:-$themedir_def}
[ -d $themedir ] || themedir=$themedir_def
themecss=$themedir/gnome-shell.css
title="gnome-shellColors"
colorItems=(
'StScrollBar_StButton#vhandle@background-color' \
'StScrollBar_StButton#hhandle@background-color' \
'StScrollBar_StButton#vhandle:hover@background-color' \
'.popup-menu-boxpointer@-arrow-border-color' \
'.popup-menu@color' \
'.popup-menu-item:active@background-color' \
'.popup-separator-menu-item@-gradient-end' \
'.popup-slider-menu-item@-slider-background-color' \
'.popup-slider-menu-item@-slider-active-background-color' \
'.modal-dialog-button@background-gradient-start' \
'.modal-dialog-button@background-gradient-end' \
'.modal-dialog-button:hover@background-gradient-start' \
'.modal-dialog-button:hover@background-gradient-end' \
'.modal-dialog-button:pressed@background-gradient-start' \
'.modal-dialog-button:pressed@background-gradient-end' \
'.panel-button@color' \
'.panel-button:hover@color' \
'.panel-button:focus@color' \
'.window-caption@color' \
'.workspace-thumbnail-indicator@outline' \
'#searchEntry@color' \
'#searchEntry:hover@color' \
'#searchEntry:hover@background-gradient-start' \
'#searchEntry:hover@background-gradient-end' \
'#searchEntry:focus@color' \
'#searchEntry:focus@background-gradient-start' \
'#searchEntry:focus@background-gradient-end' \
'.search-entry-icon@color' \
'.view-tab-title@color' \
'.view-tab-title:hover@color' \
'.view-tab-title:selected@color' \
'.view-tab-title:selected@background-color' \
'.app-filter@color' \
'.app-filter:hover@color' \
'.contact:selected@background-color' \
'.search-result-content:hover___.overview-icon@background-color' \
'.search-result-content:hover___.overview-icon@color' \
'.calendar-vertical-separator@-stipple-color' \
'.calendar-month-label@color' \
'.calendar-change-month-back:hover@background-color' \
'.calendar-change-month-back:active@background-color' \
'.calendar-change-month-forward:hover@background-color' \
'.calendar-change-month-forward:active@background-color' \
'.calendar-day-base:hover@color' \
'.calendar-day-base:hover@background-color' \
'.calendar-day-base:active@background-color' \
'.calendar-day-heading@color' \
'.calendar-day-with-events@color' \
'.events-day-header@color' \
'.events-day-task@color' \
'.switcher-list@background' \
'.switcher-list@border' \
'.switcher-list_.item-box:selected@background' \
'.workspace-switcher-container@background' \
'.ws-switcher-active-up@background' \
'.ws-switcher-active-down@background' \
'.modal-dialog@border' \
'.modal-dialog@color' \
'.run-dialog-label@color' \
'.run-dialog-error-label@color' \
'.polkit-dialog-password-entry@background-gradient-start' \
'.polkit-dialog-password-entry@background-gradient-end' \
'.polkit-dialog-password-entry@border' \
'.polkit-dialog-password-entry:focus@border' \
'#LookingGlassDialog@color' \
'#LookingGlassDialog_.notebook-tab@color' \
'#LookingGlassDialog_.notebook-tab:hover@color' \
'.lg-dialog_StLabel@color' \
'.lg-dialog_StEntry@color' \
'.lg-dialog_StEntry@selection-background-color' \
'.lg-dialog_StEntry@selected-color' \
'.lg-obj-inspector-button@border' \
'.lg-obj-inspector-button:hover@border' \
'.lg-dialog_.shell-link@color' \
'.lg-dialog_.shell-link:hover@color' \
)
colors=""
declare -a ncolors
ret=2
[ "$themecss" ] || { echo "No Theme css defined."; exit 3; }
[ -f $themecss ] || { echo "Theme css not found."; exit 2; }
[ -w $themecss ] || { echo "Theme css not writable."; exit 4;}
function reloadTheme {
printf "What's missing?
gjs -I /usr/share/gnome-shell/js -c \"const Main = imports.ui.main; Main.loadTheme();\"
"
}
function getcolors {
colors=""
ncolors=()
for I in ${colorItems[li]} ; do
[/li] class=${I%@*} ; Class=${class//_/ } ; Class=${Class/ / > }
color=${I#*@} ; Color=${color//-/_}
clr="$Class\\
$color"
rgb=$(sed = $themecss | sed 'N;s/
/ /' | sed 's/\([0-9]*\) \(.*\)/\2 |\1/' | sed -n "/$Class *{* *|.*$/,/}/p" | sed "s|$color|$Color|;s|^[ ]*||" | sed -n "/^$Color *:/p" | awk '{ print $NF, $(NF-1)}' | sed 's/|\([0-9]*\) \(.*\);/\1s|\2/')
ncolors=(${ncolors[li]} $rgb)
[/li] colors="$colors --field=\"$clr\":CLR \"${rgb#*|}\""
done
}
function setcolors {
sedcmd=""
cmd=$(echo yad --form $colors --title="$title" --button=Edit:3 --button=Refresh:2 --button=gtk-ok:0 --button=gtk-cancel:1 --columns=5)
rcolors=$(eval $cmd) ; ret=$?
case $ret in
1) exit 1 ;;
3) which $editor &>/dev/null && $editor $themecss ; setcolors ;;
0|2)
rcolors=($(echo $rcolors | sed 's/|/| /g;s/\([0-9a-fA-F]\{2\}\)[0-9a-fA-F]\{2\}/\1/g'))
[ ${#ncolors[li]} -eq ${#rcolors[*]} ] || exit 5
[/li] i=0
while [ $i -lt ${#ncolors[li]} ] ; do
[/li] sedcmd="$sedcmd${ncolors[$i]}|${rcolors[$i]};"
let i++
done
cp $themecss{,.orig}
eval $(echo sed -i -e "'$sedcmd'" $themecss)
reloadTheme
;;
esac
}
while [ $ret -ge 2 ] ; do
getcolors
setcolors
done