commit f8efaf114f814d6482a2bb48dc841ddc09bad2eb
parent 7986a71694bfa39e1132205a9d2efc14e512a001
Author: Suraj N. Kurapati <sunaku@gmail.com>
Date: Tue, 12 Sep 2006 09:37:58 -0700
[project @ 1634e998051d2558b35bd4cd6767b9cba2a4745a]
[project @ 75]
split wmiirc into a loader & a config file
exceptions are now logged
runtime exceptions no longer crash the wmiirc causing unusable WM
Diffstat:
wm.rb | | | 7 | +++++-- |
wmiirc | | | 427 | ++----------------------------------------------------------------------------- |
wmiirc-config.rb | | | 446 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 461 insertions(+), 419 deletions(-)
diff --git a/wm.rb b/wm.rb
@@ -86,7 +86,7 @@ module Wmii
end
end
- puts "could not find #{aClientId}"
+ puts "could not find #{aClientId} in area #{aArea.inspect} or view #{aView.inspect}"
nil
end
@@ -332,18 +332,21 @@ module Wmii
private
# Updates the path of this area for proper insertion and inserts the given client.
def setup_for_insertion! aFirstClient
+ raise ArgumentError, 'nonexistent client' unless aFirstClient.exist?
+
dstIdx = self.index
maxIdx = parent.indices.last
if dstIdx > maxIdx
# move *near* final destination
+ clientId = aFirstClient.index
aFirstClient.ctl = "sendto #{maxIdx}"
# recalculate b/c sendto can be destructive
maxIdx = parent.indices.last
maxCol = parent[maxIdx]
- aFirstClient = Wmii.find_client(aFirstClient.basename, maxCol)
+ aFirstClient = Wmii.find_client(clientId, maxCol)
# move *into* final destination
if maxCol.indices.length > 1
diff --git a/wmiirc b/wmiirc
@@ -1,5 +1,5 @@
#!/usr/bin/ruby -w
-# Ruby-based configuration file for wmii.
+# Loader for ruby-based wmii configuration.
=begin
Copyright 2006 Suraj N. Kurapati
@@ -18,426 +18,19 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
=end
-$: << File.dirname(__FILE__)
-require 'rc'
+require 'logger'
-
-## WM startup
-
-FS = Wmii.fs
-FS.event = "Start wmiirc\n" # terminate existing wmiirc processes
-
-
-## executable programs
-
-# names of external programs
-PROGRAM_MENU = find_programs( ENV['PATH'].squeeze(':').split(':') )
-
-# names of internal actions
-ACTION_MENU = find_programs('~/dry/apps/wmii/etc/wmii-3', File.dirname(__FILE__))
-
-
-## UI configuration
-
-ENV['WMII_FONT'] = '-misc-fixed-medium-r-normal--18-120-100-100-c-90-iso10646-1'
-ENV['WMII_SELCOLORS']='#ffffff #285577 #4c7899'
-ENV['WMII_NORMCOLORS']='#222222 #eeeeee #666666'
-
-system %{xsetroot -solid '#333333'}
-
-
-## WM configuration
-
-FS.def.border = 2
-
-FS.def.font = ENV['WMII_FONT']
-FS.def.selcolors = ENV['WMII_SELCOLORS']
-FS.def.normcolors = ENV['WMII_NORMCOLORS']
-
-FS.def.colmode = 'default'
-FS.def.colwidth = 0
-
-FS.def.rules = <<EOS
-/jEdit.*/ -> code
-/Buddy List.*/ -> chat
-/XChat.*/ -> chat
-/.*thunderbird.*/ -> mail
-/Gimp.*/ -> gimp
-/QEMU.*/ -> ~
-/MPlayer.*/ -> ~
-/xconsole.*/ -> ~
-/alsamixer.*/ -> ~
-/.*/ -> !
-/.*/ -> 1
-EOS
-
-
-## key configuration
-
-# Symbolic name of modifier key.
-MODKEY = 'Mod1'
-
-# Symbolic name for up direction key.
-UP = 't'
-
-# Symbolic name for down direction key.
-DOWN = 'n'
-
-# Symbolic name for left direction key.
-LEFT = 'h'
-
-# Symbolic name for right direction key.
-RIGHT = 's'
-
-# Keycode for the primary mouse button.
-PRIMARY = 1
-
-# Keycode for the middle mouse button.
-MIDDLE = 2
-
-# Keycode for the secondary mouse button.
-SECONDARY = 3
-
-
-# Initial key sequence used by all shortcuts.
-ACTION = "#{MODKEY}-Control-"
-
-FOCUS = ACTION
-SEND = "#{ACTION}m,"
-SWAP = "#{ACTION}w,"
-LAYOUT = "#{ACTION}z,"
-GROUP = "#{ACTION}g,"
-MENU = ACTION
-PROGRAM = ACTION
-
-
-# Shortcut key sequences and their associated logic.
-SHORTCUTS = {
- # focus previous view
- "#{FOCUS}comma" => lambda do
- cycle_view :left
- end,
-
- # focus next view
- "#{FOCUS}period" => lambda do
- cycle_view :right
- end,
-
- # focus previous area
- "#{FOCUS}#{LEFT}" => lambda do
- Wmii.current_view.ctl = 'select prev'
- end,
-
- # focus next area
- "#{FOCUS}#{RIGHT}" => lambda do
- Wmii.current_view.ctl = 'select next'
- end,
-
- # focus floating area
- "#{FOCUS}space" => lambda do
- Wmii.current_view.ctl = 'select toggle'
- end,
-
- # focus previous client
- "#{FOCUS}#{UP}" => lambda do
- Wmii.current_area.ctl = 'select prev'
- end,
-
- # focus next client
- "#{FOCUS}#{DOWN}" => lambda do
- Wmii.current_area.ctl = 'select next'
- end,
-
-
- # apply equal spacing layout to currently focused column
- "#{LAYOUT}w" => lambda do
- Wmii.current_area.mode = 'default'
- end,
-
- # apply stacked layout to currently focused column
- "#{LAYOUT}v" => lambda do
- Wmii.current_area.mode = 'stack'
- end,
-
- # apply maximized layout to currently focused column
- "#{LAYOUT}m" => lambda do
- Wmii.current_area.mode = 'max'
- end,
-
- # maximize the floating area's focused client
- "#{LAYOUT}z" => lambda do
- Wmii.current_view[0].sel.geom = '0 0 east south'
- end,
-
-
- # apply tiling layout to the currently focused view
- "#{LAYOUT}t" => lambda do
- Wmii.current_view.tile!
- end,
-
- # apply gridding layout to the currently focused view
- "#{LAYOUT}g" => lambda do
- Wmii.current_view.grid!
- end,
-
-
- # add/remove the currently focused client from the selection
- "#{GROUP}g" => lambda do
- Wmii.current_client.invert_selection!
- end,
-
- # add all clients in the currently focused view to the selection
- "#{GROUP}a" => lambda do
- Wmii.current_view.select!
- end,
-
- # invert the selection in the currently focused view
- "#{GROUP}i" => lambda do
- Wmii.current_view.invert_selection!
- end,
-
- # nullify the selection
- "#{GROUP}n" => lambda do
- Wmii.select_none!
- end,
-
-
- # launch an internal action by choosing from a menu
- "#{MENU}i" => lambda do
- action = show_menu(ACTION_MENU)
- system(action << '&') unless action.empty?
- end,
-
- # launch an external program by choosing from a menu
- "#{MENU}e" => lambda do
- program = show_menu(PROGRAM_MENU)
- system(program << '&') unless program.empty?
- end,
-
- # focus any view by choosing from a menu
- "#{MENU}Shift-v" => lambda do
- Wmii.focus_view(show_menu(Wmii.tags))
- end,
-
- "#{MENU}a" => lambda do
- focus_client_from_menu
- end,
-
-
- "#{PROGRAM}x" => lambda do
- system 'terminal &'
- end,
-
- "#{PROGRAM}k" => lambda do
- system 'epiphany &'
- end,
-
- "#{PROGRAM}j" => lambda do
- system 'nautilus --no-desktop &'
- end,
-
-
- "#{SEND}#{LEFT}" => lambda do
- Wmii.selected_clients.each do |c|
- c.ctl = 'sendto prev'
- end
- end,
-
- "#{SEND}#{RIGHT}" => lambda do
- Wmii.selected_clients.each do |c|
- c.ctl = 'sendto next'
- end
- end,
-
- "#{SEND}space" => lambda do
- Wmii.selected_clients.each do |c|
- c.ctl = 'sendto toggle'
- end
- end,
-
- "#{SEND}Delete" => lambda do
- Wmii.selected_clients.each do |c|
- c.ctl = 'kill'
- end
- end,
-
- "#{SEND}t" => lambda do
- change_tag_from_menu
- end,
-
- # remove currently focused view from current selection's tags
- "#{SEND}Shift-minus" => lambda do
- curTag = Wmii.current_view.name
-
- Wmii.selected_clients.each do |c|
- c.untag! curTag
- end
- end,
-
- "#{ACTION}b" => lambda do
- toggle_temp_view
- end,
-
- # wmii-2 style detaching
- "#{ACTION}d" => lambda do
- detach_selection
- end,
-
- # wmii-2 style detaching
- "#{ACTION}Shift-d" => lambda do
- attach_last_client
- end,
-
- # toggle maximizing the currently focused client to full screen
- "#{SEND}m" => lambda do
- SHORTCUTS["#{SEND}space"].call
- SHORTCUTS["#{LAYOUT}z"].call
- end,
-
- # swap the currently focused client with the one to its left
- "#{SWAP}#{LEFT}" => lambda do
- Wmii.current_client.ctl = 'swap prev'
- end,
-
- # swap the currently focused client with the one to its right
- "#{SWAP}#{RIGHT}" => lambda do
- Wmii.current_client.ctl = 'swap next'
- end,
-
- # swap the currently focused client with the one below it
- "#{SWAP}#{DOWN}" => lambda do
- Wmii.current_client.ctl = 'swap down'
- end,
-
- # swap the currently focused client with the one above it
- "#{SWAP}#{UP}" => lambda do
- Wmii.current_client.ctl = 'swap up'
- end,
-}
-
-10.times do |i|
- k = (i - 1) % 10 # associate '1' with the leftmost label, instead of '0'
-
- # focus _i_th view
- SHORTCUTS["#{FOCUS}#{i}"] = lambda do
- Wmii.focus_view Wmii.tags[k] || i
- end
-
- # send selection to _i_th view
- SHORTCUTS["#{SEND}#{i}"] = lambda do
- Wmii.selected_clients.each do |c|
- c.tags = Wmii.tags[k] || i
- end
- end
-
- # send selection to _i_th area
- SHORTCUTS["#{SEND}Shift-#{i}"] = lambda do
- dstCol = Wmii.current_view[i]
-
- Wmii.selected_clients.each do |c|
- dstCol.insert! c
- end
- end
-
- # apply grid layout with _i_ clients per column
- SHORTCUTS["#{LAYOUT}#{i}"] = lambda do
- Wmii.current_view.grid! i
- end
-
- # add _i_th view to current selection's tags
- SHORTCUTS["#{SEND}equal,#{i}"] =
- SHORTCUTS["#{SEND}Shift-equal,#{i}"] = lambda do
- Wmii.selected_clients.each do |c|
- c.tag! Wmii.tags[k] || i
- end
- end
-
- # remove _i_th view from current selection's tags
- SHORTCUTS["#{SEND}minus,#{i}"] = lambda do
- Wmii.selected_clients.each do |c|
- c.untag! Wmii.tags[k] || i
- end
- end
-end
-
-# jump to view whose name begins with the pressed key
-('a'..'z').each do |char|
- SHORTCUTS["#{MENU}v,#{char}"] = lambda do
- choices = Wmii.tags
- choices.delete Wmii.current_view.name
-
- if view = choices.select {|t| t =~ /^#{char}/i}.first
- Wmii.focus_view view
- end
- end
-end
-
-FS.def.grabmod = MODKEY
-FS.def.keys = SHORTCUTS.keys.join("\n")
-
-
-## status bar
-
-Thread.new do
- sb = Ixp::Node.new('/bar/status', true)
- sb.colors = ENV['WMII_NORMCOLORS']
-
- loop do
- cpuLoad = `uptime`.scan(/\d+\.\d+/).join(' ')
- diskSpace = `df -h ~`.split[-3..-1].join(' ')
-
- 5.times do
- sb.data = "#{Time.now.to_s} | #{cpuLoad} | #{diskSpace}"
- sleep 1
- end
- end
-end
-
-
-## WM event loop
+LOG = Logger.new(__FILE__ + '.log', 5)
begin
- IO.popen('wmiir read /event') do |io|
- while event = io.readline.chomp
- type, arg = event.split($;, 2)
-
- case type
- when 'Start'
- exit if arg == 'wmiirc'
-
- when 'BarClick'
- viewId, mouseBtn = arg.split
-
- case mouseBtn.to_i
- when PRIMARY
- Wmii.focus_view viewId
-
- when MIDDLE
- # add view to selection's tags
- Wmii.selected_clients.each do |c|
- c.tag! viewId
- end
-
- when SECONDARY
- # remove view from selection's tags
- Wmii.selected_clients.each do |c|
- c.untag! viewId
- end
- end
+ load File.join(File.dirname(__FILE__), 'wmiirc-config.rb')
- when 'ClientClick'
- clientId, mouseBtn = arg.split
+rescue => e
+ LOG.error e
- case mouseBtn.to_i
- when MIDDLE, SECONDARY
- Wmii::Client.new("/client/#{clientId}").invert_selection!
- end
+ LOG.info "#{__FILE__}: resuming from error"
+ retry
- when 'Key'
- SHORTCUTS[arg].call
- end
- end
- end
-rescue EOFError
- exit 1 # wmiiwm has quit
+rescue Exception => e
+ LOG.fatal e
end
diff --git a/wmiirc-config.rb b/wmiirc-config.rb
@@ -0,0 +1,446 @@
+# Ruby-based configuration file for wmii.
+=begin
+ Copyright 2006 Suraj N. Kurapati
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+=end
+
+$: << File.dirname(__FILE__)
+require 'rc'
+
+
+## WM startup
+
+FS = Wmii.fs
+FS.event = "Start wmiirc\n" # terminate existing wmiirc processes
+
+
+## executable programs
+
+# names of external programs
+PROGRAM_MENU = find_programs( ENV['PATH'].squeeze(':').split(':') )
+
+# names of internal actions
+ACTION_MENU = find_programs('~/dry/apps/wmii/etc/wmii-3', File.dirname(__FILE__))
+
+
+## UI configuration
+
+ENV['WMII_FONT'] = '-misc-fixed-medium-r-normal--18-120-100-100-c-90-iso10646-1'
+ENV['WMII_SELCOLORS']='#ffffff #285577 #4c7899'
+ENV['WMII_NORMCOLORS']='#222222 #eeeeee #666666'
+
+system %{xsetroot -solid '#333333'}
+
+
+## WM configuration
+
+FS.def.border = 2
+
+FS.def.font = ENV['WMII_FONT']
+FS.def.selcolors = ENV['WMII_SELCOLORS']
+FS.def.normcolors = ENV['WMII_NORMCOLORS']
+
+FS.def.colmode = 'default'
+FS.def.colwidth = 0
+
+FS.def.rules = <<EOS
+/jEdit.*/ -> code
+/Buddy List.*/ -> chat
+/XChat.*/ -> chat
+/.*thunderbird.*/ -> mail
+/Gimp.*/ -> gimp
+/QEMU.*/ -> ~
+/MPlayer.*/ -> ~
+/xconsole.*/ -> ~
+/alsamixer.*/ -> ~
+/.*/ -> !
+/.*/ -> 1
+EOS
+
+
+## key configuration
+
+# Symbolic name of modifier key.
+MODKEY = 'Mod1'
+
+# Symbolic name for up direction key.
+UP = 't'
+
+# Symbolic name for down direction key.
+DOWN = 'n'
+
+# Symbolic name for left direction key.
+LEFT = 'h'
+
+# Symbolic name for right direction key.
+RIGHT = 's'
+
+# Keycode for the primary mouse button.
+PRIMARY = 1
+
+# Keycode for the middle mouse button.
+MIDDLE = 2
+
+# Keycode for the secondary mouse button.
+SECONDARY = 3
+
+
+# Initial key sequence used by all shortcuts.
+ACTION = "#{MODKEY}-Control-"
+
+FOCUS = ACTION
+SEND = "#{ACTION}m,"
+SWAP = "#{ACTION}w,"
+LAYOUT = "#{ACTION}z,"
+GROUP = "#{ACTION}g,"
+MENU = ACTION
+PROGRAM = ACTION
+
+
+# Shortcut key sequences and their associated logic.
+SHORTCUTS = {
+ # focus previous view
+ "#{FOCUS}comma" => lambda do
+ cycle_view :left
+ end,
+
+ # focus next view
+ "#{FOCUS}period" => lambda do
+ cycle_view :right
+ end,
+
+ # focus previous area
+ "#{FOCUS}#{LEFT}" => lambda do
+ Wmii.current_view.ctl = 'select prev'
+ end,
+
+ # focus next area
+ "#{FOCUS}#{RIGHT}" => lambda do
+ Wmii.current_view.ctl = 'select next'
+ end,
+
+ # focus floating area
+ "#{FOCUS}space" => lambda do
+ Wmii.current_view.ctl = 'select toggle'
+ end,
+
+ # focus previous client
+ "#{FOCUS}#{UP}" => lambda do
+ Wmii.current_area.ctl = 'select prev'
+ end,
+
+ # focus next client
+ "#{FOCUS}#{DOWN}" => lambda do
+ Wmii.current_area.ctl = 'select next'
+ end,
+
+
+ # apply equal spacing layout to currently focused column
+ "#{LAYOUT}w" => lambda do
+ Wmii.current_area.mode = 'default'
+ end,
+
+ # apply stacked layout to currently focused column
+ "#{LAYOUT}v" => lambda do
+ Wmii.current_area.mode = 'stack'
+ end,
+
+ # apply maximized layout to currently focused column
+ "#{LAYOUT}m" => lambda do
+ Wmii.current_area.mode = 'max'
+ end,
+
+ # maximize the floating area's focused client
+ "#{LAYOUT}z" => lambda do
+ Wmii.current_view[0].sel.geom = '0 0 east south'
+ end,
+
+
+ # apply tiling layout to the currently focused view
+ "#{LAYOUT}t" => lambda do
+ Wmii.current_view.tile!
+ end,
+
+ # apply gridding layout to the currently focused view
+ "#{LAYOUT}g" => lambda do
+ Wmii.current_view.grid!
+ end,
+
+
+ # add/remove the currently focused client from the selection
+ "#{GROUP}g" => lambda do
+ Wmii.current_client.invert_selection!
+ end,
+
+ # add all clients in the currently focused view to the selection
+ "#{GROUP}a" => lambda do
+ Wmii.current_view.select!
+ end,
+
+ # invert the selection in the currently focused view
+ "#{GROUP}i" => lambda do
+ Wmii.current_view.invert_selection!
+ end,
+
+ # nullify the selection
+ "#{GROUP}n" => lambda do
+ Wmii.select_none!
+ end,
+
+
+ # launch an internal action by choosing from a menu
+ "#{MENU}i" => lambda do
+ action = show_menu(ACTION_MENU)
+ system(action << '&') unless action.empty?
+ end,
+
+ # launch an external program by choosing from a menu
+ "#{MENU}e" => lambda do
+ program = show_menu(PROGRAM_MENU)
+ system(program << '&') unless program.empty?
+ end,
+
+ # focus any view by choosing from a menu
+ "#{MENU}Shift-v" => lambda do
+ Wmii.focus_view(show_menu(Wmii.tags))
+ end,
+
+ "#{MENU}a" => lambda do
+ focus_client_from_menu
+ end,
+
+
+ "#{PROGRAM}x" => lambda do
+ system 'terminal &'
+ end,
+
+ "#{PROGRAM}k" => lambda do
+ system 'epiphany &'
+ end,
+
+ "#{PROGRAM}j" => lambda do
+ system 'nautilus --no-desktop &'
+ end,
+
+
+ "#{SEND}#{LEFT}" => lambda do
+ Wmii.selected_clients.each do |c|
+ c.ctl = 'sendto prev'
+ end
+ end,
+
+ "#{SEND}#{RIGHT}" => lambda do
+ Wmii.selected_clients.each do |c|
+ c.ctl = 'sendto next'
+ end
+ end,
+
+ "#{SEND}space" => lambda do
+ Wmii.selected_clients.each do |c|
+ c.ctl = 'sendto toggle'
+ end
+ end,
+
+ "#{SEND}Delete" => lambda do
+ Wmii.selected_clients.each do |c|
+ c.ctl = 'kill'
+ end
+ end,
+
+ "#{SEND}t" => lambda do
+ change_tag_from_menu
+ end,
+
+ # remove currently focused view from current selection's tags
+ "#{SEND}Shift-minus" => lambda do
+ curTag = Wmii.current_view.name
+
+ Wmii.selected_clients.each do |c|
+ c.untag! curTag
+ end
+ end,
+
+ "#{ACTION}b" => lambda do
+ toggle_temp_view
+ end,
+
+ # wmii-2 style detaching
+ "#{ACTION}d" => lambda do
+ detach_selection
+ end,
+
+ # wmii-2 style detaching
+ "#{ACTION}Shift-d" => lambda do
+ attach_last_client
+ end,
+
+ # toggle maximizing the currently focused client to full screen
+ "#{SEND}m" => lambda do
+ SHORTCUTS["#{SEND}space"].call
+ SHORTCUTS["#{LAYOUT}z"].call
+ end,
+
+ # swap the currently focused client with the one to its left
+ "#{SWAP}#{LEFT}" => lambda do
+ Wmii.current_client.ctl = 'swap prev'
+ end,
+
+ # swap the currently focused client with the one to its right
+ "#{SWAP}#{RIGHT}" => lambda do
+ Wmii.current_client.ctl = 'swap next'
+ end,
+
+ # swap the currently focused client with the one below it
+ "#{SWAP}#{DOWN}" => lambda do
+ Wmii.current_client.ctl = 'swap down'
+ end,
+
+ # swap the currently focused client with the one above it
+ "#{SWAP}#{UP}" => lambda do
+ Wmii.current_client.ctl = 'swap up'
+ end,
+}
+
+10.times do |i|
+ k = (i - 1) % 10 # associate '1' with the leftmost label, instead of '0'
+
+ # focus _i_th view
+ SHORTCUTS["#{FOCUS}#{i}"] = lambda do
+ Wmii.focus_view Wmii.tags[k] || i
+ end
+
+ # send selection to _i_th view
+ SHORTCUTS["#{SEND}#{i}"] = lambda do
+ Wmii.selected_clients.each do |c|
+ c.tags = Wmii.tags[k] || i
+ end
+ end
+
+ # send selection to _i_th area
+ SHORTCUTS["#{SEND}Shift-#{i}"] = lambda do
+ dstCol = Wmii.current_view[i]
+
+ Wmii.selected_clients.each do |c|
+ dstCol.insert! c
+ end
+ end
+
+ # apply grid layout with _i_ clients per column
+ SHORTCUTS["#{LAYOUT}#{i}"] = lambda do
+ Wmii.current_view.grid! i
+ end
+
+ # add _i_th view to current selection's tags
+ SHORTCUTS["#{SEND}equal,#{i}"] =
+ SHORTCUTS["#{SEND}Shift-equal,#{i}"] = lambda do
+ Wmii.selected_clients.each do |c|
+ c.tag! Wmii.tags[k] || i
+ end
+ end
+
+ # remove _i_th view from current selection's tags
+ SHORTCUTS["#{SEND}minus,#{i}"] = lambda do
+ Wmii.selected_clients.each do |c|
+ c.untag! Wmii.tags[k] || i
+ end
+ end
+end
+
+# jump to view whose name begins with the pressed key
+('a'..'z').each do |char|
+ SHORTCUTS["#{MENU}v,#{char}"] = lambda do
+ choices = Wmii.tags
+ choices.delete Wmii.current_view.name
+
+ if view = choices.select {|t| t =~ /^#{char}/i}.first
+ Wmii.focus_view view
+ end
+ end
+end
+
+FS.def.grabmod = MODKEY
+FS.def.keys = SHORTCUTS.keys.join("\n")
+
+
+## status bar
+
+Thread.new do
+ sb = Ixp::Node.new('/bar/status', true)
+ sb.colors = ENV['WMII_NORMCOLORS']
+
+ loop do
+ cpuLoad = `uptime`.scan(/\d+\.\d+/).join(' ')
+ diskSpace = `df -h ~`.split[-3..-1].join(' ')
+
+ 5.times do
+ sb.data = "#{Time.now.to_s} | #{cpuLoad} | #{diskSpace}"
+ sleep 1
+ end
+ end
+end
+
+
+## WM event loop
+
+begin
+ IO.popen('wmiir read /event') do |io|
+ while event = io.readline.chomp
+ type, arg = event.split($;, 2)
+
+ case type
+ when 'Start'
+ if arg == 'wmiirc'
+ LOG.info "Exiting because another wmiirc has started."
+ exit
+ end
+
+ when 'BarClick'
+ viewId, mouseBtn = arg.split
+
+ case mouseBtn.to_i
+ when PRIMARY
+ Wmii.focus_view viewId
+
+ when MIDDLE
+ # add view to selection's tags
+ Wmii.selected_clients.each do |c|
+ c.tag! viewId
+ end
+
+ when SECONDARY
+ # remove view from selection's tags
+ Wmii.selected_clients.each do |c|
+ c.untag! viewId
+ end
+ end
+
+ when 'ClientClick'
+ clientId, mouseBtn = arg.split
+
+ case mouseBtn.to_i
+ when MIDDLE, SECONDARY
+ Wmii::Client.new("/client/#{clientId}").invert_selection!
+ end
+
+ when 'Key'
+ SHORTCUTS[arg].call
+ end
+ end
+ end
+rescue EOFError
+ LOG.fatal "wmiiwm has quit"
+ exit 1
+end