Writing sublets¶
Hello world¶
Starting a sublet from scratch is really easy, just create an empty sublet with sur: sur template hello
This will create a folder hello with two files:
Filename | Description |
---|---|
hello.rb | The sublet file with the minimal required code |
hello.spec | The specification file with basic information for sur about the sublet |
Say hello¶
Per default, the new sublet will do nothing and we need to add something do the data field:
Numbers: on /off 1 # Hello sublet file
2 # Created with sur-0.2
3 configure :hello do |s|
4 s.interval = 60
5 end
6
7 on :run do |s|
8 s.data = "Hello, world!"
9 end
Using variables¶
Typically, a sublet just needs local and instance variables to store data across runs and/or to calculate intermediate values. Due to the DSL, instance variables that normally just need a to be prefixed with a just @ now need an owner to be tracked as instance variable. That can either be the first argument of every event block or self inside of a helper.
Numbers: on /off 1 # Hello sublet file
2 # Created with sur-0.2
3 configure :hello do |s|
4 s.interval = 60
5 s.world = "variable world"
6 end
7
8 on :run do |s|
9 s.data = "Hello, #{s.world}"
10 end
Move code to helper¶
Sometimes it can be useful to move code into own functions to call it on several events. Instead of just copying the code let's move the code into a helper. A helper is just another block that can be used to add methods to the sublet itself.
Numbers: on /off 1 # Hello sublet file
2 # Created with sur-0.2
3 configure :hello do |s|
4 s.interval = 60
5 s.world = "variable world"
6 end
7
8 helper do |s|
9 def hello_time
10 case Time.now.strftime("%H").to_i
11 when 6..9 then "Good morning"
12 when 10..15 then "Good day"
13 when 16..18 then "Good evening"
14 when 19..5 then "Good night"
15 end
16 end
17 end
18
19 on :run do |s|
20 s.data = "%s, %s" % [ s.hello_time, s.world ]
21 end
Test your sublet¶
sur comes with a tester for sublet to ease the whole thing: @sur test hello/hello.rb
The output looks like this:
Numbers: on /off 1 ------------------
2 hello
3 ------------------
4 @visible = true
5 @interval = 60
6 @config = {}
7 @world = "variable world"
8 @data = Hello, variable world!
9 ------------------
10 (1) run
11 (2) hello_time (helper)
12 (0) Quit
13 ------------------
14 >>> Select one method:
15 >>>
The lines starting with @ show the defined instanced variables, the lines with (1) the callable methods.
Install and submit¶
Once you are satisfied with your work you need to build your sublet: sur build hello/hello.spec
This will create a hello-0.0.sublet file that can either be installed locally sur install ./hello-0.0.sublet
or uploaded to the sur repository sur submit ./hello-0.0.sublet
and installed from there.
Components¶
Configure¶
A sublet starts with the configure block, which tells subtle the name and does basic initialization like the interval time if it's used. Assignment of instance variables must be done like s.value = "something"
or otherwise the DSL can't keep track of it.
Numbers: on /off1 configure :sublet do |s|
2 s.interval = 60
3 s.variable = "something"
4 end
Generally there are two different types of Sublets:
- sublets that are updated by given interval in seconds (default 60s)
- sublets that are updated when a file is modified (via inotify) or via socket
- sublets that are updated via SUBTLE_SUBLET_DATA client message
The sublet data must be of type String, everything else will be ignored.
Helper¶
Custom methods need to be written inside of a helper block to be used a instance method. Inside of this helpers, instance variables must be accessed via the self keyword:
Numbers: on /off1 helper do
2 def something(test)
3 self.variable = test
4 self.data = test
5 end
6 end
Events¶
Sublets are event driven, so there are some specific events only for sublets:
Name | Description | Arguments |
---|---|---|
:mouse_over | Whenever the pointer is over the sublet | s |
:mouse_down | Whenever the pointer is pressed on the sublet. | s, x, y, button |
:mouse_out | Whenever the pointer leaves the sublet | s |
:run | Whenever either the interval time is expired | s |
:watch | Whenever the watched file is modified/socket has data ready | s |
:data | Whenever subtle receives a SUBTLE_SUBLET_DATA client message for this sublet | s |
:unload | Whenever the sublet is unloaded | s |
Numbers: on /off1 on :mouse_down do |s, x, y, button|
2 puts "button %d at x=%d and y=%d" % [ x, y, button ]
3 end
Hooks¶
Sublets can use all hooks that are useable in the main config too, the syntax is almost the same:
Numbers: on /off1 on :client_create do |s, c|
2 puts s.name #< Name of the sublet
3 puts c.name #< Name of the client
4 end
Grabs¶
Since r2608 sublets can provide grabs identified by symbols, that can be used in the main config.
Numbers: on /off1 configure :grabby do |s|
2 s.interval = 5
3 end
4
5 grab :GrabbyGrab do |s, c|
6 puts "sublet name: %s" % [ s.name ]
7 puts "pressed on : %s" % [ c.name ]
8 end
Please use reasonable names for the grabs, there is no check or enforcement of names.
Configuration¶
Configuration of a sublet can be done (since r2148) Subtle::Subtle#config, this returns a hash and can be used as in the following example:
Numbers: on /off 1 # Config:
2 sublet :configured do
3 interval 50
4 some_string "#00ff00"
5 end
6
7 # Sublet:
8 configure :configured do |s|
9 s.interval = s.config[:interval] || 30
10 s.some_string = s.config[:some_string] || "default"
11
12 # Works with colors too
13 s.red = Subtlext::Color.new(s.config[:red] || "#ff0000")
14 end
15
16 on :run do |s|
17 s.data = s.red + s.some_string
18 end
The specification contains an info field that can be displayed via sur config sublet
, it's basically an array of hashes that contains information how to use it:
Numbers: on /off1 spec.config = [
2 { :name => "format_string", :type => "string", :def_value => "%y/%m/%d %H:%M", :description => "Format of the clock (man date)" },
3 ]
Customization¶
Colors¶
The color of the ouput of a Sublets can be changed in this way:
Numbers: on /off 1 configure :colorful do |s|
2 s.red = Subtlext::Color.new("#ff0000")
3 s.green = Subtlext::Color.new("#00ff00")
4 s.blue = Subtlext::Color.new("#0000ff")
5 s.background = "#303030"
6 end
7
8 on :run do |s|
9 s.data = s.red + "su" + s.green + "bt" + s.blue + "le"
10 end
Icons¶
There is also a way to add a X bitmap to a sublet:
Numbers: on /off1 configure :iconized do |s|
2 s.icon = Subtlext::Icon.new("/usr/share/icons/subtle.xbm")
3 end
4
5 on :run do |s|
6 s.data = @icon + "subtle"
7 end
A nice collection of this pixmap can be found here
Subtle will add a padding of 3px left and right of the pixmap, so keep that in mind when using the click hooks.
Examples¶
Below is the code of a shipped sublets that displays the time. It should be really straight forward:
Numbers: on /off1 configure :clock do |s|
2 s.interval = 60 #< Set interval time
3 end
4
5 on :run do |s|
6 s.data = Time.now.strftime("%d%m%y%H%M") #< Set data
7 end
Another example for the inotify sublet which is also included within subtle:
Numbers: on /off 1 configure :notify do |s|
2 s.file = "/tmp/watch"
3 s.watch(s.file)
4 end
5
6 on :watch do
7 begin
8 self.data = IO.readlines(@file).first.chop #< Read data and strip
9 rescue => err #< Catch error
10 puts err
11 self.data = "subtle"
12 end
13 end
The watch command also works with Ruby sockets, but be aware of blocking I/O:
Numbers: on /off 1 configure :socket do |s|
2 s.socket = TCPSocket.open("localhost", 6600)
3 s.watch(s.socket)
4 end
5
6 on :watch do |s|
7 begin
8 s.data = s.socket.readline.chop #< Read data and strip
9 rescue => err #< Catch error
10 puts err
11 s.data = "subtle"
12 end
13 end
14
15 on :run do |s|
16 # Do nothing
17 end
Subtle will automatically set sockets to O_NONBLOCK.
And finally an example with a click callback:
Numbers: on /off 1 configure :click do |s|
2 s.interval = 999 #< Do nothing
3 end
4
5 on :mouse_down do |s, x, y, button|
6 Subtlext::Client["xterm"].raise
7 puts x, y, button
8 end
9
10 on :run do |s|
11 # Do nothing here
12 end