ActionTimer Overview
The Update Challenge
To understand the purpose of ActionTimer, it helps to have some understanding of how Rainmeter runs a skin. On each skin
Update, the value set in the [Rainmeter] section of the skin, Rainmeter does the following:
- Update all measures
- Execute measure actions
- Update all meters
- Redraw the skin
Update has a lower limit of 16, or once every 16 milliseconds. This means that any series of separate actions can only execute every 16 milliseconds. In addition, setting a very low Update rate in [Rainmeter] can cause the entire skin to use a lot of CPU resources, when you may only need it to be "fast" for a specific purpose, perhaps some animation or transition effect. Finally, any series of actions you take in the context of the Update cycle are "blocking", in the sense that Rainmeter must complete them before it is able to continue with other normal skin processing.
While you can "stack up" actions in a single action option:
IfTrueAction=[!SetOption SomeMeter X "5"][!SetOption SomeMeter X "10"]
Rainmeter will run both of the actions in the same Update cycle, before it updates the meters and redraws the skin, and so in effect they both visibly happen "at once". The meter won't visibly move to "5" and then "10", but will just jump straight to "10". The only current solution is to have the two actions take place in two Update cycles, and thus the fastest the series can ever execute is every 16 milliseconds.
Now 16 milliseconds seems pretty fast, and it is. However, if you have some animation with 100 "frames" or want to do some "transition" of a meter; fading the opacity, shifting the color or sliding the position, it is in fact visibly quite slow, and in addition quite CPU "expensive".
Don't forget as well, that that 16 millisecond lower limit is the time Rainmeter will have to do everything in the skin. Update all measures, take all actions, update all meters, and redraw the skin. In reality, even a moderately complicated skin isn't really going to update every 16 milliseconds in any case, it will at best "try to".
The ActionTimer Solution
What ActionTimer does is execute the list of actions defined in
ActionListN, one after the other, in a separate thread outside the normal Update cycle, as fast as it possibly can. This is REALLY fast. The
Wait N values that you put in between each action in the list is what stops them from appearing to just happen all at once, and allows you to completely control the speed of the series of actions. Wait can be any number, from 1 (one millisecond) to whatever you need.
Since the actions in
ActionListN are executed in a separate thread from the main Rainmeter process, the skin will carry on updating normally, while the ActionTimer plugin will control the actions in the list.
Say goodbye to the 16 millisecond limit for your animations or meter transitions, and goodbye to unreasonable CPU usage when you have one simple animation in a larger more complex skin.
The examples in the .rmskin in the post above demonstrate some different ways you might use the plugin. However, it is designed with the maximum amount of flexibility we could give it, and the uses you find for it are only limited by your imagination.
toolbar.gif
Important Considerations
- Generally, you will need to update meters and redraw the skin between actions in the list.
Remember our example of "stacking up" actions in a single options above:
IfTrueAction=[!SetOption SomeMeter X "5"][!SetOption SomeMeter X "10"]
As we noted, those would in effect both happen "at once" visibly. What ActionTimer does to address this is in effect:
Code: Select all
ActionList1=[!SetOption SomeMeter X "5"]|Wait 10|[!SetOption SomeMeter X "10"]
That Wait, which is the key to ActionTimer, will cause a 10 millisecond delay between each action.
That is a start, but hold on... since it doesn't update [SomeMeter] or redraw the skin in between, the visible effect is still going to be "all at once". What you really want it to do is:
Code: Select all
ActionList1=[!SetOption SomeMeter X "5"][!UpdateMeter SomeMeter][!Redraw]|Wait 10|[!SetOption SomeMeter X "10"][!UpdateMeter SomeMeter][!Redraw]
While that is the effect we want, ActionListN is actually always defined with separate ActionName options, each called in the order they are in the list:
Code: Select all
ActionList1=MoveFive|Wait 10|MoveTen
MoveFive=[!SetOption SomeMeter X "5"][!UpdateMeter SomeMeter][!Redraw]
MoveTen=[!SetOption SomeMeter X "10"][!UpdateMeter SomeMeter][!Redraw]
You can use variables to shorten things as well:
Code: Select all
[Variables]
U=[!UpdateMeter SomeMeter][!Redraw]
[SomeMeasure]
Measure=Plugin
Plugin=ActionTimer
ActionList1=MoveFive|Wait 10|MoveTen
MoveFive=[!SetOption SomeMeter X "5"]#U#
MoveTen=[!SetOption SomeMeter X "10"]#U#
- Dynamic variables in actions are only updated when the ActionTimer measure is updated.
Dynamic #Variables# used in a measure in Rainmeter are resolved only when the measure is updated, and only if DynamicVariables=1 is used on the measure. This means that if we want to "increment" a variable during the ActionListN processing, for instance:
Code: Select all
[SomeMeasure]
Measure=Plugin
Plugin=ActionTimer
ActionList1=ChangeSizeCalc|Wait 5|ChangeSizeCalc|Wait 5|ChangeSizeCalc
ChangeSizeCalc=[!SetVariable Size "(#Size#+5)"]#U#
DynamicVariables=1
Then not only does our #U# have to take care of updating the meters we want to change, and redraw the skin, but we also need to update the [SomeMeasure] measure between each action:
Code: Select all
[Variables]
Size=8
U=[!UpdateMeasure SomeMeasure][UpdateMeter SomeMeter][!Redraw]
That way when #Size# is used in the actions, it will always have the "current" value of the variable, and can be used to increment itself.
Hint: Since an ActionTimer measure returns no value, and does no processing unless called with !CommandMeasure, this would be the only reason to ever update the measure, and generally you can just set UpdateDivider=-1 on it. This can be useful to keep the normal skin update from updating the value of variables in the measure, perhaps before you are ready.
- ActionListN is a "list" and not a "loop".
Attempts to create a recurring loop of actions, by for instance having the last (or worse yet only) item in an ActionList execute the same ActionList, is not what is intended for this plugin. It will attempt to protect you from creating a "runaway" measure, by not allowing the list to be executed while it is still running, however even that will cause Rainmeter to use excessive CPU or even become unresponsive if the plugin and Rainmeter are having to deal with the error condition every few milliseconds.
Don't forget that the ActionList, the plugin, is running in a separate thread from the main skin Update cycle. While that can allow for much faster actions than normal, it also removes the automatic "throttle control" that the Update cycle provides. A loop inside the thread can easily and quickly cause the plugin to overwhelm Rainmeter's ability to manage the action messages coming from it.
Extreme care should be used when trying to find ways to avoid a long "list", by creating loops "inside" the plugin. It will be very tricky to get them to work right, and in fact they are almost certain to cause problems. Any loops should be "outside' the plugin, using Loop, Calc or String measures with IfCondition / IfMatch testing to restart the plugin as needed to have the ActionList run "endlessly" in a safe way.
You do not have the required permissions to view the files attached to this post.