The subject of restrictions should already be familiar to you if you've read How Does it Work?. If you haven't, please do so before reading the rest of this section as it contains important information needed to understand the content of this page.
During the development of more complex skins, some special requirements may become apparent to you. For example, you want to change the text somewhere in a Messenger window and you don't want the modification to look bad in localized versions of Messenger. Without restrictions, the only way to do this properly would be to create two different versions of your skin and distribute them separately. If you then want to add a third and fourth language, maintaining all the different versions of the same skin can quickly become troublesome.
Languages are used here as an example to illustrate the need for a more general feature: being able to specify resources that depend on external factors. This ability can be found in the Messenger Plus! skinning system through the use of restrictions. Restrictions represent the first key element you'll need to learn to do more in your skins and stop feeling constrained in a static environment.
Resource groups exist because of restrictions. In all the examples you've seen so far in this documentation, the use of resource groups was limited to its most primary use: one resource group with one version restriction to create one specific target for the skin. Adding more resource groups to your skin becomes a necessity when you start considering issues such as language and you don't want to copy/paste big chunk of data because of a single line of text. If we keep on using the example of localization, here is how the problem cited above could be solved:
Resource Group 1 Restriction: version Replace resources: pictures, definitions, style Resource Group 2 Restriction: version, language (English) Replace resources: strings (English) Resource Group 3 Restriction: version, language (French) Replace resources: strings (French)
In the first group, most resources are defined with a single version restriction to target the appropriate Messenger version. Everything that does not include text written in a specific language is included in this group. A specific group is then created for each of the languages supported, defining only the resources that are language-specific. When the skin is loaded, Messenger Plus! analyses every group one by one and load their content if the set of restriction is valid in the current environment. Here are some examples of loading sequences that could happen with the above conditions:
Be careful about the last example: you must never forget to add a default for specific restrictions. In the example above, if you wanted to restrict the whole skin to either English or French users of Messenger, then a matching language restriction would have to be added in Group 1.
Resource Group 1 Restriction: version, language (English, French) Replace resources: pictures, definitions, style
If you want your skin to be available to anybody, load English by default and still support French, just remove the language restriction from Group 2.
Resource Group 2 Restriction: version, language (English) Replace resources: strings (English)
Resource groups don't have numbers in skininfo files but Messenger Plus! loads the groups in the order they're specified. So if Group 2 was to include the default English strings with no language restriction, everything would work fine: English strings are always loaded by the skinning system when parsing Group 2 and if the restrictions of Group 3 are matching (French version of Messenger), then the strings are loaded again in French. Resources that are redefined in several groups are simply reloaded while the groups are analyzed sequentially. This means that the last definition of a resource is the one that's used in Messenger. If you were to switch Group 2 and Group 3, then the strings would always be displayed in English as the second group would be loaded conditionally in a French version of Messenger and the third group would always be loaded without language restriction, replacing any localized version of the text.
One important role of restrictions is the specification of Messenger versions. This is the only mandatory restriction that's required by Messenger Plus! to load a resource group. Restricting versions is required because you can't know what the next version of Messenger will be like and you certainly don't want to crash the all the users who've trusted your work in the last couple of months because they've just upgraded their Messenger. Versions restrictions allow you create a single skin that will work on every known version of Messenger. Version compatibility is the first cause of trouble for users who are interested in installing a skin and restrictions solve that problem transparently, without any hassle for the developer.
Let's re-use the logic of the previous language example. The problem is different but the implementation is the same and this time, we'll write it in proper XML. Consider this: you want to create a skin that replaces two pictures and a window definition file in Messenger. The skin needs to work with both Messenger 8.1 and Messenger 8.5. After analysis, you notice that the window definition file is different for each versions but the pictures' ids are the same. Here is the resulting skininfo data:
<MessengerSkin> <!-- Pictures for Messenger 8.1 and 8.5 --> <ResGroup> <Restrictions> <MsgVersions> <Version Major="8" Minor="1"/> <Version Major="8" Minor="5"/> </MsgVersions> </Restrictions> <Resources><Replace> <Graphics><Pictures> <Picture Id="162"> <File>away.png</File> </Picture> <Picture Id="163"> <File>busy.png</File> </Picture> </Pictures></Graphics> </Replace></Resources> </ResGroup> <!-- Definition File for Messenger 8.1 --> <ResGroup> <Restrictions> <MsgVersions> <Version Major="8" Minor="1"/> </MsgVersions> </Restrictions> <Resources><Replace> <Windows><Definitions> <Definition Id="920"> <File>convodef_81.txt</File> </Definition> </Definitions></Windows> </Replace></Resources> </ResGroup> <!-- Definition File for Messenger 8.5 --> <ResGroup> <Restrictions> <MsgVersions> <Version Major="8" Minor="5"/> </MsgVersions> </Restrictions> <Resources><Replace> <Windows><Definitions> <Definition Id="920"> <File>convodef_85.txt</File> </Definition> </Definitions></Windows> </Replace></Resources> </ResGroup> </MessengerSkin>
XML tends to make simple things look bigger than what they really are so the interesting parts have been formatted in bold. In this code, you can see 3 different resource groups, each one with a different set of restrictions and resources. Here is the result of this skin:
Windows Live Messenger 8.1
Windows Live Messenger 8.5
Because many kinds of restrictions exist in Messenger Plus! (as seen in the schema of SkinInfo), it is important to understand how they combine with each other. The rule is simple: restrictions of a same kind combine with a logical OR and groups of different kinds combine with an AND. In the example shown above, the first group specifies two restrictions of the same kind: Messenger version 8.1 and Messenger version 8.5. This is interpreted as "Use this group if the version of Messenger is either 8.1 OR 8.5".
Let's say you add a language restriction in the mix to target only American English versions of Messenger, like this:
<Restrictions> <MsgVersions> <Version Major="8" Minor="1"/> <Version Major="8" Minor="5"/> </MsgVersions> <MsgLanguages> <Language IsoCode="en-us"/> </MsgLanguages> </Restrictions>
It would be interpreted as "Use this group if the version of Messenger is either 8.1 OR 8.5, AND the language of Messenger is English-US". So you'd need either Messenger 8.1 English-US or Messenger 8.5 English-US.
If a second language restriction is added for French, as show here:
<Restrictions> <MsgVersions> <Version Major="8" Minor="1"/> <Version Major="8" Minor="5"/> </MsgVersions> <MsgLanguages> <Language IsoCode="en-us"/> <Language IsoCode="fr-fr"/> </MsgLanguages> </Restrictions>
The resulting interpretation would be "Use this group if the version of Messenger is either 8.1 OR 8.5, AND the language of Messenger is either English-US or French-FR". The skin would be applied to Messenger 8.1 English-US, Messenger 8.5 English-US, Messenger 8.1 French-FR and Messenger 8.5 French-FR.
Note that in the particular case of languages, it is possible to exclude a language instead of including it using the FilterMode attribute. For example, if you know your skin works with every localized version of Messenger 8.5 but does not work with the Traditional Chinese one, you can write the corresponding restriction as:
<Restrictions> <MsgVersions> <Version Major="8" Minor="5"/> </MsgVersions> <MsgLanguages FilterMode="exclude"> <Language IsoCode="zh-tw"/> </MsgLanguages> </Restrictions>
Messenger Plus! gives you access to several basic restrictions for your skin and more restriction kinds may be added in the future. However, what would happen if you wanted to add your own rules into your files? this would mean allowing users to change your skin at runtime with some kind of modifiable options. Fortunately, the system already supports this feature and calls it Skin Options. All you need to know about that subject can be found in the following section.
Specialized Subjects, How Does it Work?.