Styles, RC Files, and Themes


To go along with the work that raster is doing here at
RHAD on themes, I've been thinking about the subject of
extending RC files to handle the whims of a theme engine.

(For those who are unfamiliar with the concept, a theme
engine is a library of C routines to draw bits of widgets.
Theme engine + Set of configuration files = Theme)

My first thought, was simply to do something like

# Declare a style called "pixmap-button"
style "pixmap-button" {
  bg[NORMAL] = "#aabbcc";
  engine "pixmaps" {
  # This portion parsed by the pixmap theme engine
    bevel[NORMAL][] = { "button.png", 15, 32 18, 3 }

# Give all widgets in class GtkButton and derived classes
# the style "pixmap-button"
class "GtkButton" style "pixmap-button"

However, Tim pointed out that this doesn't work well if
a program or user does, on top of the theme:

style "my-button" {
  fg[NORMAL] = "ff0000"

# Set all widgets with the name MyButton to have style "my-button"
widget "*MyButton" style "my-button"

Instead of getting a pixmap-button with red text, the
result is a default GTK+ (non-themed) button with red

Both Tim and I had solutions to this problem:

Tim thought (thinks) that the right thing to do is to
separate out the theme from the style. 
style {} declarations would be restricted to exactly
what they are now, but there would also be style_class {}
declarations that served two purposes:

 - They set internal options for the theme engine
 - They set defaults for the the core parts of the style.

This is only interesting if different widgets can get
different defaults, independent of what RC styles are set
for those widgets. So you have to be able to combine an RC
style with a certain set of defaults after the fact. If you
have "n" RC styles and "m" style classes, you can end up
with n*m different styles.

  An RC style, is what is declared by a style {} declaration
  in an RC file. This is different from the actual 'style'
  object that is accessed as widget->style 

Now, it occured to me, if the code is being added anyways
to allow layering a style on top of a set of defaults,
you might as well just allow layering one RC style 
on top of another RC style.

So, I came up with an alternate approach. Currently, the 
last pattern specified that matches a widget completely
determines that widget's style.

In the new approach, every pattern that matches a widget
affects the style, but options specified in higher
priority patterns (those specified later in the file)
overrides lower priority styles.

So, the declaration:

style "my-button" {
  fg[NORMAL] = "ff0000"

widget "*.MyButton" style "my-button"

simply makes MyButton have the style it would have if the 
pattern was not there at all, but with a red foreground in 
the normal state.

Implementation details

I implemented my approach last night, and so far it seems
to work fairly well. (It needs to be benchmarked some - 
it should do considerably more pattern matches than the
current code, since it must match against every pattern,
not just match patterns until one succeeds, but I don't
know if this will have a significant effect on 
performance in the end.)

The way I did it was to make a GSList of the RC styles for
every pattern that matched a given widget. Then use the
GSList as a key to look up the style in a hash table. If no
style is found, then layer the RC styles together to form a
style and store that in the hash table.

Source availability:

A patch against CVS to implement this (no theme support,
just the modification to the way RC styles are formed
and looked up)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]