wmii: auto-tagging

September 1st, 2006

Lately I’ve been playing with wmii, the window manager. The ruby-addons for wmii by mfp open up the base wmii quite a bit. Once I got used to this dynamic window manager, I can’t imagine going back to WIMP.

I started to poke around in the ruby-wmii config files, because I was curious about how whenever I opened Firefox, the client was automatically tagged with “web”. Since I was constantly tagging my other apps with names using MODKEY-ctrl-T, I decided I wanted some of them to auto-tag like the browsers do.

After initially just copying the existing code that tags the browsers, I finally worked out a way to get it to tag things the way I want them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
 # *** excerpt of wmiirc-config.rb ***

 # first, I commented out this orginal tagger

 # {{{ Tag all browser instances as 'web' in addition to the current tag
 # browsers = %w[Firefox Konqueror]
 # browser_re = /^#{browsers.join("|")}/
 # on_createclient(condition{|c| browser_re =~ read("/client/#{c}/class")}) do |cid|
 #   write("/client/#{cid}/tags", normalize(read("/client/#{cid}/tags") + "+web"))
 # end

  #############################################
  # here's the stuff I added
        
  # these are tags for particular apps that I want to have 
  # new tags - note, they won't get appended to their current tag

  tag_for_apps = { 
    "irc" => "Xchat", 
    "gaim" => "Gaim", 
    "web" => "Firefox",
    "4-jedit" => "jedit"
  }
  
  # these are terminals that I've given specific titles to
  # so they can be tagged
  tag_for_named_terms = {
    "2-consoles" => "console:",
    "3-logs" => "log:",
    "1-terms" => "term:"
  }
    
  # now when a new client comes up, check for an autotag
  on_createclient do |cid|
    LOGGER.info "checking for autotag on class: #{read("/client/#{cid}/class")} " + 
        "and name: #{read("/client/#{cid}/name")} "
    # if this client is a terminal, check the 'name'
    if /terminal/ =~ read("/client/#{cid}/class")
      tag_for_named_terms.each do |tfn|
        names_re = /#{tfn[1]}/
        if names_re =~ read("/client/#{cid}/name")
          write("/client/#{cid}/tags", tfn[0])
          LOGGER.info "  ... autotag'd #{tfn[1]} with #{tfn[0]}!"
        end
      end
    # not a terminal, so go by the 'class'
    else
      tag_for_apps.each do |tfa|
        apps_re = /#{tfa[1]}/
        if apps_re =~ read("/client/#{cid}/class")
          write("/client/#{cid}/tags", tfa[0])
          LOGGER.info "  ... autotag'd #{tfa[1]} with #{tfa[0]}!"
        end
      end
    end
  end

Notice, for terminals, I check for certain terminal window titles. I changed my gnome-terminal script a bit, so now it looks like this:

#!/bin/sh

# set working dir
wd="/home/jason/dev/rails_app" 

gnome-terminal --working-directory=$wd --hide-menubar -e "mongrel_rails start" -t "log: web server" \
--window --working-directory=$wd --hide-menubar -e "tail -f log/development.log" -t "log: dev log" \
--window --working-directory=$wd --hide-menubar -e "script/console" -t "console: rails irb" \
--window --working-directory=$wd --hide-menubar -e "mysql -u root --password=mysecret myapp_development" -t "console: mysql" \
--window --working-directory=$wd --hide-menubar -t "term: approot"

For some of my tag names, I stick a number in the front – that’s just to force them into order so I can easily MODKEY-n over to them.

I’d like to work the auto-tagger out into a plugin, but after poking around some of the existing plugins I gave up. I have no idea how to check for on_createclient from within a plugin, and I’m pretty confused about how those long-winded option get passed to plugins. If anyone has any hints, I’d love to hear them.

4 Responses to “wmii: auto-tagging”

  1. moskvax Says:

    What’s the advantage of this over the built-in wmii rules? Maybe I don’t get something, but it looks to me like what you’ve written is basically the same functionality-wise as this, earlier on in the wmiirc-config.rb:

    rules <<eof />EOF

    When I start firefox, nicotine, etc. or open new windows within them, they are “auto-tagged”, i.e. they pop up in a view with no other tags than what I’ve specified there.

  2. moskvax Says:

    and the thing I’ve pasted looks like this with linebreaks:

    
    rules <<EOF
    /Firefox/ -> net
    /Nicotine/ -> p2p
    /Azureus/ -> p2p
    EOF@
    
    

    I apologise for the comment spammage, I really have no experience with making comments on blogs ;)

  3. Jason Says:

    Um. I guess I didn’t realize you could do that. When I looked at the default ‘rules’ I just got the impression they were mainly there for sending certain apps to the floating layer. I saw the section for tagging Firefox/Konquerer with ‘web’ and assumed that was the way to do it.

    In retrospect, I guess the only advantage to using my example is if for some reason you want a little more control, as with the way I ‘title’ my terminal windows and then tag them by parts of their titles.

  4. mfp Says:
    The functionality provided by tag_for_apps is equivalent to the rules moskvax showed. However, the one thing the code in the default wmiirc-config.rb (with the on_createclient callback) does that rule matching can’t is adding a tag without replacing the current one. For instance, whereas
    rules <<EOF
    /Firefox/ -> net
    EOF
    
    would tag firefox as “net” unconditionally,
      # {{{ Tag all browser instances as 'web' in addition to the current tag
      browsers = %w[Firefox Konqueror]
      browser_re = /^#{browsers.join("|")}/
      on_createclient(condition{|c| browser_re =~ read("/client/#{c}/class")}) do |cid|
        write("/client/#{cid}/tags", normalize(read("/client/#{cid}/tags") + "+web"))
      end
    
    merely retags it as <current_tag>+web. The point of this is ensuring that all browser windows are visible in the “web” view (so that I can close them easily
    I often have a dozen tags at a time and going through each one to close old windows would be painful), while letting each window remain in the view where it was created originally.

    Here’s another use case: when I’m hacking rcov, I often want to have both a browser window and the console where I’m hacking visible at a time. If my browsers went to “web” automatically, I’d have to pull one by going to the web view and retagging it as +rcov. With the above code, it’s tagged as rcov+web and I don’t need to retag.

    As for how to wrap it up as a plugin: atm. only bindings and bar applets can be imported selectively with
      from "me@foo.com" do
        use_binding "bar" 
        use_bar_applet "baz" 
     end
    

    This means that right now your snippet would have to be added to wmiirc-config.rb directly. However, I’ll probably implement “generalized plugins”, which would allow any code to be evaluated in the WMII::Configuration context. I’ll also try to improve the documentation.

Sorry, comments are closed for this article.