Up

GSTheme

Authors

Adam Fedor (fedor@gnu.org)
Richard Frith-Macdonald (rfm@gnu.org)
Useful/configurable drawing functions

Copyright: (C) 2004-2006 Free Software Foundation, Inc.


Contents -

  1. The theme management system
  2. Types of theming
  3. Subclassing GSTheme

The theme management system

The theme management system for the GNUstep GUI is based around the GSTheme class, which provides support for loading of theme bundles and methods for drawing common user interface elements.
The theme system works in conjunction with a variety of other GUI classes and is intended to eventually allow for very major changes in GUI appearance and behavior.

Various design imperatives apply to the theme system, but probably the key ones are:

To attain these aims implies the recognition of some more specific objectives and some possible technical solutions:

Types of theming

There are various aspects of theming which can be treated pretty much separately, so there is no reason why a theme might not be created which just employs one of these mechanisms.

System images
Possibly the simples theme change... a theme might supply a new set of system images used for arrows and other icons that the GUI decorates controls with.
System colors
A theme might simply define a new system color list, so that controls are drawn in a new color range, though they would still function the same way. Even specifying new colors can make the GUI look quite different though.
Beyond system colors, the theming API also provides a mechanism for specifying colors for particular parts of GUI controls.
Image tiling
Controls might be given sets of images used as tiling to draw themselves rather than using the standard line drawing and color fill mechanisms.
Interface style
A theme might supply a set of interface style keys for various controls, defining how those controls should behave subject to the limitation of the range of behaviors coded into the GUI library.
Method override
A theme might actually provide code, in the form of a subclass of GSTheme such that drawing methods have completely custom behavior.

Subclassing GSTheme

While many themes can be created without subclassing GSTheme, there are some cases where writing code is necessary (most notably when interfacing to a native theming engine for some platform in order to make a GNUstep app have a native look).
In these cases the subclass should follow certain rules in order to operate cleanly and efficiently:

Stability
Theme operation should remain consistent while it is in use, particularly in the provision of resources such as images and colors.
If a theme needs to change a resource (such as an image) then it should do so by calling -deactivate , making the change, and then calling -activate . This sequence ensures that the GUI library is made aware of any changes and can redraw the screen.
The deactivation/activation sequence is expensive, so the subclass should attempt to combine multiple resource updates into a group rather than performing the deactivation/activation for each resource individually.
Activation
The standard -activate method replaces existing system images, colors, interface style settings and other user defaults settings with versions stored in the theme bundle.
If a subclass wishes to dynamically provide these resources rather than supplying them as static information in the bundle, it may update the in-memory information after the normal operation has taken place. This should be done by the theme registering itsself as an observer of GSThemeWillActivateNotification and adding the resources just before the theme becomes active.
Cleanup may be done in response to a GSThemeWillDeactivateNotification (called before the default cleanup) or a GSThemeDidDeactivateNotification (called after the default cleanup).
Versioning
With a theme which contains only static resources, versioning is not much of an issue, but with a code-based theme (ie where you subclass GSTheme) versioning does become very important. This is because, while you can load code from a bundle, you can't unload it again... so if you have two versions of a theme where the subclass has the same name, then you have a conflict and can't load both and swap between the two.
Thematic.app solves this problem my incorporating a version number into the name of the GSTheme subclasses it creates, but that's not the only consideration...
You must also ensure that either you do not define any other classes in your theme or that, if you do define them you make sure that each of them incorporates the theme version number.
A similar consideration would apply to any categories, however category conflicts are far more difficult to resolve since even with different version names of the categories, the categories all effect the same class/methods. In fact this issue is so tricky to deal with that you should simply not use categories within your theme code.
To work around this limitation, the GSTheme class supports overriding of the methods of any other class while the theme is active. See the -overriddenMethod:for: method for more information.
Image override
System images (those returned by the [NSImage +imageNamed:] method) are handled by the default theming mechanism, for each system image supplied in the theme bundle, the image is loaded from the bundle and used while the theme is active. Any pre-existing in-memory image is saved on theme activation and restored on theme deactivation.
A theme subclass may override the -imageClass method to change the class used to load each image from the bundle... thus allowing customisation of not just the images but also of the image behavior in the (very rare) cases where this is desirable.
Finally, a theme may provide application specific images which are loaded in preference to named images from the application's own bundle. These images are simply stored in a subdirectory whose name is the same as the application's bundleIdentifier.

Up