Snippets

This page shows small snippets that might be useful. Without further instructions they just need to be copied into the config of subtle.

Alt-Tab

This cycles through windows of view

Numbers: on /off 1 grab "A-Tab" do
 2   clients = Subtlext::Client.visible
 3 
 4   clients.last.instance_eval do
 5     focus
 6     raise
 7   end
 8 end
 9 
10 grab "A-S-Tab" do 
11 clients = Subtlext::Client.visible
12 
13   clients.first.instance_eval do                                                 
14     lower                                                                        
15   end
16   clients.first.instance_eval do
17     focus
18   end                                                                            
19 end

Extend view

Numbers: on /off 1 require "subtle/subtlext" 
 2 
 3 STORE ||= {}
 4 
 5 module Subtlext
 6   class View
 7     def method_missing(meth, *args)
 8       STORE[self.name] = { } unless(STORE.has_key?(self.name))
 9 
10       if meth.to_s.end_with?("=")
11         meth = meth.to_s.chop.to_sym
12 
13         STORE[self.name][meth] = args[0]
14       else
15         STORE[self.name][meth]
16       end
17     end
18   end
19 end

Finally make some use of this like following hook:

Numbers: on /off1 on :view_jump do |v|
2   v.visits += 1 rescue v.visits = 1
3   puts "View %s, %d visits" % [ v.name, v.visits ]
4 end

Focus gravities

Focus window a specific gravities on view.

Numbers: on /off 1 {
 2   "KP_7" => :top_left,    "KP_8" => :top,    "KP_9" => :top_right,
 3   "KP_4" => :left,        "KP_5" => :center, "KP_6" => :right,
 4   "KP_1" => :bottom_left, "KP_2" => :bottom, "KP_3" => :bottom_right
 5 }.each do |k, v|
 6   grab "A-C-" + k, lambda {
 7     c = Subtlext::View.current.clients.select { |c|
 8       c.gravity.name.to_sym == v
 9     }
10 
11     c.first.focus unless(c.empty?)
12   }
13 end

Move windows

This snippet adds nine grabs to move windows on the fly to nine defined views. It uses tagging for this, creates tags based on the view names and applies them when needed.

Numbers: on /off 1 on :start do
 2   # Create missing tags
 3   views = Subtlext::View.all.map { |v| v.name }
 4   tags  = Subtlext::Tag.all.map { |t| t.name }
 5 
 6   views.each do |v|
 7     unless tags.include?(v)
 8       t = Subtlext::Tag.new(v)
 9       t.save
10     end
11   end
12 end
13 
14 # Add nine C-< number> grabs
15 (1..9).each do |i|
16  grab "C-%d" % [ i ] do |c|
17    views = Subtlext::View.all
18    names = views.map { |v| v.name }
19 
20    # Sanity check
21    if i <= views.size
22      # Tag client
23      tags = c.tags.reject { |t| names.include?(t.name) or "default" == t.name }
24      tags << names[i - 1]
25 
26      c.tags = tags
27 
28      # Tag view
29      views[i - 1].tag(names[i - 1])
30    end
31  end
32 end

Current view

This snippet works similar to the previous, it adds tags based on the view names. When there is an untagged window (a window with the default tag only) it adds the name of the current view as tag, which effectively moves the window to the current view.

Numbers: on /off 1 on :start do
 2   # Create missing tags
 3   views = Subtlext::View.all.map { |v| v.name }
 4   tags  = Subtlext::Tag.all.map { |t| t.name }
 5 
 6   views.each do |v|
 7     unless tags.include?(v)
 8       t = Subtlext::Tag.new(v)
 9       t.save
10     end
11   end
12 end
13 
14 # Assign tags to clients
15 on :client_create do |c|
16   view = Subtlext::View.current
17   tags = c.tags.map { |t| t.name }
18 
19   # Add tag to view
20   view.tag(view.name) unless(view.tags.include?(view.name))
21 
22   # Exclusive for clients with default tag only
23   if tags.include?("default") and 1 == tags.size
24     c.tags = [ view.name ]
25   end
26 end

Scratchpad

