iPhone Theming on WinterBoard
Pretty much the most requested application for iPhoneOS 2.x has been SummerBoard. Unfortunately, RiPDev is busy writing a new Installer for 2.x (the branding for which they bought off of NullRiver, whom I hope made a pretty penny on that transaction), which means no SummerBoard, not for us. (Also, RiPDev seems like they are going to be selling a similar product via Installer, so its unlikely that they are going to want the competition from anything free.)
This, unfortunately, leaves the rest of us in a lurch. It gives me a warm feeling inside when I see the wallpapers I've taken show up behind SpringBoard, and I haven't been able to do that since I upgraded to the iPhone 3G. Seeing as I just finished releasing a new version of Cydia (which has a number of features people have been looking for in it), I figured I'd have time to solve this: enter WinterBoard.
Now, when I do things, I like to seriously do things. Here, that means not just creating a "temporary solution": WinterBoard, to me, needs to be everything SummerBoard was and wasn't. I mean, let's face it: SummerBoard was nice, but it just didn't cut it after a while and NullRiver pretty much stopped updating it after only a few months of work. Also, as it wasn't open source, no one else could continue the project.
For those who don't know that much about SummerBoard the idea is that you should be able to theme SpringBoard: change the icons of applications, use a custom wallpaper (well, a wallpaper at all), and even modify the statusbar and dock. This is pretty much all SummerBoard did, though. Even this had a bunch of issues involving localization (themes often do not work very well in other languages as icons are themed by the displayed name of the program. Besides, many more things to theme started cropping up in the community: sliders, batteries, etc..
What SummerBoard really had going for it, though, was how it worked: it hooks into SpringBoard and overrides functionality down into its core. This lets it swap out icons at runtime without having to actually muck around on disk and swap out the .png files. This, in turn, makes it incredibly safe: you don't have to worry that the guy packaging the theme managed to think through backups correctly (or that the people who wrote the package mangager didn't think through package conflicts... I'm looking at you Installer...): the theme sits entirely self contained in its own folder.
With WinterBoard, I therefore wanted to bring as much power as I could for theming the device down in one simple backend tool as I possibly could, and I think I've drastically succeeded. Pretty much every form of graphic-file related theme I've so far seen (and a few other varieties we may think of) is supported by WinterBoard, all using the SummerBoard model of "the safe other folder". WinterBoard truly is the modern replacement for SummerBoard. It's also open source.
What is a Theme?
A theme is a folder that sits in /Library/Themes (or $HOME/Library/SummerBoard/Themes, which is supported for backwards compatibility with SummerBoard, but storing themes there is wrong on a few different levels). These folders end in ".theme" and are otherwise the name of the theme; for example: "Transparent Icon Labels.theme". Inside of this folder you have a set of folders, a number of .png files, and optionally an Info.plist that contains some extended information.
One thing I wished I had done, btw, is spent the extra hour before going to bed thinking through having it be <name>.theme instead of just <name>, but by the time I woke up again there were already hundreds of themes posted and it was too late :P. I have gone ahead and made this change, as documented in the previous paragraph, but themes without this extension will still work.
One thing that is a drastic modification from SummerBoard is that you can have multiple themes installed at once. This is partly due to how powerful WinterBoard is: there are so many things you can theme that people really want to be able to mix and match them. This means you might have a battery theme installed from one source, a set of icons from another, and might override the wallpaper with your user settings.
The interface for this is a priority ordered list of themes that you can drag around (with the same interface as the MobilePhone favorites screen, although the dragging is a little more finicky, a bug I currently believe to be a fault in the control Apple made public for doing that), each of which can either be checked or unchecked, which indicates whether it is turned on.
Legacy Theme Support
As most of the existing themes out there are designed for SummerBoard, it is definitely important to support this "de-facto standard" of theme organization. The way a SummerBoard theme worked is by having a few components, all of which are optional:
- Dock.png - replacement graphic for the bottom dock (which may be transparent)
- Icons/ - a folder of files such as Calendar.png which are used as application icons
- StatusBar.png - graphic to display as the status bar at the top, when its "dark"
- Wallpaper.png - an image to display behind all of the icons on SpringBoard
This is really simple and is supported fully by WinterBoard. The one thing that should be pointed out: the Icons/ folder was horrendously non-internationalized. As it uses the displayed name of the program (such as "Calendar"), if you are using a different language icons simply don't theme. The way some of the larger themes got around this by seriously providing icons (often duplicate files as Installer didn't support symlinks very well at all) for every possible name of a program in the many languages the phone supported.
Personally, I think that's nuts, and it's been confusing users of WinterBoard over the last few days. WinterBoard therefore looks up the english variation of the name and attempts that if it can't find an icon specifically for the current language. Also, if you have your device switched to use Celsius for temperatures the Weather icon is also different (and is even loaded as a special case): WinterBoard corrects this oversight as well, mapping the Weather icon in as would be expected.
One final note on icon themes: App Store applications often are "composed" by SpringBoard from a flat, square graphic by wrapping them in a button style with a shadow. This effect can destroy many theme sets, to the point where people have called this wrapping "raping". WinterBoard therefore turns this behavior off for icons that are themed. If, however, your theme is designed with this effect in mind you can set the key ComposeStoreIcons to true in your Info.plist file. (Please note that this behavior is currently a little weird in how its supported with multiple themes. This will be fixed.)
- Video Wallpaper - Apparently some people have become addicted to video wallpaper, a feature that has been around on and off in various forms from random theme packages. In order to bring this into the WinterBoard fold you can specify a Wallpaper.mp4 file that will be placed at the very bottom of the wallpaper stack. Obviously, your video will need to be the right dimensions for the device. (Please note that right now it skips a little to a black screen as it loops.)
- Sounds - A bunch of system sounds are stored in /System/Library/Audio/UISounds/. If you create a folder in your theme called UISounds/ you will be able to theme these (provided you also can provide .caf files). Support for other formats may be forthcoming.
- Web Clips - If you want to theme Web Clips you can do so using Icons/ using the name of the clip (example: Google.png). This works very similarly to how Icons/ themes other icons by name.
- Lock Background - You can also theme the background of the lock screen using LockBackground.png.
- SMS Background - Behind the SMS windows you can put an image using SMSBackground.png.
- Debug Output - If you activate syslogd you can set Debug to true in your com.saurik.WinterBoard.plist preferences file (yes, this is rather esoteric) in order to get a dump of various hooks. This can help figure out filenames you might want to theme.
- Font Replacement - WinterBoard can globally rename one font into another. To do this, by way of example: you can place a key "FontName-Helvetica" with the value "Courier New" to use the latter font anywhere someone would have used the former.
- Per-Page Wallpapers - You can have a different wallpaper per page of SpringBoard icons by having a file named Page#.png, such as Page0.png. This graphic will be displayed above widgets and wallpapers, but below the icons. Unfortunately, due to a bug that I'm working on fixing, it will also be displayed above the dock when your icons are wiggling. Please do not freak out when this happens ;P.
- Icon Alpha - Setting the IconAlpha key of your Info.plist to some decimal number between 0 and 1 will affect the transparency of the icons.
Theming Bundle Resources
The entire idea, though, of theming things by their displayed named is wrong, even if not for localization reasons: with App Store multiple programs are allowed to have the same name. What they should have that's unique, though is their "bundle identifier". Pretty much everything we think about on Apple computers is stored in the form of a "bundle" (including our themes in short order, albeit usually with extensions like .theme... *sigh*). These then have names which are supposed to be unique (although watch them not end up being all the time in practice).
In general, the way you figure out the bundle identifier of a bundle is to open its Info.plist file and read the key for CFBundleIdentifier. This can be done using the Property List Editor tool on a Mac or by using either Apple's (desktop) or Erica's (on-device) plutil to convert the file to XML. Now, I realize this can be difficult, so please bear with me for a moment and I'll show you an alternative.
With this information you can now use the bundle identifier as the name of a file in Icons/ (such as Icons/com.apple.mobilemail.png). The fun doesn't stop there, though. More often than not (although there are some irritating exceptions) most of the graphics files on disk are loaded using a filename offset from a named bundle (in which case they are called "resources". An example of this are the pictures used for battery status on the lock screen. These files are stored in /System/Library/CoreServices/SpringBoard.app: a bundle that represents the SpringBoard program.
To theme these we then simply need to get their name (such as BatteryBG_1.png) and then place a file in Bundles/com.apple.springboard (com.apple.springboard is the bundle identifier of com.apple.springboard). As promised, there's another option if getting that bundle identifier is getting irritating: you can also use Folders/SpringBoard.app/BatteryBG_1.png to theme bundle resources by folder name.
This mechanism should provide a very generic mechanism for theming files from random programs even, including App Store applications. (This is possible to do in WinterBoard, btw, as WinterBoard doesn't just hook SummerBoard: its resident in every program that's running to provide global themes.) It is so generic that it even replaces StatusBar.png and Dock.png: we can theme FSO_BG.png and SBDockBG.png out of SpringBoard's bundle.
Oh, one more thing: as I love genericity I also use this system to replace the Icons/ folder entirely (which is kind of a weird concept anyway). The icons for applications are stored as icon.png inside the bundle and are accessed as such, so you can mostly theme using Bundles/com.apple.mobilemail/icon.png (for example). I think there may still be some issues with how this works, though, so I might stick to Icons/ for a bit longer until I iron out all the kinks (specifically having to do with multi-app bundles like MobileSlideShow).
Cached .artwork Themes
Finally, the most complex example of image-based themes I've so far seen has to do with .artwork files. These files exist as loading lots of small .png files from disk can be irritatingly time consuming, so instead they are loaded as a block and stored (I believe) in a shared memory cache. As these tiny graphics are often used to build all aspects of the interface these represent the ultima thule of iPhone theming.
Messing with them, though, is currently really hard: you have to use special tools to unpack the files and all you get out of them are a bunch of numerically-named png files (.artwork files don't have filenames in them). You then have to carefully make new images of the same size and rebuild the complete .artwork file, which then has to be installed on the phone with a rickety package that attempts to backup and restore the original. Yeek!
After I heard about this, I set out to fix this with WinterBoard: I want theming to be a fun, safe experience that can be taken up by anybody without special tools. To do this I first analyzed how .artwork files worked, and lo and behold there actually are filenames that go with all of those png files people were compressing (already this makes the task a million times easier.
At first I implemented this by providing a folder in your theme called UIImages/ in which you can store replacements for these files. As an example, you might have UIImages/UISearchFieldIcon.png (which happens to be the name of the little magnifying glass used at the left of text fields to indicate you can search with them).
However, I have since figured out that these .artwork files are actually designed to be a cache of files that are otherwise part of a bundle and should really be stored in Folders/UIKit.framework/. The UIImages/ path will be maintained for backwards compatibility. This new understanding, combined with some code updates, means that we can now theme any .artwork file (such as those used for MobilePhone.app).
I'm writing this documentation a little bit before the WinterBoard release related to it, so for right now you need to keep using UIImages/. The support for MobilePhone.app is in there, but hooking back to UIKit.framework/ is not.
Of course, you need to know what you can put there to make this feature useful. For a list of filenames you can theme you can grab this text file, but just having the names isn't really helpful. While I currently feel uncomfortable distributing a copy of these images from Apple as a file on my website, I have released a tool as part of WinterBoard that will let you quickly extract them for yourself called, yep, UIImages. Here's how you use it:
$ mkdir /tmp/images $ cd /tmp/images $ /Applications/WinterBoard.app/UIImages $ ls UISearchFieldIcon.png -la -rw-r--r-- 1 root wheel 468 Aug 4 03:13 UISearchFieldIcon.png
One final variant are things that are loaded from a "mapped image domain". Common examples of this are the TextInput localization bundles. The way you specify these is using Domains/TextInput_ru/std-kb-ru.png.
Theming with HTML
So, while staring at the desktop, I realized "wait, why don't I make that a website? then you could do all kinds of neat things with it!". This dream has been made a reality with the latest version of WinterBoard. There is a new file you can add called Wallpaper.html which puts a UIWebDocumentView behind SpringBoard. (You can use LockBackground.html to do the same thing on the lock screen.)
This view has a transparent background and has been told not to clear what's behind it, so you can set its background-color: CSS to transparent if you want to see through to Wallpaper.png (although you can also use standard HTML to handle the backgrounds now rather than resorting to that specific case).
The way I did this (and this is just a property of my theme, you can do anything you want obviously) is to use the WebKit-specific CSS properties Apple provided us with for doing transforms and animations. These work beutifully and are super fast. For more documentation on these, you should go to Apple's iPhone Reference Library and get the two guides they have for download.
If what you really want is to install "widgets" (things that sit on the wallpaper and provide interesting HTML functionality) then you should use Widget.html: these will get layered on top of all other wallpaper layers (in priority order) and not conflict against the wallpaper in other themes.
Theming .strings Localization Files
When a program needs to support multiple languages, what it does is it constructs multiple folders in its bundle of the form <language>.lproj. Inside of these folders it has .strings files, which are serialized property lists (which, in turn, can be in one of a number of different formats). These .strings files are called "tables" and map from "keys" to localized strings.
As an example, SpringBoard.app has a folder English.lproj, which contains a file SpringBoard.strings, which maps the key "AWAY_LOCK_LABEL" to the value "slide to unlock". This string is what is displayed on the main lock screen under the slider.
This file is stored in the binary version of the property list format, but you can convert it by first installing Erica's Utilities from Cydia and then running plutil -c xml1 on the file (I'd recommend doing this to a copy so you aren't changing your original).
If you'd like to change this text you can mirror that same structure in your theme under Folders/SpringBoard.app/. Inside your SpringBoard.strings you will want to map just that one string to a different value. The simplest format you can use is the string table format, which looks like this:
"AWAY_LOCK_LABEL" = "slide to saurik";
A quick note on the naming of a language: it used to be that, if you wanted English, you used English.lproj. This naming scheme was used for a few more languages until it became obvious that it didn't scale, at which point the localization system switched to using ISO country codes. The software on the iPhone, though, continues to use the older names for its .lproj folders.
However, I actually haven't figured out yet how to get these old names, so I don't support them. If you want to theme something in English you will need to use en.lproj, not English.lproj, even if the original folder on disk was using the older name.
SpringBoard Text Styles
For a while a really common request was that WinterBoard A) let you "fix" the color of the icon labels to SummerBoard's white and B) allow you to make them transparent. The former is supported by modifying Info.plist which allows for many CSS styles to be applied to the labels. This takes the form of two keys: DockedIconLabelStyle and UndockedIconLabelStyle. An example of a reasonable value is "color: blue; font-family: monospace".
The story on this is a little more complicated, though, and is worth mentioning: the default color for docked icon labels is white, but SpringBoard makes all the other icons get gray text. This behavior was apparently changed by SummerBoard to make the text more consistently viewable over random wallpapers. Specifically, all text is rendered white.
To make WinterBoard correctly support these old themes, it does something similar. Specifically, if it detects that no themes are specifically setting any styles (so there are no DockedIconLabelStyle or UndockedIconLabelStyle values in play) it forces SpringBoard to render all icon labels as if they were on the dock. To override specifically this behavior (which I doubt there is any good reason to do rather than just applying a specific style) you can set the key UndockedIconLabels to true.
Similarly, you can set TimeStyle to change the style of text used to render the clock on the status bar and OperatorNameStyle to change any text-based (not image based) carrier names (such as those used by MakeItMine). Another new addition is CalendarIconDateStyle and CalendarIconDayStyle, which modify the number and day of the week that are drawn on the calendar icon, respectively.
Finally we have BadgeStyle, which you can use to change the rendering of the little badge icons that appear on icons (like for new mail).
More to Come!
This is actually not even all WinterBoard does currently, but certainly isn't all WinterBoard will be able to do given another few days of work. For continued updates on new WinterBoard functionality keep checking out this page: I'm going to be continue to update this page as more features are designed!