wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit b26fc42fedb54b8f6b2900e72f7af833644fe86b
parent 6afe9e626240fd29aa8d54acc97d3ae898439bde
Author: Kris Maglione <jg@suckless.org>
Date:   Sat, 10 Oct 2009 14:57:00 -0400

Sync ruby wmiirc.

Diffstat:
alternative_wmiircs/ruby/LICENSE | 25-------------------------
alternative_wmiircs/ruby/README | 21+++++++++++++++++++--
alternative_wmiircs/ruby/config.rb | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
alternative_wmiircs/ruby/config.yaml | 589+++++++++++++------------------------------------------------------------------
alternative_wmiircs/ruby/wmiirc | 15++++++++++-----
5 files changed, 261 insertions(+), 534 deletions(-)

diff --git a/alternative_wmiircs/ruby/LICENSE b/alternative_wmiircs/ruby/LICENSE @@ -19,28 +19,3 @@ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -Portions of this software originate from wmii <http://wmii.suckless.org>: - -(the MIT license) - -© 2006-2007 Kris Maglione <fbsdaemon@gmail.com> -© 2003-2006 Anselm R. Garbe <garbeam at suckless dot org> - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/alternative_wmiircs/ruby/README b/alternative_wmiircs/ruby/README @@ -54,13 +54,26 @@ Installation: mv ~/.wmii-hg ~/.wmii-hg.backup git clone git://github.com/sunaku/wmiirc.git ~/.wmii-hg + # choose + cd ~/.wmii-hg + git checkout --track -b CHOICE origin/CHOICE # choices are: + + +--------+------------------------------------------------+ + | CHOICE | DESCRIPTION | + +--------+------------------------------------------------+ + | dvorak | sunaku's personal configuration; DSK friendly! | + | qwerty | QWERTY port of sunaku's personal configuration | + | strict | port of the default wmiirc shipped with wmii | + | master | barebones template for starting from scratch | + +--------+------------------------------------------------+ + # run ~/.wmii-hg/wmiirc Documentation: # see list of all key bindings - grep 'Mod.*#' ~/.wmii-hg/config.yaml + egrep '^ +\$\{\w+\}' ~/.wmii-hg/config.yaml # read the configuration file less ~/.wmii-hg/config.yaml @@ -71,7 +84,11 @@ Configuration: Run ~/.wmii-hg/wmiirc to apply your changes. +Contribution: + + Fork this project on GitHub and send pull requests. + Questions: - Send me an e-mail; see LICENSE for my address. + Send me an e-mail (see LICENSE for my address). diff --git a/alternative_wmiircs/ruby/config.rb b/alternative_wmiircs/ruby/config.rb @@ -44,7 +44,7 @@ ACTIONS = Handler.new KEYS = Handler.new ## -# When a block is given, registers a handler +# If a block is given, registers a handler # for the given event and returns the handler. # # Otherwise, executes all handlers for the given event. @@ -106,7 +106,10 @@ end # Instruction on what the user should enter or choose. # def key_menu choices, prompt = nil - words = %w[dmenu -b -fn].push(CONFIG['display']['font']) + words = ['dmenu', '-fn', CONFIG['display']['font']] + + # show menu at the same location as the status bar + words << '-b' if CONFIG['display']['bar'] == 'bottom' words.concat %w[-nf -nb -sf -sb].zip( [ @@ -145,11 +148,11 @@ end # The choice that should be initially selected. # # If this choice is not included in the list -# of cohices, then this item will be made +# of choices, then this item will be made # into a makeshift title-bar for the menu. # def click_menu choices, initial = nil - words = %w[wmii9menu] + words = ['wmii9menu'] if initial words << '-i' @@ -170,6 +173,36 @@ def click_menu choices, initial = nil end ## +# Shows a key_menu() containing the given +# clients and returns the chosen client. +# +# If nothing was chosen, then nil is returned. +# +# ==== Parameters +# +# [prompt] +# Instruction on what the user should enter or choose. +# +# [clients] +# List of clients to present as choices to the user. +# +# If this parameter is not specified, +# its default value will be a list of +# all currently available clients. +# +def client_menu prompt = nil, clients = Rumai.clients + choices = [] + + clients.each_with_index do |c, i| + choices << "%d. [%s] %s" % [i, c[:tags].read, c[:label].read.downcase] + end + + if target = key_menu(choices, prompt) + clients[target.scan(/\d+/).first.to_i] + end +end + +## # Returns the basenames of executable files present in the given directories. # def find_programs *dirs @@ -269,7 +302,7 @@ def load_config config_file # applied. but a "bad command" error is raised nevertheless! # warn e.inspect - warn e.backtrace + warn e.backtrace.join("\n") end launch 'xsetroot', '-solid', CONFIG['display']['background'] @@ -343,7 +376,7 @@ def load_config config_file @status_button_by_name.each_value {|b| b.refresh } - end.call + end ## # Returns the status button associated with the given name. @@ -400,14 +433,106 @@ def load_config config_file end # control + action 'reload' do + # reload this wmii configuration + reload_config + end + + action 'rehash' do + # scan for available programs and actions + @programs = find_programs(ENV['PATH'].squeeze(':').split(':')) + end + + # kill all currently open clients + action 'clear' do + # firefox's restore session feature does not + # work unless the whole process is killed. + system 'killall firefox firefox-bin thunderbird thunderbird-bin' + + # gnome-panel refuses to die by any other means + system 'killall -s TERM gnome-panel' + + Thread.pass until clients.each do |c| + begin + c.focus # XXX: client must be on current view in order to be killed + c.kill + rescue + # ignore + end + end.empty? + end + + # kill the window manager only; do not touch the clients! + action 'kill' do + fs.ctl.write 'quit' + end + + # kill both clients and window manager + action 'quit' do + action 'clear' + action 'kill' + end + + event 'Unresponsive' do |client_id| + client = Client.new(client_id) + + IO.popen('xmessage -nearmouse -file - -buttons Kill,Wait -print', 'w+') do |f| + f.puts 'The following client is not responding.', '' + f.puts client.inspect + f.puts client.label.read + + f.puts '', 'What would you like to do?' + f.close_write + + if f.read.chomp == 'Kill' + client.slay + end + end + end + + event 'Notice' do |*argv| + unless defined? @notice_mutex + require 'thread' + @notice_mutex = Mutex.new + end + + Thread.new do + # prevent notices from overwriting each other + @notice_mutex.synchronize do + button = fs.rbar['!notice'] + button.create unless button.exist? + + # display the notice + message = argv.join(' ') + + LOG.info message # also log it in case the user is AFK + button.write "#{CONFIG['display']['color']['notice']} #{message}" + + # clear the notice + sleep [1, CONFIG['display']['notice'].to_i].max + button.remove + end + end + end + %w[key action event].each do |param| - CONFIG['control'][param].each do |name, code| - eval "#{param}(#{name.inspect}) {|*argv| #{code} }", - TOPLEVEL_BINDING, "#{config_file}:control:#{param}:#{name}" + if settings = CONFIG['control'][param] + settings.each do |name, code| + if param == 'key' + # expand ${...} expressions in shortcut key sequences + name = name.gsub(/\$\{(.+?)\}/) { CONFIG['control'][$1] } + end + + eval "#{param}(#{name.inspect}) {|*argv| #{code} }", + TOPLEVEL_BINDING, "#{config_file}:control:#{param}:#{name}" + end end end # script + action 'status' + action 'rehash' + eval CONFIG['script']['after'].to_s, TOPLEVEL_BINDING, "#{config_file}:script:after" @@ -418,5 +543,5 @@ end # def reload_config LOG.info 'reload' - launch $0 + exec $0 end diff --git a/alternative_wmiircs/ruby/config.yaml b/alternative_wmiircs/ruby/config.yaml @@ -12,6 +12,16 @@ ## +# Program preferences. +# +program: + terminal: urxvt + browser: firefox + editor: mousepad + filer: thunar + + +## # Appearance settings. # display: @@ -26,7 +36,7 @@ display: ## # The font to use in all text drawn by wmii. # - font: -*-fixed-medium-r-*-*-18-*-*-*-*-*-*-* + font: -*-fixed-medium-r-*-*-13-*-*-*-*-*-*-* ## # Thickness of client border (measured in pixels). @@ -48,11 +58,11 @@ display: # http://wmii.suckless.org/scripts_n_snips/themes # color: - normal: "#c0c0c0 #0a0a0a #202020" - focus: "#ffffff #285577 #4c7899" - error: "#8a1f11 #FBE3E4 #FBC2C4" # from http://www.blueprintcss.org - notice: "#514721 #FFF6BF #FFD324" # from http://www.blueprintcss.org - success: "#264409 #E6EFC2 #C6D880" # from http://www.blueprintcss.org + normal: "#000000 #c1c48b #81654f" + focus: "#000000 #81654f #000000" + error: "#000000 #81654f #000000" + notice: "#000000 #a1956d #413328" + success: "#000000 #c1c48b #81654f" ## # Color of desktop background. @@ -69,7 +79,7 @@ display: mode: default rule: | /gimp/ -> 17+83+41 - /.*/ -> 50+50 + /.*/ -> 62+38 # Golden Ratio ## # Mapping of clients to views they must appear on. @@ -80,10 +90,7 @@ display: # Processing stops after the first matching mapping is applied. # client: - - /\b(xconsole|alsamixer|XMMS|Sonata)\b/ : 1 - - /^pidgin:|:WeeChat\b/ : chat - - /\b(Liferea|GMail|Thunderbird)\b/ : mail - - /:(Firefox|Shiretoko):.*\bRestore\b.*\bSession\b/ : web + - /MPlayer|VLC/ : ~ ## # Self-refreshing buttons on the status bar. @@ -103,42 +110,6 @@ display: # bar reflects the vertical order in which they are defined below. # status: - - music: - refresh: 15 - content: | - unless defined? @music - require 'rubygems' - gem 'librmpd', '~> 0.1' - require 'librmpd' - - @music = MPD.new - end - - unless @music.connected? - @music.connect - end - - music_state = (@music.stopped? || @music.paused?) ? '(-)' : '(>)' - - if song = @music.current_song - artist = song.artist - title = song.title || (f = song.file and File.basename(f)) - song_name = [artist, title].compact.join(': ') - end - - [music_state, song_name].compact - - - volume: - refresh: 60 - content: | - ['volume', `amixer get Master`.scan(/\d+%/).first] - - - disk_space: - refresh: 600 # 10 minutes - content: | - free, used, path = `df -h ~`.split.last(3) - [path, used, 'used', free, 'free'] - - system_load: refresh: 10 content: | @@ -169,373 +140,153 @@ control: grab: Mod1 ## + # Prefix for all shortcuts. + # + mod: Mod1 + + ## + # Direction keys. + # + up: k + down: j + left: h + right: l + + ## # Key bindings. # # <key sequence>: <Ruby code to execute> # + # A key sequence may contain ${...} expressions which + # are replaced with the value corresponding to '...' + # in the 'control' section of this configuration file. + # + # For example, if the 'control' section of + # this configuration file appeared like this: + # + # control: + # foo: Mod4 + # bar: y + # + # and the following key sequence was used: + # + # ${foo}-${bar},${bar} + # + # then after ${...} expression replacement, + # that key sequence would appear like this: + # + # Mod4-y,y + # key: #--------------------------------------------------------------------------- # focus #--------------------------------------------------------------------------- - Mod1-Control-t: | # focus above client + ${mod}-${up}: | # focus above client curr_view.select(:up) rescue nil - Mod1-Control-n: | # focus below client + ${mod}-${down}: | # focus below client curr_view.select(:down) rescue nil - Mod1-Control-h: | # focus left client + ${mod}-${left}: | # focus left client curr_view.select(:left) rescue nil - Mod1-Control-s: | # focus right client + ${mod}-${right}: | # focus right client curr_view.select(:right) rescue nil - Mod1-Control-space: | # focus floating area (toggle) + ${mod}-space: | # focus floating area (toggle) curr_view.select(:toggle) - Mod1-Control-comma: | # focus previous view - prev_view.focus - - Mod1-Control-period: | # focus next view - next_view.focus - # focus the view whose index or name equals the pressed number - Mod1-Control-1: focus_view( tags[0] || 1 ) - Mod1-Control-2: focus_view( tags[1] || 2 ) - Mod1-Control-3: focus_view( tags[2] || 3 ) - Mod1-Control-4: focus_view( tags[3] || 4 ) - Mod1-Control-5: focus_view( tags[4] || 5 ) - Mod1-Control-6: focus_view( tags[5] || 6 ) - Mod1-Control-7: focus_view( tags[6] || 7 ) - Mod1-Control-8: focus_view( tags[7] || 8 ) - Mod1-Control-9: focus_view( tags[8] || 9 ) - Mod1-Control-0: focus_view( tags[9] || 10 ) - - # focus the view whose name begins with the pressed alphabet - Mod1-Control-v,a: t = tags.grep(/^a/i).first and focus_view(t) - Mod1-Control-v,b: t = tags.grep(/^b/i).first and focus_view(t) - Mod1-Control-v,c: t = tags.grep(/^c/i).first and focus_view(t) - Mod1-Control-v,d: t = tags.grep(/^d/i).first and focus_view(t) - Mod1-Control-v,e: t = tags.grep(/^e/i).first and focus_view(t) - Mod1-Control-v,f: t = tags.grep(/^f/i).first and focus_view(t) - Mod1-Control-v,g: t = tags.grep(/^g/i).first and focus_view(t) - Mod1-Control-v,h: t = tags.grep(/^h/i).first and focus_view(t) - Mod1-Control-v,i: t = tags.grep(/^i/i).first and focus_view(t) - Mod1-Control-v,j: t = tags.grep(/^j/i).first and focus_view(t) - Mod1-Control-v,k: t = tags.grep(/^k/i).first and focus_view(t) - Mod1-Control-v,l: t = tags.grep(/^l/i).first and focus_view(t) - Mod1-Control-v,m: t = tags.grep(/^m/i).first and focus_view(t) - Mod1-Control-v,n: t = tags.grep(/^n/i).first and focus_view(t) - Mod1-Control-v,o: t = tags.grep(/^o/i).first and focus_view(t) - Mod1-Control-v,p: t = tags.grep(/^p/i).first and focus_view(t) - Mod1-Control-v,q: t = tags.grep(/^q/i).first and focus_view(t) - Mod1-Control-v,r: t = tags.grep(/^r/i).first and focus_view(t) - Mod1-Control-v,s: t = tags.grep(/^s/i).first and focus_view(t) - Mod1-Control-v,t: t = tags.grep(/^t/i).first and focus_view(t) - Mod1-Control-v,u: t = tags.grep(/^u/i).first and focus_view(t) - Mod1-Control-v,v: t = tags.grep(/^v/i).first and focus_view(t) - Mod1-Control-v,w: t = tags.grep(/^w/i).first and focus_view(t) - Mod1-Control-v,x: t = tags.grep(/^x/i).first and focus_view(t) - Mod1-Control-v,y: t = tags.grep(/^y/i).first and focus_view(t) - Mod1-Control-v,z: t = tags.grep(/^z/i).first and focus_view(t) + ${mod}-1: focus_view tags[0] || 1 + ${mod}-2: focus_view tags[1] || 2 + ${mod}-3: focus_view tags[2] || 3 + ${mod}-4: focus_view tags[3] || 4 + ${mod}-5: focus_view tags[4] || 5 + ${mod}-6: focus_view tags[5] || 6 + ${mod}-7: focus_view tags[6] || 7 + ${mod}-8: focus_view tags[7] || 8 + ${mod}-9: focus_view tags[8] || 9 + ${mod}-0: focus_view tags[9] || 10 #--------------------------------------------------------------------------- # move #--------------------------------------------------------------------------- - Mod1-Control-m,t: | # move grouping toward the top + ${mod}-Shift-${up}: | # move grouping toward the top grouping.each {|c| c.send(:up) rescue nil } - Mod1-Control-m,n: | # move grouping toward the bottom + ${mod}-Shift-${down}: | # move grouping toward the bottom grouping.each {|c| c.send(:down) rescue nil } - Mod1-Control-m,h: | # move grouping toward the left + ${mod}-Shift-${left}: | # move grouping toward the left grouping.each {|c| c.send(:left) rescue nil } - Mod1-Control-m,s: | # move grouping toward the right + ${mod}-Shift-${right}: | # move grouping toward the right grouping.each {|c| c.send(:right) rescue nil } - Mod1-Control-m,space: | # move grouping to floating area (toggle) + ${mod}-Shift-space: | # move grouping to floating area (toggle) grouping.each {|c| c.send(:toggle) rescue nil } - Mod1-Control-m,v: | # move grouping to chosen view - # - # Changes the tag (according to a menu choice) of - # each grouped client and returns the chosen tag. - # - # The +tag -tag idea is from Jonas Pfenniger: - # - # http://zimbatm.oree.ch/articles/2006/06/15/wmii-3-and-ruby - # - choices = tags.map {|t| [t, "+#{t}", "-#{t}"] }.flatten - - if target = key_menu(choices, 'tag as:') - grouping.each do |c| - case target - when /^\+/ then c.tag $' - when /^\-/ then c.untag $' - else c.tags = target - end - end - end - - Mod1-Control-m,Delete: | # kill all clients in grouping - grouping.each {|c| c.kill } - # move grouping to the view whose index or name equals the pressed number - Mod1-Control-m,1: grouping.each {|c| c.tags = tags[0] || 1 } - Mod1-Control-m,2: grouping.each {|c| c.tags = tags[1] || 2 } - Mod1-Control-m,3: grouping.each {|c| c.tags = tags[2] || 3 } - Mod1-Control-m,4: grouping.each {|c| c.tags = tags[3] || 4 } - Mod1-Control-m,5: grouping.each {|c| c.tags = tags[4] || 5 } - Mod1-Control-m,6: grouping.each {|c| c.tags = tags[5] || 6 } - Mod1-Control-m,7: grouping.each {|c| c.tags = tags[6] || 7 } - Mod1-Control-m,8: grouping.each {|c| c.tags = tags[7] || 8 } - Mod1-Control-m,9: grouping.each {|c| c.tags = tags[8] || 9 } - Mod1-Control-m,0: grouping.each {|c| c.tags = tags[9] || 10 } + ${mod}-Shift-1: grouping.each {|c| c.tags = tags[0] || 1 } + ${mod}-Shift-2: grouping.each {|c| c.tags = tags[1] || 2 } + ${mod}-Shift-3: grouping.each {|c| c.tags = tags[2] || 3 } + ${mod}-Shift-4: grouping.each {|c| c.tags = tags[3] || 4 } + ${mod}-Shift-5: grouping.each {|c| c.tags = tags[4] || 5 } + ${mod}-Shift-6: grouping.each {|c| c.tags = tags[5] || 6 } + ${mod}-Shift-7: grouping.each {|c| c.tags = tags[6] || 7 } + ${mod}-Shift-8: grouping.each {|c| c.tags = tags[7] || 8 } + ${mod}-Shift-9: grouping.each {|c| c.tags = tags[8] || 9 } + ${mod}-Shift-0: grouping.each {|c| c.tags = tags[9] || 10 } #--------------------------------------------------------------------------- - # swap + # client #--------------------------------------------------------------------------- - Mod1-Control-w,t: | # swap with above client - curr_client.swap(:up) rescue nil - - Mod1-Control-w,n: | # swap with below client - curr_client.swap(:down) rescue nil - - Mod1-Control-w,h: | # swap with left client - curr_client.swap(:left) rescue nil - - Mod1-Control-w,s: | # swap with right client - curr_client.swap(:right) rescue nil + ${mod}-f: | # zoom client to fullscreen (toggle) + curr_client.fullscreen! - # swap current client with the column whose index equals the pressed number - Mod1-Control-w,1: curr_client.swap 1 - Mod1-Control-w,2: curr_client.swap 2 - Mod1-Control-w,3: curr_client.swap 3 - Mod1-Control-w,4: curr_client.swap 4 - Mod1-Control-w,5: curr_client.swap 5 - Mod1-Control-w,6: curr_client.swap 6 - Mod1-Control-w,7: curr_client.swap 7 - Mod1-Control-w,8: curr_client.swap 8 - Mod1-Control-w,9: curr_client.swap 9 - Mod1-Control-w,0: curr_client.swap 10 + ${mod}-Shift-c: | # kill the current client + curr_client.kill #--------------------------------------------------------------------------- # column #--------------------------------------------------------------------------- - Mod1-Control-z,w: | # apply equal-spacing layout to current column - curr_area.layout = :default + ${mod}-d: | # apply equal-spacing layout to current column + curr_area.layout = 'default-max' - Mod1-Control-z,Shift-w: | # apply equal-spacing layout to all columns - curr_view.columns.each do |a| - a.layout = :default - end - - Mod1-Control-z,v: | # apply stacked layout to current column + ${mod}-v: | # apply stacked layout to current column curr_area.layout = 'stack-max' - Mod1-Control-z,Shift-v: | # apply stacked layout to all columns - curr_view.columns.each do |a| - a.layout = 'stack-max' - end - - Mod1-Control-z,m: | # apply maximized layout to current column + ${mod}-m: | # apply maximized layout to current column curr_area.layout = 'stack+max' - Mod1-Control-z,Shift-m: | # apply maximized layout to all columns - curr_view.columns.each do |a| - a.layout = 'stack+max' - end - - #--------------------------------------------------------------------------- - # group - #--------------------------------------------------------------------------- - - Mod1-Control-g,g: | # toggle current client from grouping - curr_client.group! - - Mod1-Control-g,c: | # add clients in current area to grouping - curr_area.group - - Mod1-Control-g,Shift-c: | # remove clients in current area from grouping - curr_area.ungroup - - Mod1-Control-g,f: | # add clients in floating area to grouping - Area.floating.group - - Mod1-Control-g,Shift-f: | # remove clients in floating area from grouping - Area.floating.ungroup - - Mod1-Control-g,m: | # add clients in managed areas to grouping - curr_view.managed_areas.each {|a| a.group } - - Mod1-Control-g,Shift-m: | # remove clients in managed areas from grouping - curr_view.managed_areas.each {|a| a.ungroup } - - Mod1-Control-g,v: | # add clients in current view to grouping - curr_view.group - - Mod1-Control-g,Shift-v: | # remove clients in current view from grouping - curr_view.ungroup - - Mod1-Control-g,i: | # invert the grouping in the current view - curr_view.group! - - Mod1-Control-g,Shift-i: | # invert the grouping in all views - Rumai.group! - - Mod1-Control-g,n: | # remove all clients everywhere from grouping - Rumai.ungroup - - #--------------------------------------------------------------------------- - # detach - #--------------------------------------------------------------------------- - - Mod1-Control-d: | # detach grouping from current view - grouping.each do |c| - c.with_tags do - delete curr_tag - push DETACHED_TAG - end - end - - Mod1-Control-Shift-d: | # attach most recently detached client - v = View.new DETACHED_TAG - - if v.exist? and c = v.clients.last - c.with_tags do - delete DETACHED_TAG - push curr_tag - end - end - - #--------------------------------------------------------------------------- - # zoom - #--------------------------------------------------------------------------- - - Mod1-Control-f: | # zoom client to fullscreen (toggle) - curr_client.fullscreen! - - Mod1-Control-b: | # copy grouping to temporary view - clients = grouping - - unless clients.empty? - # determine new view - if curr_tag =~ ZOOMED_SUFFIX - src, num = $`, $1.to_i - dst = "#{src}~#{num+1}" - else - dst = "#{curr_tag}~1" - end - - # add clients to new view - clients.each {|c| c.tag dst } - - # focus new view - v = View.new dst - v.focus - v.arrange_in_grid - - # propagate focus into new view - clients.first.focus v - end - - Mod1-Control-Shift-b: | # return grouping to original view - clients = grouping - - unless clients.empty? - src = curr_tag - - if src =~ ZOOMED_SUFFIX - # determine new view - dst = $` - - # remove clients from old view - clients.each do |c| - c.with_tags do - delete src - - if empty? - push dst - else - dst = last - end - end - end - - # focus new view - v = View.new dst - v.focus - - # propagate focus into original view - clients.first.focus v - end - end - - #--------------------------------------------------------------------------- - # arrange - #--------------------------------------------------------------------------- - - Mod1-Control-z,t: | # arrange clients in current view like LarsWM does - curr_view.arrange_as_larswm - - Mod1-Control-z,g: | # arrange clients in current view like a grid - curr_view.arrange_in_grid - - Mod1-Control-z,d: | # arrange clients in current view like a diamond - curr_view.arrange_in_diamond - - # apply grid layout with the pressed number of clients per column - Mod1-Control-z,1: curr_view.arrange_in_grid 1 - Mod1-Control-z,2: curr_view.arrange_in_grid 2 - Mod1-Control-z,3: curr_view.arrange_in_grid 3 - Mod1-Control-z,4: curr_view.arrange_in_grid 4 - Mod1-Control-z,5: curr_view.arrange_in_grid 5 - Mod1-Control-z,6: curr_view.arrange_in_grid 6 - Mod1-Control-z,7: curr_view.arrange_in_grid 7 - Mod1-Control-z,8: curr_view.arrange_in_grid 8 - Mod1-Control-z,9: curr_view.arrange_in_grid 9 - Mod1-Control-z,0: curr_view.arrange_in_grid 9999 # make one giant column - #--------------------------------------------------------------------------- # menu #--------------------------------------------------------------------------- - Mod1-Control-i: | # run internal action chosen from a menu + ${mod}-a: | # run internal action chosen from a menu if choice = key_menu(actions, 'run action:') action choice end - Mod1-Control-e: | # run external program chosen from a menu + ${mod}-p: | # run external program chosen from a menu if choice = key_menu(@programs, 'run program:') launch choice end - Mod1-Control-u: | # focus view chosen from a menu + ${mod}-t: | # focus view chosen from a menu if choice = key_menu(tags, 'show view:') focus_view choice end - Mod1-Control-a: | # focus client chosen from a menu - choices = [] - - clients.each_with_index do |c, i| - choices << "%d. [%s] %s" % [i, c[:tags].read, c[:label].read.downcase] - end - - if target = key_menu(choices, 'show client:') - i = target.scan(/\d+/).first.to_i - clients[i].focus - end - #--------------------------------------------------------------------------- # launcher #--------------------------------------------------------------------------- - Mod1-Control-x: | # launch a terminal + ${mod}-Return: | # launch a terminal # # Launch a new terminal and set its # working directory to be the same @@ -562,77 +313,9 @@ control: require 'fileutils' FileUtils.cd work do - launch 'urxvt' + launch CONFIG['program']['terminal'] end - Mod1-Control-k: | # launch a web browser - launch 'firefox' - - Mod1-Control-j: | # launch a file manager - launch 'thunar' - - Mod1-Control-q: | # launch a note taker - launch 'mousepad' - - #--------------------------------------------------------------------------- - # music - #--------------------------------------------------------------------------- - - Mod1-Control-Prior: | # previous song - @music.previous rescue nil - status 'music' - - Mod1-Control-Next: | # next song - @music.next rescue nil - status 'music' - - Mod1-Control-Return: | # pause song (toggle) - begin - if @music.stopped? - @music.play - else - @music.pause = !@music.paused? - end - rescue - # ignore - end - - status 'music' - - Mod1-Control-Home: | # load a playlist - if list = key_menu(@music.playlists, 'load playlist:') - @music.clear - @music.load list - @music.play - end - - Mod1-Control-End: | # add current song to a playlist - if list = key_menu(@music.playlists, 'add current song to playlist:') - file = File.join(File.expand_path('~/.mpd/playlists'), list + '.m3u') - - songs = File.readlines(file) rescue [] - songs << @music.current_song.file - songs.uniq! - - File.open(file, 'w') {|f| f.puts songs } - end - - #--------------------------------------------------------------------------- - # volume - #--------------------------------------------------------------------------- - - Mod1-Control-Shift-Prior: | # increase volume - system 'amixer set Master 3dB+' - status 'volume' - - Mod1-Control-Shift-Next: | # decrease volume - system 'amixer set Master 3dB-' - status 'volume' - - Mod1-Control-Shift-Return: | # mute volume (toggle) - system 'amixer set Master toggle' - status 'volume' - ## # Event handlers. # @@ -691,47 +374,6 @@ control: RightBarClick: | status_click *argv.reverse - Unresponsive: | - client_id = argv[0] - client = Client.new(client_id) - - IO.popen('xmessage -nearmouse -file - -buttons Kill,Wait -print', 'w+') do |f| - f.puts 'The following client is not responding.', '' - f.puts client.inspect - f.puts client.label.read - - f.puts '', 'What would you like to do?' - f.close_write - - if f.read.chomp == 'Kill' - client.slay - end - end - - Notice: | - unless defined? @notice_mutex - require 'thread' - @notice_mutex = Mutex.new - end - - Thread.new do - # prevent notices from overwriting each other - @notice_mutex.synchronize do - button = fs.rbar['!notice'] - button.create unless button.exist? - - # display the notice - message = argv.join(' ') - - LOG.info message # also log it in case the user is AFK - button.write "#{CONFIG['display']['color']['notice']} #{message}" - - # clear the notice - sleep [1, CONFIG['display']['notice'].to_i].max - button.remove - end - end - ClientMouseDown: | client_id, mouse_button = argv @@ -753,35 +395,6 @@ control: # <action name>: <Ruby code to execute> # action: - reload: | # reload this wmii configuration - reload_config - - rehash: | # scan for available programs and actions - @programs = find_programs(ENV['PATH'].squeeze(':').split(':')) - - clear: | # kill all clients - # firefox's restore session feature does not - # work unless the whole process is killed. - system 'killall firefox firefox-bin thunderbird thunderbird-bin' - - # gnome-panel refuses to die by any other means - system 'killall -s TERM gnome-panel' - - Thread.pass until clients.each do |c| - begin - c.focus # XXX: client must be on current view in order to be killed - c.kill - rescue - # ignore - end - end.empty? - - kill: | # kill the window manager only; do not touch the clients! - fs.ctl.write 'quit' - - quit: | # kill both clients and window manager - action 'clear' - action 'kill' ## @@ -792,13 +405,5 @@ control: # after: <Ruby code to execute after processing this file> # script: - before: | - DETACHED_TAG = '|' - ZOOMED_SUFFIX = /~(\d+)$/ - - after: | - action 'rehash' - - # desktop wallpaper - system 'sh ~/.fehbg' - + before: + after: diff --git a/alternative_wmiircs/ruby/wmiirc b/alternative_wmiircs/ruby/wmiirc @@ -1,5 +1,7 @@ #!/usr/bin/env ruby +# # Bootloader for wmii configuration. +# #-- # Copyright protects this work. # See LICENSE file for details. @@ -25,11 +27,14 @@ begin LOG.info 'birth' # load configuration library - config_home = File.dirname(__FILE__) - config_libs = File.join(config_home, 'config.rb') - config_file = File.join(config_home, 'config.yaml') + def find_config file + base_dirs = ENV['WMII_CONFPATH'].to_s.split(/:+/) + ruby_dirs = base_dirs.map {|dir| File.join(dir, 'ruby') } - require config_libs + Dir["{#{base_dirs.zip(ruby_dirs).join(',')}}/#{file}"].first + end + + require find_config('config.rb') # terminate any existing wmiirc fs.event.write 'Start wmiirc' @@ -39,7 +44,7 @@ begin end # apply user configuration - load_config config_file + load_config find_config('config.yaml') # setup tag bar (buttons that correspond to views) fs.lbar.clear