The scratchpad snippet is just a small hack of the tagging. Normally subtle doesn't allow to create a window without tags, so that it's never visible. This grab just creates a urxvt, strips all tags and sets sticky. On the next press it just toggles sticky and blends the window in and out, like a scratchpad.

Numbers: on /off 1 grab "A-b" do
 2   if (c = Subtlext::Client.first("scratch"))
 3     c.toggle_stick
 4     c.focus
 5   elsif (c = Subtlext::Client.spawn("urxvt -name scratch"))
 6     c.tags  = [] 
 7     c.flags = [ :stick ]
 8   end
 9 end

Scratchstack

Like the Scratchpad, this snippet can show and hide a client, but instead just one specific client, it can cycle through multiple running ones. There are basically three grabs:

  1. Win-Keypad+ Adds a client to the stack and initially hides it
  2. Win-Keypad- Removes a client fromt he stack and retags it
  3. Win-comma Cycles through the clients on the stack
Numbers: on /off 1 scratch_stack   = []
 2 scratch_current = 0
 3 
 4 # Add window to stack
 5 grab modkey + "-KP_Add" do |c|
 6   unless scratch_stack.include?(c.win)
 7     scratch_stack << c.win
 8     c.tags = []
 9     c.toggle_stick if c.is_stick?
10   end
11 end
12 
13 # Remove window from stack
14 grab modkey + "-KP_Subtract" do |c|
15   if scratch_stack.include?(c.win)
16     c.retag
17     scratch_stack.delete(c.win)
18   end
19 end
20 
21 # Cycle through stack windows
22 grab modkey + "-comma" do
23   # Get id of next window
24   if 0 < scratch_current
25     cur_idx = scratch_stack.index(scratch_current)
26 
27     # Hide current window
28     cur_client = Subtlext::Client[scratch_current]
29     cur_client.toggle_stick
30 
31     # Check whether cur is last window of stack
32     if cur_idx == scratch_stack.size - 1
33       scratch_current = 0
34 
35       return
36     end
37 
38     idx = cur_idx + 1
39   else
40     idx = 0
41   end
42 
43   # Show next window
44   cur = Subtlext::Client[scratch_stack[idx]]
45 
46   scratch_current = cur.win
47   cur.toggle_stick
48 end

Check config

In case you keep forgetting to run subtle -k after changing the config this might be handy for you. It checks the config, displays a message via xmessage or just reloads the config.

Numbers: on /off 1 # Make xmessage stick and urgent
 2 tag "xmessage" do
 3   match  "xmessage" 
 4   float  true
 5   stick  true
 6   urgent true
 7 end
 8 
 9 # The actual grab
10 grab "A-C-r", <<SCRIPT
11 subtle -k &>/dev/null
12 reload=$?
13 
14 if [ $reload -eq 1 ] ; then
15   xmessage 'Syntax error, reload anyway?' -center -buttons NO:1,YES:0
16   reload=$?
17 fi
18 
19 [ $reload -eq 0 ] && subtler -r
20 SCRIPT

Switch view

Allow you to go to the next non-empty view. very useful when you don't want :ViewNext to go into hidden views (Mostly with dynamic views)

Numbers: on /off 1 def goto_next_view(vArr)
 2     cindx = vArr.index(Subtlext::View.current);
 3 
 4     #Find the next view beyond all existing
 5     for i in 1..vArr.size do
 6         cV = vArr[(i + cindx) % vArr.size];
 7 
 8         # Verify that the potential next view isn't displayed on another screens
 9         if (Subtlext::View.visible.index(cV) == nil) then
10             containsClients = false;
11             # Check if the view has clients and if those clients are not only sticky one.
12             cV.clients.each {|c|
13                 containsClients = !(cV.tags & c.tags).empty?;
14                 if(containsClients)
15                     break;
16                 end
17             }
18 
19             if (containsClients) then
20                 cV.jump;
21                 break;
22             end;
23         end
24     end
25 end
26 
27 grab "W-Right" do
28     goto_next_view(Subtlext::View[:all]);
29 end
30 
31 grab "W-Left" do
32     goto_next_view(Subtlext::View[:all].reverse);
33 end
34