wmiirc-rumai

git clone git://oldgit.suckless.org/wmiirc-rumai/
Log | Files | Refs | README | LICENSE

commit e8bf8f74b052e27e1fe2a0bf5b18a703e755ee92
parent 33cc57a5cc195c9be03bb2c2f175742aaf6f9080
Author: Suraj N. Kurapati <sunaku@gmail.com>
Date:   Sun,  6 Aug 2006 18:43:58 -0700

[project @ 5fbfa9c8867766ebcdc399888a8f094a580ce30f]

[project @ 4]
add	tiling and grid layouts

Diffstat:
wmii.rb | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
wmiirc | 47++++++++++++++++++++++++++++++++++-------------
2 files changed, 170 insertions(+), 58 deletions(-)

diff --git a/wmii.rb b/wmii.rb @@ -1,4 +1,22 @@ # Ruby interface to WMII. +=begin + Copyright 2006 Suraj N. Kurapati + Copyright 2006 Stephan Maka + + 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 $:.unshift File.join(File.dirname(__FILE__), 'ruby-ixp/lib') require 'ixp' @@ -17,58 +35,54 @@ class Wmii end end - def create(file) - @cl.create(file) - rescue IXP::IXPException => e - puts "#{e.backtrace.first}: #{e}" + # Creates the given WM path. + def create aPath + begin + @cl.create aPath + rescue IXP::IXPException => e + puts "#{e.backtrace.first}: #{e}" + end end - def remove(file) - @cl.remove(file) - rescue IXP::IXPException => e - puts "#{e.backtrace.first}: #{e}" + # Deletes the given WM path. + def remove aPath + begin + @cl.remove aPath + rescue IXP::IXPException => e + puts "#{e.backtrace.first}: #{e}" + end end - # Writes the given content to the given WM path, and returns +true+ if the operation was successful. - # def write aPath, aContent - # begin - # IO.popen("wmiir write #{aPath}", 'w') do |io| - # puts "wmiir: writing '#{aContent}' into '#{aPath}'" if $DEBUG - # io.write aContent - # end - # rescue Errno::EPIPE - # return false - # end - - # $? == 0 - # end - - def write(file, data) - @cl.open(file) { |f| f.write(data.to_s) } - rescue IXP::IXPException => e - puts "#{e.backtrace.first}: #{e}" + # Writes the given content to the given WM path. + def write aPath, aContent + begin + @cl.open(aPath) do |f| + f.write aContent.to_s + end + rescue IXP::IXPException => e + puts "#{e.backtrace.first}: #{e}" + end end - # def read aPath - # `wmiir read #{aPath}` - # end + # Reads from the given WM path and returns the content. If the path is a directory, then the names of all files in that directory are returned. + def read aPath + begin + @cl.open(aPath) do |f| + if f.respond_to? :next # read file-names from directory + names = '' - def read(file) - @cl.open(file) do |f| - if f.respond_to? :next # read directory listing - str = '' + while i = f.next + names << i.name << "\n" + end - while i = f.next - str << i.name << "\n" + names + else # read file contents + f.read_all end - - str - else - f.read_all end + rescue IXP::IXPException => e + puts "#{e.backtrace.first}: #{e}" end - rescue IXP::IXPException => e - puts "#{e.backtrace.first}: #{e}" end # Shows the view with the given name. @@ -93,11 +107,11 @@ class Wmii # Shows the client which has the given ID. def showClient aClientId read('/tags').split.each do |view| - read("/#{view}").split.grep(/^\d+$/).each do |column| - read("/#{view}/#{column}").split.grep(/^\d+$/).each do |client| - if read("/#{view}/#{column}/#{client}/index") == aClientId + read("/#{view}").split.grep(/^\d+$/).each do |area| + read("/#{view}/#{area}").split.grep(/^\d+$/).each do |client| + if read("/#{view}/#{area}/#{client}/index") == aClientId showView view - write '/view/ctl', "select #{column}" + write '/view/ctl', "select #{area}" write "/view/sel/ctl", "select #{client}" return end @@ -160,6 +174,83 @@ class Wmii end end + # Applies wmii-2 style tiling layout to the current view while maintaining the order of clients in the current view. Only the first client in the primary column is kept; all others are evicted to the *top* of the secondary column. Any teritiary, quaternary, etc. columns are squeezed into the *bottom* of the secondary column. + def applyTilingLayout + areaList = read('/view').split.grep(/^[^0]\d*$/) + + unless areaList.empty? + # keep only the first client in zoomed area + write '/view/2/ctl', 'select 0' + + read('/view/1').split.grep(/^[^0]\d*$/).length.times do |i| + write '/view/1/1/ctl', 'sendto next' + write '/view/2/sel/ctl', 'swap up' if i.zero? + end + + write '/view/1/mode', 'max' + + # squeeze unzoomed clients into secondary column + if secondary = read('/view/2') + write '/view/2/ctl', "select #{secondary.split.grep(/^\d+$/).last}" + + (areaList.length - 2).times do + read('/view/3').split.grep(/^\d+$/).length.times do + write '/view/3/0/ctl', 'sendto prev' + end + end + + write '/view/2/mode', 'default' + end + end + end + + # Applies wmii-2 style grid layout to the current view while maintaining the order of clients in the current view. If the maximum number of clients per column, the distribution of clients among the columns is calculated according to wmii-2 style. if is specified, it Only the first client in the primary column is kept; all others are evicted to the *top* of the secondary column. Any teritiary, quaternary, etc. columns are squeezed into the *bottom* of the secondary column. + def applyGridLayout aMaxClientsPerColumn = nil + # determine client distribution + unless aMaxClientsPerColumn + numClients = 0 + + read('/view').split.grep(/^[^0]\d*$/).each do |column| + numClients += read("/view/#{column}").split.grep(/^\d+$/).length + end + + numColumns = Math.sqrt(numClients) + aMaxClientsPerColumn = (numClients / numColumns).ceil + end + + # distribute the clients + begin + columnList = read('/view').split.grep(/^[^0]\d*$/) + + columnList.each do |column| + if clientList = read("/view/#{column}") + write "/view/#{column}/mode", 'default' # set *equal* layout for column + + numClients = clientList.split.grep(/^\d+$/).length + nextColumn = column.to_i + 1 + + if numClients > aMaxClientsPerColumn + # evict excess clients to next column + write "/view/#{nextColumn}/ctl", 'select 0' + + (numClients - aMaxClientsPerColumn).times do |i| + write "/view/#{column}/#{aMaxClientsPerColumn}/ctl", 'sendto next' + write "/view/#{nextColumn}/sel/ctl", 'swap up' if i.zero? + end + + elsif numClients < aMaxClientsPerColumn + # import clients from next column + write "/view/#{column}/ctl", "select #{read("/view/#{column}").split.grep(/^\d+$/).last}" + + (aMaxClientsPerColumn - numClients).times do + write "/view/#{nextColumn}/0/ctl", 'sendto prev' + end + end + end + end + end until columnList.length == read('/view').split.grep(/^[^0]\d*$/).length + end + # Returns a list of program names available in the given paths. def findPrograms *aPaths list = [] diff --git a/wmiirc b/wmiirc @@ -1,5 +1,22 @@ #!/usr/bin/ruby -w # wmii-3 configuration, written in Ruby. +=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 'wmii' @@ -81,6 +98,9 @@ SHORTCUTS = { "#{LAYOUT}m" => lambda do WM.write '/view/sel/mode', 'max' end, "#{LAYOUT}z" => lambda do WM.write '/view/0/sel/geom', '0 0 east south' end, + "#{LAYOUT}t" => lambda do WM.applyTilingLayout end, + "#{LAYOUT}g" => lambda do WM.applyGridLayout end, + "#{MENU}i" => lambda do system(WM.showMenu(ACTION_MENU) << '&') end, "#{MENU}e" => lambda do system(WM.showMenu(PROGRAM_MENU) << '&') end, @@ -109,7 +129,6 @@ SHORTCUTS = { "#{PROGRAM}x" => lambda do system 'terminal &' end, "#{PROGRAM}k" => lambda do system 'epiphany &' end, "#{PROGRAM}j" => lambda do system 'nautilus --no-desktop &' end, - # "#{PROGRAM}q" => lambda do system 'beagle-search &' end, "#{SEND}#{LEFT}" => lambda do WM.write '/view/sel/sel/ctl', 'sendto prev' end, @@ -118,6 +137,7 @@ SHORTCUTS = { "#{SEND}Delete" => lambda do WM.write '/view/sel/sel/ctl', 'kill' end, # change the tag of the current client + # +tag -tag idea from Jonas Pfenniger <http://zimbatm.oree.ch/articles/2006/06/15/wmii-3-and-ruby> "#{SEND}t" => lambda do choices = WM.read('/tags').split.map {|t| [t, "+#{t}", "-#{t}"]}.flatten tags = WM.read('/view/sel/sel/tags').split('+') @@ -170,6 +190,7 @@ SHORTCUTS = { SHORTCUTS["#{SELECT}#{i}"] = lambda do WM.showView(WM.read('/tags').split[k] || i) end SHORTCUTS["#{SEND}#{i}"] = lambda do WM.write '/view/sel/sel/tags', (WM.read('/tags').split[k] || i) end + SHORTCUTS["#{LAYOUT}#{i}"] = lambda do WM.applyGridLayout i end end WM.write '/def/grabmod', MODKEY @@ -178,24 +199,24 @@ WM.write '/def/keys', SHORTCUTS.keys.join("\n") # EVENT LOOP begin -IO.popen('wmiir read /event') do |io| - while event = io.readline.chomp - type, arg = event.split + IO.popen('wmiir read /event') do |io| + while event = io.readline.chomp + type, arg = event.split - p event, type, arg if $DEBUG + p event, type, arg if $DEBUG - case type - when 'Start' - exit if arg == 'wmiirc' + case type + when 'Start' + exit if arg == 'wmiirc' - when 'BarClick' - WM.showView arg + when 'BarClick' + WM.showView arg - when 'Key' - SHORTCUTS[arg].call + when 'Key' + SHORTCUTS[arg].call + end end end -end rescue EOFError exit # wmiiwm has quit end