gtkdialog – Applying styles to gtkdialog applications

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 http://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 http://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 http://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” (http://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:

  1. The named style is defined (there can be as many styles as are needed)
  2. The style is associated with one or more “targets” – widget, widget_class or class (more on that in the next section)
  3. The styles and associations are written to a GTK resource file
  4. 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.

Though the document at http://www.orford.org/gtk/ is entitles “Gtk2 Theme Creation Guide” it is actually quite enlightening for anyone who wants to style objects in gtkdialog-based applications, as I have been doing in this article. The “GTK Theming Tutorial” at https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes is similarly useful in this context even tough it might appear off-topic at first glance.

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:

  1. 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.
  2. One can change the numeric values for the various properties and the changes will be immediately reflected in the UI.
  3. Once can check and uncheck the checkboxes and the changes will be immediately reflected in the UI.
  4. 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.

2 thoughts on “gtkdialog – Applying styles to gtkdialog applications

  1. peter

    Hi,
    This is great, awesome!!
    But – scriptName=ex23 – testing with gtkdialog 0.8.3-3 with my own script – I will like to set the font size, but if I change “export GTK2_RC…” to “export GTK3_RC…” stays the same and with gtk2 it looks awful.
    How can I do that, or it’s possible to do it?
    Thanks, Great work!!

    Reply
    1. Czapski Michael Post author

      Hello, Peter.

      Thanks for the good word.
      I do all my gtkdialog work on RedHat 6-like OS’ because I need gnome 2 for various things so I did not test the examples on gnome3 until now that you pointed out the issue.
      Example 23 (ex23) works unchanged on gnome3 so give it a try without changing GTK2_… to GTK3_…
      Styling works as expected, though I must say that I am not particularly happy with the look of the example in CentOS 7 VBox image I downloaded from osboxes.org.

      Her is the link to what that result looks like for me: ex23 unde gnome3 with GTK2_... env variable

      Note that some of the icons I have in my gnome2 environment are evidently not present in gnome3 or are in different directories. In this case the gtk-quit icons is not found. Use “application-exit” in its place and you should see what is expected.

      All the best

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *