In this article I explore application of styles, colours, backgrounds, fonts, etc., to various gtkdialog application objects.
This is the next article in a series of articles on gtkdialog, “gtkdialog Exploration – articles and examples”, which can be found at https://blogs.czapski.id.au/2017/04/gtkdialog-exploration.
Pre-Requisites
This article assumes that the Virtual Box Machine Image created in accordance with the instructions in the blog article to be found at https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image is available but it is expected that pretty much any Linux environment will do just as well so long as it supports yad and gtkdialog. For convenience I posted the export of the VirtualBox image which would have been built if the reader followed all the articles in the series “Build a Linux-based Infrastructure Solution Demonstration Series” to date, that is to the 8th of March 2017. The link to the main article is https://blogs.czapski.id.au/2017/04/virtualbox-image-with-content-as-built-so-far.
It also assumes that yad and gtkdialog are installed, as discussed in the article “Install yad and gtkdialog” (https://blogs.czapski.id.au/2017/04/gtkdialog-for-rapid-prototyping-of-linux-applications-install-gtkialog-and-yad)
Example of styling – teaser
There is a way to “style” gtkdialog objects, which works in some instances, and which can be used as appropriate.
Consider the following example, which was implemented in an earlier article:
scriptName=ex19
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh
cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash
GTKDIALOG=gtkdialog
fnEchoDateTime() {
echo "$(date)"
}
export -f fnEchoDateTime
echo '
style "bgWhite" { bg[NORMAL] = "#FFFFFF" }
style "fgWhite" { fg[NORMAL] = "#FFFFFF" }
style "bgBlack" { bg[NORMAL] = "#000000" }
style "bgRed" { bg[NORMAL] = "#FF0000" }
style "fgRed" { fg[NORMAL] = "#FF0000" }
style "bgGreen" { bg[NORMAL] = "#FFFF00" }
style "fgGreen" { fg[NORMAL] = "#FFFF00" }
style "bgBlue" { bg[NORMAL] = "#0000FF" }
style "fgBlue" { fg[NORMAL] = "#0000FF" }
widget "MyWindowBg" style "bgBlack"
widget "MyWindowBg.GtkVBox.GtkHBox.MyButtonBg" style "bgGreen"
widget "MyWindowBg.GtkVBox.myEVB" style "bgBlue"
widget_class "*<GtkFrame>.GtkLabel" style "fgWhite"
widget_class "*<GtkFrame>.*.GtkLabel" style "fgGreen"
widget_class "*<GtkButton>.*.GtkLabel" style "fgRed"
' > /tmp/gtkrc_mono
export GTK2_RC_FILES=/tmp/gtkrc_mono
GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2
MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window
title="My First Window"
window-position="${GTK_WIN_POS_CENTER}"
default-width="400"
name="MyWindowBg"
>
<vbox>
<eventbox name="myEVB" above-child="false" visible-window="true">
<frame Description >
<text><label>This is an example window.</label></text>
</frame>
</eventbox>
<hbox>
<button name="MyButtonBg" use-underline="true" tooltip-text="Refresh window variable - update date in window title">
<label> _Refresh </label>
<input file icon="gtk-refresh"></input>
<width>16</width>
<action function="refresh">vWindow</action>
</button>
<button ok></button>
<button cancel></button>
</hbox>
</vbox>
<variable>vWindow</variable>
<input>fnEchoDateTime</input>
<action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION
case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac
rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT
/tmp/${scriptName}.sh
Here we define and use GTK styles to change foreground and/or background colours of the various objects.
Here is how the application window looks.
This is just a brief teaser. How to apply styles to objects, what works and what does not, etc., is covered in the following sections.
Some Sources of Information
Let’s explore some sources of information for on styles that might work with gtkdialog objects.
https://en.wikibooks.org/wiki/GTK%2B_By_Example/Theming
http://www.cc.gatech.edu/data_files/public/doc/gtk/tutorial/gtk_tut.html – worth exploring for the underlying concepts and considerations
http://www.cc.gatech.edu/data_files/public/doc/gtk/tutorial/gtk_tut-19.html – specific discussion of styles
Constructing style and making gtkdialog use it
GTK loads and processes the GTK resource file, if one exists, which amongst other things can contain style definitions. This is the method we use to provide styles and define the objects to which they are to be applied. Consider the following excerpt from example ex21 in the next section:
GTKRC_LOCATION=/tmp
[[ ! -f ${GTKRC_LOCATION}/emblem-unreadable.png ]] && cp -v /usr/share/icons/gnome/32x32/emblems/emblem-unreadable.png ${GTKRC_LOCATION}
echo '
style "windowStyle" {
bg_pixmap[NORMAL] = "emblem-unreadable.png"
}
widget "MyWindow" style "windowStyle"
' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono
The four key things to note are:
- The named style is defined (there can be as many styles as are needed)
- The style is associated with one or more “targets” – widget, widget_class or class (more on that in the next section)
- The styles and associations are written to a GTK resource file
- The shell variable GTK2_RC_FILES which points to that file is then exported so that it can be used by gtkdialog at runtime to locate the styles and objects to which to apply them
I am using different style resource files for different applications so that each of my gtkdialog scripts manages its own styles.
The style definition follows this pattern:
style "<name>" {
<style definitions>
}
Style are specified using syntax defined by GTK for gtk resources.
Consult GTK resources for reference:
Other discussions can be consulted at:
Styling the Window object and its children
Styles can be applied to the Window object using the name attribute of the Window object and the appropriate definition of style.
Consider the following example to set the baseline for applying styles to a Window object:
scriptName=ex20
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh
cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash
GTKRC_LOCATION=/tmp
GTKDIALOG=gtkdialog
GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2
MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window
title="My Window"
window-position="${GTK_WIN_POS_CENTER}"
default-width="400"
border-width="5"
name="MyWindow"
>
<vbox>
<frame Description >
<text name="MyText">
<label>This is an example window.</label>
</text>
</frame>
<hbox>
<button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
<label> _Quit </label>
<input file icon="gtk-quit"></input>
<width>16</width>
<action function="exit">vWindow</action>
</button>
<button name="ButtonCancel" use-underline="true" width-request="100">
<label> _Cancel </label>
<input file icon="gtk-cancel"></input>
<width>16</width>
<action function="closewindow">vWindow</action>
</button>
</hbox>
</vbox>
<variable>vWindow</variable>
<action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION
case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac
rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT
/tmp/${scriptName}.sh
This produces:
This is the default appearance in my environment without applying any styles.
It is possible, if perhaps not as useful as might at first appear, to apply an image as a repeating motif to the window’s background. If the image is smaller than the window it will be repeated. If the image is larger than the window the top left portion of the image will be used.
Consider the following example:
scriptName=ex21
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh
cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash
GTKRC_LOCATION=/tmp
# pixmap images must be in the same folder as the gtkrc file
# since the bg_pixmap style directive does not accept file path - just file name
#
# copy some images to the gtkrc file location
[[ ! -f ${GTKRC_LOCATION}/emblem-unreadable.png ]] && cp -v /usr/share/icons/gnome/32x32/emblems/emblem-unreadable.png ${GTKRC_LOCATION}
GTKDIALOG=gtkdialog
echo '
style "windowStyle" {
bg_pixmap[NORMAL] = "emblem-unreadable.png"
}
widget "MyWindow" style "windowStyle"
' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono
GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2
MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window
title="My Window"
window-position="${GTK_WIN_POS_CENTER}"
default-width="400"
border-width="5"
name="MyWindow"
>
<vbox>
<frame Description >
<text name="MyText">
<label>This is an example window.</label>
</text>
</frame>
<hbox>
<button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
<label> _Quit </label>
<input file icon="gtk-quit"></input>
<width>16</width>
<action function="exit">vWindow</action>
</button>
<button name="ButtonCancel" use-underline="true" width-request="100">
<label> _Cancel </label>
<input file icon="gtk-cancel"></input>
<width>16</width>
<action function="closewindow">vWindow</action>
</button>
</hbox>
</vbox>
<variable>vWindow</variable>
<action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION
case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac
rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT
/tmp/${scriptName}.sh
This produces the following:
Let’s consider the definition of the style:
GTKRC_LOCATION=/tmp
[[ ! -f ${GTKRC_LOCATION}/emblem-unreadable.png ]] && cp -v /usr/share/icons/gnome/32x32/emblems/emblem-unreadable.png ${GTKRC_LOCATION}
echo '
style "windowStyle" {
bg_pixmap[NORMAL] = "emblem-unreadable.png"
}
widget "MyWindow" style "windowStyle"
' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono
Here we set the background pixmap to use the emblem-unreadable.png. This image will be repeated horizontally and vertically as the window background. The image file must reside in the same directory as the resource file containing this style definition (later in this article we will learn how to configure the gtkrc so that the image does not have to be copied over). In the example above, we copy it from its original location if it is not already there. You may or may not have this specific image in your environment. If you don’t have it use a different one.
The object to which the style is to be applied can be specified in a number of ways.
GTKRC_LOCATION=/tmp
[[ ! -f ${GTKRC_LOCATION}/emblem-unreadable.png ]] && cp -v /usr/share/icons/gnome/32x32/emblems/emblem-unreadable.png ${GTKRC_LOCATION}
echo '
style "windowStyle" {
bg_pixmap[NORMAL] = "emblem-unreadable.png"
}
widget "MyWindow" style "windowStyle"
' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono
In the example above we use the name of the widget to which this style is to be applied. The name of the Window object, in this case, is used to make this association:
<window
title="My Window"
window-position="${GTK_WIN_POS_CENTER}"
default-width="400"
border-width="5"
name="MyWindow"
>
<vbox>
Let’s modify this style so that it changes styles of other components. Consider the following example:
scriptName=ex22
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh
cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash
GTKRC_LOCATION=/tmp
# pixmap images must be in the same folder as the gtkrc file
# since the bg_pixmap style directive does not accept file path - just file name
#
# copy some images to the gtkrc file location
[[ ! -f ${GTKRC_LOCATION}/bits.xpm ]] && cp /usr/share/emacs/23.1/etc/images/ezimage/bits.xpm ${GTKRC_LOCATION} # same place as the rc file
[[ ! -f ${GTKRC_LOCATION}/kill-group.xpm ]] && cp /usr/share/emacs/23.1/etc/images/gnus/kill-group.xpm ${GTKRC_LOCATION}
[[ ! -f ${GTKRC_LOCATION}/emblem-unreadable.png ]] && cp /usr/share/icons/gnome/32x32/emblems/emblem-unreadable.png ${GTKRC_LOCATION}
GTKDIALOG=gtkdialog
echo '
style "windowStyle" {
# bg_pixmap[NORMAL] = "kill-group.xpm"
# bg_pixmap[NORMAL] = "bits.xpm"
bg_pixmap[NORMAL] = "emblem-unreadable.png"
# bg[NORMAL] = "#989898" # Grayish
bg[NORMAL] = "lightblue"
fg[NORMAL] = "darkblue"
# fg[NORMAL] = "#FFFFFF"
}
widget "MyWindow" style "windowStyle"
#widget_class "<GtkWindow>*" style "windowStyle"
' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono
GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2
MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window
title="My Window"
window-position="${GTK_WIN_POS_CENTER}"
default-width="400"
border-width="5"
name="MyWindow"
>
<vbox>
<frame Description >
<text name="MyText">
<label>This is an example window.</label>
</text>
</frame>
<hbox>
<button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
<label> _Quit </label>
<input file icon="gtk-quit"></input>
<width>16</width>
<action function="exit">vWindow</action>
</button>
<button name="ButtonCancel" use-underline="true" width-request="100">
<label> _Cancel </label>
<input file icon="gtk-cancel"></input>
<width>16</width>
<action function="closewindow">vWindow</action>
</button>
</hbox>
</vbox>
<variable>vWindow</variable>
<action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION
case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac
rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT
/tmp/${scriptName}.sh
This produces the following:
Note that the window background acquires light blue tint. Note too that nothing shows the dark blue colour. This is because the window object does not have anything that has a visible foreground. The objects which have foreground, like text and buttons, are nested inside the window object but since the style is to be applied to the widget by name this style does not get propagated to child objects.
Edit the example and change the two lines from:
widget "MyWindow" style "windowStyle"
#widget_class "<GtkWindow>*" style "windowStyle"
to
#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
then re-execute the modified example. This produces the following:
Specifying ‘widget_class “<GtkWindow>*”‘ cause the style to be applied to the Window objects and all the child objects in the hierarchy. In this case the visible outcome is that the text of all the child objects (the only aspect of these objects that has foreground to which to apply a foreground colour) turned dark blue.
Experiment by changing style definition of fg[NORMAL] to use different colours. There is discussion of GTK colours and how they can be specified at https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes/SymbolicColors.
One can apply styles to named widgets, to widget classes (and child objects) and to GTK classes. There is a resource at https://www.cs.tut.fi/lintula/manual/gtk/gtk/gtk-resource-files.html which has a discussion of this topic in the section “Pathnames and patterns”.
Here we are going at a bit of a tangent, working with objects inside the Window, to see how the window style is inherited and overridden.
Change the style definition in the example to read as follows and execute to see the outcome:
echo '
style "windowStyle" {
# bg_pixmap[NORMAL] = "kill-group.xpm"
# bg_pixmap[NORMAL] = "bits.xpm"
bg_pixmap[NORMAL] = "emblem-unreadable.png"
# bg[NORMAL] = "#989898" # Grayish
bg[NORMAL] = "lightblue"
fg[NORMAL] = "darkblue"
# fg[NORMAL] = "#FFFFFF"
}
style "buttonStyle" {
bg[NORMAL] = "green"
fg[NORMAL] = "brown"
}
widget "MyWindow" style "windowStyle"
#widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style "buttonStyle"
' > ${GTKRC_LOCATION}/gtkrc_mono
This produces the following:
Please note that specifying targets to which to apply styles is a bit tricky and involves style merge priorities. For example the following will not produce the desired outcome:
#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style "buttonStyle"
The windowStyle will be applied to all child objects and the style to be applied to class GtkButton will be ignored. This is the consequence of GTK style application priority – see https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes#Priority.
Change the definition as follows and re-execute the example:
#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
This produces the following, which is what we expected to achieve in the first place:
The child foreground style is used for everything except the GtkButton class objects, because the GtkButton class style has the highest priority as far as button styles go. See https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes#Priority for discussion of this topic.
The style merging needs some exploration and some experimentation. Consider the following change:
style "buttonStyle" {
bg[NORMAL] = "green"
fg[NORMAL] = "brown"
}
style "frameStyle" {
bg[NORMAL] = "red"
fg[NORMAL] = "maroon"
}
#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
#widget_class "*.GtkFrame.*" style "frameStyle"
class "GtkFrame" style : highest "frameStyle"
Execute the example and see that the frame acquired a red border but the label text and the text inside the frame are still the style of the window object.
Uncomment the ‘widget_class “*.GtkFrame.*” …’ and re-execute the example. Note that the Frame title is now maroon but so is the label text inside the text object. That’s because the specification “*.GtkFrame.*” applies the style to the Frame and all it contains.
Modify the specification to read as shown below and re-execute the example.
#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
widget_class "*.GtkFrame.GtkLabel" style "frameStyle"
class "GtkFrame" style : highest "frameStyle"
Note that the frame label is still maroon but the text object’s label is dark blue, that is it inherits foreground colour from the Window style. This is because we restricted the style application to GtkLabel under the GtkFrame only.
Let’s now explore how text can be styled with font specification. Reference: https://developer.gnome.org/pango/stable/pango-Fonts.html.
Consider the following example:
scriptName=ex23
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh
cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash
GTKRC_LOCATION=/tmp
GTKDIALOG=gtkdialog
echo '
style "windowStyle" {
bg[NORMAL] = "lightblue"
fg[NORMAL] = "darkblue"
# font_name="Bitstream Charter Italic 10"
# font_name="Caladea Bold 10"
# font_name="URW Gothic L Semi-Bold 12"
# font_name="URW Chancery L Medium Italic 16"
# font_name="Standard Symbols L 12"
# font_name="Nimbus Sans L Condensed 14"
# font_name="Fixed Bold 14"
font_name="Carlito Bold 12"
}
style "buttonStyle" {
bg[NORMAL] = "green"
fg[NORMAL] = "brown"
}
style "frameStyle" {
bg[NORMAL] = "red"
fg[NORMAL] = "maroon"
}
widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
widget_class "*.GtkFrame.GtkLabel" style "frameStyle"
class "GtkFrame" style : highest "frameStyle"
' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono
GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2
MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window
title="My Window"
window-position="${GTK_WIN_POS_CENTER}"
default-width="400"
border-width="5"
name="MyWindow"
>
<vbox>
<frame Description >
<text name="MyText">
<label>This is an example window.</label>
</text>
</frame>
<hbox>
<fontbutton name="ButtonFont" width-request="100">
<variable>btnFont</variable>
</fontbutton>
<button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
<label> _Quit </label>
<input file icon="gtk-quit"></input>
<width>16</width>
<action function="exit">vWindow</action>
</button>
<button name="ButtonCancel" use-underline="true" width-request="100">
<label> _Cancel </label>
<input file icon="gtk-cancel"></input>
<width>16</width>
<action function="closewindow">vWindow</action>
</button>
</hbox>
</vbox>
<variable>vWindow</variable>
<action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION
case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac
rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT
/tmp/${scriptName}.sh
Note the font_family style property. The string consists of the Font Family followed by font weight and font size.
Consider the font specifications. Uncomment one at a time and see the results.
style "windowStyle" {
bg[NORMAL] = "lightblue"
fg[NORMAL] = "darkblue"
# font_name="Bitstream Charter Italic 10"
# font_name="Caladea Bold 10"
# font_name="URW Gothic L Semi-Bold 12"
# font_name="URW Chancery L Medium Italic 16"
# font_name="Standard Symbols L 12"
# font_name="Nimbus Sans L Condensed 14"
# font_name="Fixed Bold 14"
font_name="Carlito Bold 12"
}
Use the font selection button to see what fonts, weights and sizes are available and copy a string to use when applying font style to specific objects.
Add different font specification to the frameStyle and see the results.
style "frameStyle" {
bg[NORMAL] = "red"
fg[NORMAL] = "maroon"
font_name="URW Chancery L Medium Italic 18"
}
This produces the following:
The following example uses a different method to configure the window background image and specifies the pixmap_path so that images do not need to be copied to the same directory as the resource file. See some material at https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/PixmapEngine
scriptName=ex24
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh
cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash
GTKRC_LOCATION=/tmp
GTKDIALOG=gtkdialog
echo '
pixmap_path "/usr/share/backgrounds/cosmos/:/usr/share/backgrounds/nature/:/usr/share/backgrounds/scenery/:/usr/share/icons/gnome/scalable/actions"
style "windowStyle" {
engine "pixmap" {
image
{
function = FLAT_BOX
file = "Garden.jpg"
# file = "gtk-execute.svg"
# file = "list-remove.svg"
# file = "media-playback-pause.svg"
border = { 0, 0, 0, 0 }
stretch = TRUE
overlay_file = "media-playback-pause.svg"
overlay_stretch = FALSE
}
}
}
#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono
GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2
MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window
title="My Window"
window-position="${GTK_WIN_POS_CENTER}"
default-width="400"
border-width="5"
name="MyWindow"
>
<vbox>
<frame Description >
<text name="MyText">
<label>This is an example window.</label>
</text>
</frame>
<hbox>
<button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
<label> _Quit </label>
<input file icon="gtk-quit"></input>
<width>16</width>
<action function="exit">vWindow</action>
</button>
<button name="ButtonCancel" use-underline="true" width-request="100">
<label> _Cancel </label>
<input file icon="gtk-cancel"></input>
<width>16</width>
<action function="closewindow">vWindow</action>
</button>
</hbox>
</vbox>
<variable>vWindow</variable>
<action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION
case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac
rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT
/tmp/${scriptName}.sh
This produces the following (note the “Pause” image over the top of the Garden image. I expected this image to repeat but it did not and there is no information on whether it can and how to make it.
We used the “pixmap” engine in the example above. That implies that there are other engines so set’s have a go at different theme engines to see what outcomes we will get.
Let’s install gtk2-engines* package.
sudo yum -y install gtk2-engines*
The following engines are now available.
ls -c1 /usr/lib64/gtk-2.0/2.10.0/engines | sort
libclearlooks.so
libcrux-engine.so
libglide.so
libhcengine.so
libindustrial.so
libmist.so
libpixmap.so
libredmond95.so
libsvg.so
libthinice.so
To work out the name of the engine strip the leading “lib” and the trailing “.so” and use what’s left.
Explore the results of executing the following example while successively uncommenting the different engine. The quick test of the differences is the dialog box which is produced after clicking on the Font button.
scriptName=ex25
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh
cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash
GTKRC_LOCATION=/tmp
GTKDIALOG=gtkdialog
echo '
pixmap_path "/usr/share/backgrounds/cosmos/:/usr/share/backgrounds/nature/:/usr/share/backgrounds/scenery/:/usr/share/icons/gnome/scalable/actions"
style "windowStyle" {
# from /usr/lib64/gtk-2.0/2.10.0/engines
# engine "clearlooks" {}
# engine "crux-engine" {}
# engine "glide" {}
# engine "hcengine" {}
# engine "industrial" {}
# engine "mist" {} # https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/MistEngine
# engine "pixmap" {} # https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/PixmapEngine
engine "redmond95" {}
# engine "thinice" {}
}
#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono
GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2
MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window
title="My Window"
window-position="${GTK_WIN_POS_CENTER}"
default-width="400"
border-width="5"
name="MyWindow"
>
<vbox>
<frame Description >
<text name="MyText">
<label>This is an example window.</label>
</text>
</frame>
<hbox>
<fontbutton></fontbutton>
<button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
<label> _Quit </label>
<input file icon="gtk-quit"></input>
<width>16</width>
<action function="exit">vWindow</action>
</button>
<button name="ButtonCancel" use-underline="true" width-request="100">
<label> _Cancel </label>
<input file icon="gtk-cancel"></input>
<width>16</width>
<action function="closewindow">vWindow</action>
</button>
</hbox>
</vbox>
<variable>vWindow</variable>
<action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION
case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac
rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT
/tmp/${scriptName}.sh
With the redmond95 engine I see something like this:
With the glide engine I see something like:
With clearlooks I see something like:
Unfortunately I could not find much information on what configuration options are available for each of these engines. About the most I could find was for the pixmap engine. Redmond95 is said to have no configuration options. I was not able to find any information about the industrial engine.
If you are inclined to explore the gtk themes there some information on the topic on the Internet. I did not follow up on this to any great extent as it si only marginally relevant to what I am trying to do in this series of articles.
There is some material on this topic at http://www.orford.org/gtk, particularly section on fonts.
https://git.enlightenment.org/themes/detourious.git/plain/gtk/detourious/gtk-2.0/gtkrc has a huge set of property specs which could be of interest for experimentation. Inspect what that you see there and have a go at styling the example. For example, change the style and target definitions in the example above to read as follows and see what you can see. Experiment with changing the target from widget_class to widget and changing foreground and background colours.
style "windowStyle" {
# from /usr/lib64/gtk-2.0/2.10.0/engines
engine "clearlooks" {}
# engine "crux-engine" {}
# engine "glide" {}
# engine "hcengine" {}
# engine "industrial" {}
# engine "mist" {} # https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/MistEngine
# engine "pixmap" {} # https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/PixmapEngine
# engine "redmond95" {}
# engine "thinice" {}
base[NORMAL] = "#ff0000"
base[PRELIGHT] = "#ffff00"
base[ACTIVE] = "#ff00ff"
base[SELECTED] = "#00ff00"
base[INSENSITIVE] = "#0000ff"
# fg[NORMAL] = "#ff0000"
# fg[PRELIGHT] = "#ffff00"
# fg[ACTIVE] = "#ff00ff"
# fg[SELECTED] = "#00ff00"
# fg[INSENSITIVE] = "#0000ff"
bg[NORMAL] = "#ff0000"
bg[PRELIGHT] = "#ffff00"
bg[ACTIVE] = "#ff00ff"
bg[SELECTED] = "#00ff00"
bg[INSENSITIVE] = "#0000ff"
}
#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
I see the following:
There are more examples at https://people.kth.se/~e95_fla/ex/gtkrc and, undoubtedly, elsewhere.
Naming Style Targets
It is possible and I imagine quite desirable to be able to apply specific style to an individual component – say a label in a text object, the title of the frame object and similar.
Examples shown so far use the style definitions to define styles and associate these styles with specific objects by name (widget), specific widget “collections” (widget_class) or specific classes of widget (class).
Named Targets
The ‘widget “name” style “style-name”‘ assignment cause the named style to be applied to a named object. Consider example ex23. As given it produces the following look:
This is accomplished with the following specification that went into the gtk resource file:
style "windowStyle" {
bg[NORMAL] = "lightblue"
fg[NORMAL] = "darkblue"
font_name="Carlito Bold 12"
}
style "buttonStyle" {
bg[NORMAL] = "green"
fg[NORMAL] = "brown"
}
style "frameStyle" {
bg[NORMAL] = "red"
fg[NORMAL] = "maroon"
}
widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
widget_class "*.GtkFrame.GtkLabel" style "frameStyle"
class "GtkFrame" style : highest "frameStyle"
Our GUI definition starts like this:
<window
title="My Window"
window-position="${GTK_WIN_POS_CENTER}"
default-width="400"
border-width="5"
name="MyWindow"
>
...
Let’s modify the style and target definitions to read:
style "windowStyle" {
bg[NORMAL] = "lightblue"
fg[NORMAL] = "darkblue"
font_name="Carlito Bold 12"
}
style "buttonStyle" {
bg[NORMAL] = "green"
fg[NORMAL] = "brown"
}
style "frameStyle" {
bg[NORMAL] = "red"
fg[NORMAL] = "maroon"
}
widget "MyWindow" style "windowStyle"
##widget_class "<GtkWindow>*" style "windowStyle"
##class "GtkButton" style : highest "buttonStyle"
##widget_class "*.GtkFrame.GtkLabel" style "frameStyle"
##class "GtkFrame" style : highest "frameStyle"
Executing the example with this change produces:
Because we are assigning the windowStyle to the object whose name is “MyWindow” the style only applies to that object. The window gets a light blue background but neither foreground colour nor font produce visible effects. This is because the window object does not have any elements to which foreground or font style directives can be applied.
This is an example of styling named objects.
Please note that styles are merged according to a set of built in rules so the effect you get may not be the effect you expect. This is discussed in passing elsewhere in this article but not formally or completely. Some experimentation will be required and some frustration is to be expected.
Containment Hierarchy Targets
Let’s say that we want to apply the foreground and background colours to all objects with components to which foreground and background colours can be applied, starting with the window object and going down the containment hierarch.
Change the style assignment definition to read:
##widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
##class "GtkButton" style : highest "buttonStyle"
##widget_class "*.GtkFrame.GtkLabel" style "frameStyle"
##class "GtkFrame" style : highest "frameStyle"
Note the syntax: ‘<GtkWindow>*
‘. Here the trailing asterisk means ‘and all down the hierarchy’
This produces the following:
Dark blue foreground colour has been applied to every component within the window containment hierarchy which has an element to which foreground colour can be applied. In this case these are labels of the text and button objects.
Light blue background colour has been applied to every component within the window containment hierarchy which has an element to which background colour can be applied. In this case these are the window background and the ‘border’ of the frame component.
Change the widget_class target to ‘<GtkWindow><GtkVBox><GtkFrame>*
‘ and execute the example. This produces the following:
Note that the window colour reverted to the default as did the colour of the button labels text. This is because we explicitly targeted the style at the frame object and its content.
Let’s zoom in a bit more into the frame and apply styling to just the frame title with the following syntax: ‘<GtkWindow><GtkVBox><GtkFrame><GtkLabel>
‘. Note that we explicitly target just the frame label and nothing else. Executing the example produces the following:
As we would expect only the frame title is explicitly styled.
This discussion introduces, in passing, the object hierarchy, or as I am calling it the containment hierarchy. Frame label is contained within the frame, which is contained within the vbox, which is contained within the window. This is almost the explicit hierarchy we have in our GUI definition in the example:
<window
title="My Window"
window-position="${GTK_WIN_POS_CENTER}"
default-width="400"
border-width="5"
name="MyWindow"
>
<vbox>
<frame Description >
<text name="MyText">
<label>This is an example window.</label>
</text>
</frame>
...
“Almost” because the “label” (GtkLabel) object is not explicitly specified in the definition of the frame so one has to know or guess. Compare this to the definition of the text object in which label is explicitly defined.
One way to not have to know or guess is to specify the asterisk instead of <GtkLabel>
in the target specification but that would style the frame label and everything else that takes foreground and background colour and is contained inside the frame as shown in the previous use case.
Let’s try the following – ‘<GtkWindow><GtkVBox><GtkFrame><GtkText><GtkLabel>
‘. Executing the example with this change produces a plain window with no styling explicitly applied to any element.
Hang on, why is this not working? This is the object hierarchy, right? The GUI definition says so!
Well, here is where knowing to look at the “Widget Construction” section at the developer documentation at http://www.murga-linux.com/puppy/viewtopic.php?t=69188&start=2 may give clues as to what might be happening. See, for example, discussion of how the various button types are constructed, paying attention to the containment hierarchy. To quote an instance:
<button> containing a label and an image is a GtkButton containing a GtkHBox or GtkVBox itself containing a GtkLabel and GtkImage (stock images are loaded by a dedicated function and hardcoded to GTK_ICON_SIZE_BUTTON)
Right. With this hint we can perhaps deduce that the text object is actually a GtkHBox or a GtkVBox containing the GtkLabel object and we could try the following, in turn:
widget_class "<GtkWindow><GtkVBox><GtkFrame><GtkHBox><GtkLabel>" style "windowStyle"
Nope.
widget_class "<GtkWindow><GtkVBox><GtkFrame><GtkVBox><GtkLabel>" style "windowStyle"
Bingo! Only the inner text label got styled so this is the precise target specification for the label of the text object.
Note in passing that even though we have a background colour defined the label does not have a visible background.
Let’s see if the GtkVBox has a colourable background:
widget_class "<GtkWindow><GtkVBox><GtkFrame><GtkVBox>" style "windowStyle"
Nope. My experience is that neither HBox nor VBox have backgrounds that can be coloured.
So how would one go about providing a colour background to a label?
Let’s change the definition of the content of the frame to read as follows:
...
name="MyWindow"
>
<vbox>
<frame Description >
<eventbox>
<text name="MyText">
<label>This is an example window.</label>
</text>
</eventbox>
</frame>
...
Let’s change the styling target to read:
widget_class "<GtkWindow><GtkVBox><GtkFrame><GtkVBox><GtkEventBox>" style "windowStyle"
Notice what is happening. The frame contains the inner vbox which contains whatever goes inside the frame. All the same, the <eventbox> object, which is normally invisible, can have its background coloured, and by extension can be used to apply styles to the objects it contains as would be achieved with the addition of the trailing asterisk to the specification.
Executing the example with this change produces the following:
The label now has background colour. |
The bottom line here is that using precise widget_class targets requires the knowledge of how the hierarchy is implemented (see the web page quoted above), and some guesswork and experimentation, like in the case of a label within text within frame.
Targeting Classes
Finally, one can apply style classes of objects.
Let’s try the following change:
style "windowStyle" {
bg[NORMAL] = "lightblue"
fg[NORMAL] = "darkblue"
}
style "buttonStyle" {
bg[NORMAL] = "green"
fg[NORMAL] = "brown"
}
style "frameStyle" {
bg[NORMAL] = "red"
fg[NORMAL] = "maroon"
}
style "labelStyle" {
fg[NORMAL] = "darkblue"
font_name="Bitstream Charter Italic 10"
}
widget_class "<GtkWindow><GtkVBox><GtkFrame><GtkVBox><GtkEventBox>" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
class "GtkFrame" style : highest "frameStyle"
class "GtkLabel" style "labelStyle"
Executing the modified example produces the following:
The class target targets all objects of the class, applying the same style to all.
Note the “style : highest” notation. This explicitly overrides the default style merge mechanism, somewhat discussed under the heading “binding styles to widget classes:” in http://www.orford.org/gtk/, and under the heading of “Priority” in https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes.
Gtkrc Examples
Finally, review the gtkrc files for the various themes to see what you can see there and to see if any of it might be of use to you when styling gtkdialog widgets.
ls -C1 /usr/share/themes/*/gtk-2.0/gtkrc | sort
/usr/share/themes/ClearlooksClassic/gtk-2.0/gtkrc
/usr/share/themes/Clearlooks/gtk-2.0/gtkrc
/usr/share/themes/Crux/gtk-2.0/gtkrc
/usr/share/themes/Glider/gtk-2.0/gtkrc
/usr/share/themes/Glossy/gtk-2.0/gtkrc
/usr/share/themes/HighContrast/gtk-2.0/gtkrc
/usr/share/themes/HighContrastInverse/gtk-2.0/gtkrc
/usr/share/themes/HighContrastLargePrint/gtk-2.0/gtkrc
/usr/share/themes/HighContrastLargePrintInverse/gtk-2.0/gtkrc
/usr/share/themes/Industrial/gtk-2.0/gtkrc
/usr/share/themes/Inverted/gtk-2.0/gtkrc
/usr/share/themes/LargePrint/gtk-2.0/gtkrc
/usr/share/themes/LowContrast/gtk-2.0/gtkrc
/usr/share/themes/LowContrastLargePrint/gtk-2.0/gtkrc
/usr/share/themes/Mist/gtk-2.0/gtkrc
/usr/share/themes/Raleigh/gtk-2.0/gtkrc
/usr/share/themes/Simple/gtk-2.0/gtkrc
/usr/share/themes/Slider/gtk-2.0/gtkrc
/usr/share/themes/ThinIce/gtk-2.0/gtkrc
Tools for exploring widget styling and colours
gtk2-styles wizard
Andrew Karuse, who published the book “Foundations of GTK+ Development” (http://www.apress.com/us/book/9781590597934), made available at https://github.com/grayasm/git-main/tree/master/tutorial/andrew_krause_gtk%2B/13_all_together the source and related resources for a C++ application which allows one to visually work with GTK styles for the various GTK widgets and save the resulting GTK resources to a file. This in turn allows one to get the exact syntax needed to implement these styles for the various widgets.
There is a YouTube video on this: https://youtu.be/EzkQAbP4My8. Watch the video to see how to get and build the wizard, and how to use it construct a valid gtkrc resource file that can be used with gtkdialog.
I have not been able to find an archive containing the sources and resources for the convenience of the downloader and the zip archive downloadable from the publisher’s book site does not have this application. While this makes life a bit more difficult it is still possible to get and build the application.
The link quoted above gets one to this:
Download each file, one at a time, to a convenient directory, say gtk2-styles. Make sure to follow the links until you see the raw source or the image and download these.
cd ./gtk2-styles
In gtk2-styles.cpp change the declaration of the const char* rcfile so that it does not initialise. If it does the make will fail with C++ errors.
struct AppData
{
// const char* rcfile=NULL;
const char* rcfile;
Build the application
make -k
Run the application
./gtk2-styles
Change styles of things for which you want to change styles then File->Save As the file.
Copy the styles you changed into a gtkrc file which you use at runtime.
Here is an example of what the application looks like for a GtkButton:
Note the following:
- One can change colours (click on the colour box and one will get the usual colour picker) and the changes will be immediately reflected in the UI.
- One can change the numeric values for the various properties and the changes will be immediately reflected in the UI.
- Once can check and uncheck the checkboxes and the changes will be immediately reflected in the UI.
- One can hover over the buttons and click them to see the results of changes.
Explore the application and then File-Save As to a file to see what a gtkrc file would look like with the changes you made to the styles provided by the default theme. Note that the saved file will contain definitions for all the objects. If you make small changes use just the changes in your gtkdialog application’s rc file.
Note that if you do not make any changes and save the rc file it will be empty.
gpick Colour Picker
Sometimes one might want to match colours of the various elements in one’s application with colours in used in some other application. For example I had an occasion recently to build a gtkdialog-based applicaiotn that would invoke a filrefox with a web page which used specific colours for specific elements like table headers and fonts. To match the colour scheme I needed to know the hex values of the specific colours. The handy tool I found on line is the gpick colour picker. It is available at http://www.gpick.org/. The source distribution requires a bunch of tools to build so rather than building from sources I opted for finding and downloading the pre-built rpm.
cd ~/Downloads
wget ftp://fr2.rpmfind.net/linux/epel/6/x86_64/gpick-0.2.4-4.el6.x86_64.rpm
sudo yum localinstall -y gpick-0.2.4-4.el6.x86_64.rpm
gpick window looks like this when first started:
Note the Hex value of the colour under the cursor, which is what I was after. There are a bunch of options and functionality I did not go into. Explore.
gtkdialog – Exploring the EventBox object by example
In this article I explore the gtkdialog EventBox object and its uses by example. EventBox can be used, among other things, to provide background colour to other objects, intercept and handle events and add frames around gtkdialog objects to help visualise the space they occupy.
This is the next article in a series of articles on gtkdialog, “gtkdialog Exploration – articles and examples”, which can be found at https://blogs.czapski.id.au/2017/04/gtkdialog-exploration.
The examples in this article demonstrate the following uses of the EventBox:
Pre-Requisites
This article assumes that the Virtual Box Machine Image created in accordance with the instructions in the blog article to be found at https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image is available but it is expected that pretty much any Linux environment will do just as well so long as it supports yad and gtkdialog. For convenience I posted the export of the VirtualBox image which would have been built if the reader followed all the articles in the series “Build a Linux-based Infrastructure Solution Demonstration Series” to date, that is to the 8th of March 2017. The link to the main article is https://blogs.czapski.id.au/2017/04/virtualbox-image-with-content-as-built-so-far.
It also assumes that yad and gtkdialog are installed, as discussed in the article “Install yad and gtkdialog” (https://blogs.czapski.id.au/2017/04/gtkdialog-for-rapid-prototyping-of-linux-applications-install-gtkialog-and-yad)
EventBox Object Model
gtkdialog, based as it is on the GTK object model, leverages the GTK object hierarchy. Consider the reference for the EventBox object at http://01micko.com/reference/eventbox.html.
The very first link points to a GtkEventBox – https://developer.gnome.org/gtk2/2.24/GtkEventBox.html.
In the GTK object hierarchy, https://developer.gnome.org/gtk2/2.24/GtkEventBox.html#GtkEventBox.object-hierarchy, the EventBox object is some levels below the GObject, the topmost object.
The GtkEventBox, and consequently the gtkdialog EventBox, object inherits from the objects higher up in the hierarchy. This will come into play when we explore attributes that can be set for an EventBox, and actions that can be configured for an EventBox.
EventBox Attributes
The gtkdialog EventBox object is a container, of a sort, to which styles can be applied, which can be “shown”/”hidden” and which can be “positioned” in the object hierarchy in such a way that all of the children which it contains are “beneath” it, so that the EventBox and not the children receives mouse clicks.
An example of an interface, which uses the EventBox object, and which will be developed in this article, is shown here.
Reference documentation for the gtkdialog EventBox object, http://01micko.com/reference/eventbox.html, provides a table of attributes specific to this gtkdialog object and makes a reference to ancestor class properties.
Attributes that can be configured for the eventbox widget are defined in the widget’s reference page see https://developer.gnome.org/gtk2/2.24/GtkEventBox.html, section Properties – https://developer.gnome.org/gtk2/2.24/GtkEventBox.html#GtkEventBox.properties
Some of the properties are inherited from the parent objects, like GtkContainer and GtkWidget. For example, border-width, which defines the amount of space between the notebook frame and the notebook content, is inherited from the GtkContainer.
Similarly, sensitive property is inherited from the GtkWidget and when set to true effectively disables everything inside the eventbox container.
See the reference page: file:///home/demo/gtkdialog-0.8.3/doc/reference/eventbox.html
To work out what attributes are actually supported, in this case by the eventbox widget, we need to do some exploration. Discussion below goes into this to an extent and I provided most of the useful attributes that can be set, both from GtkWindow itself and inherited from GtkContainer and GtkWidget. The “Works?” column indicates whether the attribute has a visible effect (Y), does not have a visible effect (N) or I have not figured out a way to test whether it works or not.
The table below summarised EventBox attributes/properties and indicates which work with the gtkdialog and which do not as far as I can tell. “Do not” may well be a function of me not seeing any visible difference with the property set to different values. Some ancestor attributes/properties which are not really useable from gtkdialog are omitted.
This does not seem to have any effect when applied to a Window object
Makes no sense for this
This does not seem to have any effect when applied to a Window object
Makes no sense for this
This does not seem to have any effect when applied to a Window object
Makes no sense for this
This does not seem to have any effect when applied to a Window object
Makes no sense for this
Disables tooltip display if tooltip is defined for the Window
Has not effect of default-height is specified.
Does not seem to have any effect when applied to the Window object
Makes no sense for this
It can be used to address styling directves to a named object
I don’t know what that is supposed to accomplish. Nothing visible happens regardless of the property value.
Makes no sense for this
FALSE disables all components contained in the eventbox.
Simple markup can be used to call out parts of tooltip text in.
See http://www.murga-linux.com/puppy/viewtopic.php?t=40418 for a markup explorer tool.
Ineffective if tooltip-disabled is TRUE.
Ineffective if tooltip-disabled is TRUE.
It is somewhat self-defeating to make a window invisible on creation unless it is a “subsidiary” window and can be made visible form some other piece of logic.
Has not effect if default-width is specified or if an outer container has a width-request set.
The following example includes just about every attrivute which can be set for the EventBox. We will explore what the various attribute settings do below.
First, let’s create an enumerations script which will supply human-readable versions of enumerations and other numeric constants that may be used in the scripts I show. See https://github.com/GNOME/gtk/blob/master/gdk/gdktypes.h, and elsewhere, for sources of these enumerations.
If you have this enumerations source because you worked through the Notebook example than you don’t need to re-create it. No new constants have been added.
above-child and visible-window attributes
In this section we will explore how the above-child and visible-window attributes of the eventbox, combined with appropriate styles, affect the appearance and function of the eventbox and its contents.
To create and exercise the first example execute the following commands, noting that you will need to copy and paste the code into an editor window because it is too large for a “here document”.
Executing this example unmodified produces the window which looks like that shown earlier – reproduced for completeness:
Because some of the attributes of the EventBox, such as the above-child and the visible-window do not produce visual effects but affect the behaviour of the application it will be necessary to describe the outcome rather than simply show a screenshot of it.
Click the Refresh and the Update buttons to see the window title change in accordance with the date formatting logic triggered by each. Note that the title window changes to display a timestamp and that the format of the timestamp changes depending on which of the two buttons is clicked.
Now change the value of the attribute above-child to “true” and click the two buttons as before. The code fragment here after this change is made is reproduced below:
Note that clicking on the “Update” button produces no effect. The above-child=”true” places all elements contained inside the eventbox “beneath” it so that it is the EventBox object that receives mouse clicks. If the event box had a signal handler attached to it, as it does not in this case, this event handler would intercept the clicks. Since there is no handler the clicks are simply ignored. Note however that if you use the Tab key to “tab to” the “Update” button, and it is selected, then pressing the Enter key will cause the action associated with this button to be executed event when the above-child is set to true.
Now change the above-child back to false and visible-window to true, as shown in the code fragment below, then run the example.
Note that the appearance of the window has changed:
Because the inner EventBox’s visible-window property is set to false the visual effects of the EventBox are not there – the background of the EventBox, which was white when the visible-window property was true is no longer white. The area of the inner EventBox takes on the appearance of the outer EventBox with its background colour of slateblue. But, the inner eventbox still intercepts the clicks made inside its borders even though the above-child is set to false – click on the Update button and see.
Now set the outer eventbox visible-window attribute to false and see the effect on the background colour and on the clickability of the Refresh button and run the example – the Refresh button is no longer clickable and the entire area of the outer EventBox, with its contained inner EventBox, has the default window colour.
Now set the inner eventbox visible-window attribute to true and run the example. The background colour of the inner EventBox is white but the Update button is still not clickable even though both eventboxes have the above-child attribute set to false.
This behaviour is, to me at least, counterintuitive but that’s what it is. Go figure.
Using eventbox to create a framed “help window”
A handy trick, which nested eventbox elements afford, is the ability to create a coloured “frame” around arbitrary content. The example below takes advantage of this trick to create a framed “help window”.
The screenshot below shows what is meant:
The window with the red border and the white background is shown when the Help button is clicked. Clicking on it or anywhere else other than on the Help button makes this window disappear.
The red border and the white background to the content inside are accomplished with the aid of the nested eventbox objects.
Execute the following commands, including copying and pasting the body of the example between geany and EOSCRIPT.
Note the sections highlighted in bold. These are the major adifferences between this example and the previous example.
There are a number of objects and patterns, apart from the eventbox, which this example introduces. They will not be discussed here. Of passing note are the use of the <eventbox><vbox><eventbox> construct to create the red border around the inner eventbox and its content, the escape key and focus-out-event handlers and the launch:HELP_WINDOW in the main window’s Help button, and closewindow:HELP_WINDOW in the help window itself.
Run the example and click the Help button. The application will launch the help window and make it disappear when the the escape key is pressed or when the mouse is clicked anywhere outside the boundaries of the Help button.
Using eventbox to create a Popup Menu
In this example we expand the use of the nested evenboxes to create a right-click popup menu.
The screenshot below shows what is meant:
The window with the red border and the white background, and the two checkboxes, is shown when the right mouse button is clicked. Setting and unsetting checkboxes is done as expected – click the checkbox or its label, use the keyboard to alternate between selecting one or the other checkbox, press enter or space to change the state of the selected checkbox. Clicking anywhere else outside the boundaries of the menu makes this menu disappear.
The menu and menu handling in this example was inspired by the example at http://blog.puppylinux.com/?viewDetailed=00030.
The red border and the white background to the content inside are accomplished with the aid of the nested eventbox objects. Checkboxes and their handling are the same regardless of what sor of window they are in.
In this example the state of the checkboxes must be persisted when the menu is closed. Since gtkdialog does not have the mechanism to have a signal handler directly programmatically set the value of a variable (push model) two functionas are introduced to set and get the value of the checkbox using a file in the file system for persistence. This was inspired by one of the gtkdialog examples and may be explored in another article. For now it should suffice to say that checking and unchecking one of the checkboxes casues the value of the checkbox (true/false, checked/unchecked) to be written to a corresponding file and the state of he checkboxes is read form these files whenever the popup menu is shown. The values of the checkboxes are read in the Refresh and Update button handler to control its logic.
Execute the following commands, including copying and pasting the body of the example between geany and EOSCRIPT.
Note the sections highlighted in bold. These are the major adifferences between this example and the previous example.
The screenshot shown before illustrates the application appearance when the right-click menu is show. In the screenshot below one of the results of checking the checkbox is shown, as an illustration of what the button handler does when the checkboxes is checked.
Using eventboxes to add frames to objects
It may be hard to work out what space the various objects in a gtkdialog application actually occupy on the screen because most, like text labels, horizontal and vertical boxes, and others, do not have visible bounding boxes which could be used to gauge that. In this example I demonstrate hos nested event boxes can be used to add visible borders to all objects and how to quickly remove them / make them invisible. This use of eventboxes is somewhat off-field but somebody muight have a use for it, during development if not in an actual useful applications.
The following screenshot illustrates one of the manifestations of this.
Execute the following commands, including copying and pasting the body of the example between geany and EOSCRIPT.
Executing this script using the command above produces:
It is difficult to say, looking at the screenshot, what are the boundaries of the various objects which are present inside the window.
Let’s consider the following code snippet:
Note the
$(_beginFrame)
and$(endFrame_)
constructs.Bash functions with the names _beginFrame and endFrame_ are executed at the time the gtkdialog XML file is being written using the
'cat <<-EODECK > ${MAIN_DIALOG_FILE}'
“here document” construct. Whatever these functions write to the stdout becomes injected into the here document at that place.In the following code fragment in the source given above note that the first pair of _beginFrame and endFrame_ funcions is commented out and the second pair is “active”. The active functions write an empty string to their stdout consequently only a newline is injected into the gtkdialog definition at the places they are invoked.
Execute the following on the command line to see this. The following fragment illustrates this:
Now comment out the active functions and uncomment the inactive functions as shown:
Execute the same command as before and note the output.
Text in bold highlights the code which was injected into the definition of the UI.
Executing the example produces the visual appearance shown in the earlier screenshot, repeated here:
To understand what this code does let’s have a look at the artefacts which are “injected”.
The _beginFrame function emits the following code, here distributed over multiple lines for ease of reading:
The outer eventbox sets the background colour of all it contains to whatever the style defines for the “outer_colour”, which in the example happens to be blue.
The vbox with the width of 1 causes a 1 pixel wide border to be shown. That border’s colour is inherited from the outer eventbox and is of the colour that eventbox’s style defines.
The inner eventbox sets the background colour of all of its content to the inner_colour, which happens to be green.
The innermost hbox adds a 1 pixel border around anything it contains and that border inherits the inner eventbox’s background colour.
Not the green 1 pixel border around the Quit button.
The injected _beginFrame code “starts” definitions of 4 containers. These containers must be “finished”/”closed” so the endFrame_ function supplied the closures:
Now change the code for the _beginFrame so that it reads as follows and execute the example:
The ending hbox no longer provides the 1 pixel green inner border so the application window now looks like:
Note that, for all intents and purposes the green 1 pixel border around the Quit button is gone. The 1 pixel green borders around all the other components is also gone, though it is harder to see. Scroll back to the previous screenshot and compare them.
Now change the definitno so that the vbox border is 0 pixels and execute the example:
This results in the following appearance:
The blue lines are even closer together.
Now change the border-width of the outer eventbox to 0 and execute the example:
Now change the border-width of the inner eventbox to 0 and execute the example:
The remaining blue areas are there because:
Reset the values of the 4 border-width attribtes back to 1.
Notice that the vbox and hbox objects which are injected by the _beginFrame function carry the spacing=”${_SPACING}” attribute. In the original source the value of this attribute is defined as 0:
_SPACING=0
Change the value to 10 and execute the example:
_SPACING=10
Notice that extra space was added between the vboxes and between the hboxes.
Comment out the _beginFrame and endFrame_ functions which inject the extra code, uncomment the _beginFrame and endFrame_ functions which do not inject the code and execute the example.
Compare the original windows and the window with the extra spacing added by the hbox and vbox elements.
If one does not have a way to see the bounding boxes of the various elements it is pretty much impossible to see what adds spaces, where and how much.
Summary
We explored the styling of the notebook object and its content, reviewing in the process how one can derive paths to various UI components which the widget_class requires to apply styles.