commit 28c53e294bca12a0b279fea0baab1ff2a5172c68
parent 8d4f02346859603a77a0899dc25a0ccef50f241c
Author: Suraj N. Kurapati <sunaku@gmail.com>
Date: Mon, 11 Sep 2006 23:26:48 -0700
[project @ f290e1d1a16e0c998feedd8629350c9d9cd4cd4e]
[project @ 71]
add support for starting IRB with an object context
replace #with_selection with modified Array#each... so client operations always work
rm Wmii::State.. all wmii methods accessed directly from the module
Diffstat:
fs.rb | | | 2 | +- |
rc.rb | | | 64 | ++++++++++++++++++++++++++++------------------------------------ |
wm.rb | | | 159 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
wmiirc | | | 124 | ++++++++++++++++++++++++++++++++++++++++---------------------------------------- |
wmiish | | | 52 | +++++++++++++++++++++++++++++++++++++++++++++------- |
5 files changed, 222 insertions(+), 179 deletions(-)
diff --git a/fs.rb b/fs.rb
@@ -106,7 +106,7 @@ module Ixp
# Obtains the IXP node at the given path. If aCreateIt is asserted, then the given path is created unless it already exists.
def initialize aPath, aCreateIt = false
- @path = aPath.squeeze('/')
+ @path = aPath.to_s.squeeze('/')
create! if aCreateIt && !exist?
end
diff --git a/rc.rb b/rc.rb
@@ -17,11 +17,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
=end
-require 'find'
require 'wm'
-
-include Wmii
-include Wmii::State
+require 'find'
# Returns a list of program names available in the given paths.
def find_programs *aPaths
@@ -55,72 +52,67 @@ end
# Focuses the client chosen from a menu.
def focus_client_from_menu
- choices = clients.map do |c|
+ choices = Wmii.clients.map do |c|
format "%d. [%s] %s", c.index, c.tags, c.name.downcase
end
target = show_menu(choices)
unless target.empty?
- focus_client target.scan(/\d+/).first
+ Wmii.focus_client target.scan(/\d+/).first
end
end
# Changes the tag, chosen from a menu, of each selected client.
# The {+tag -tag idea}[http://zimbatm.oree.ch/articles/2006/06/15/wmii-3-and-ruby] is from Jonas Pfenniger.
def change_tag_from_menu
- choices = tags.map {|t| [t, "+#{t}", "-#{t}"]}.flatten
+ choices = Wmii.tags.map {|t| [t, "+#{t}", "-#{t}"]}.flatten
target = show_menu(choices)
- with_selection do |c|
- c.with_tags do
- case target
- when /^\+/
- push $'
+ Wmii.selected_clients.each do |c|
+ case target
+ when /^\+/
+ c.tag! $'
- when /^\-/
- delete $'
+ when /^\-/
+ c.untag! $'
- else
- clear
- push target
- end
+ else
+ c.tags = target
end
end
end
# Send selected clients to temporary view or switch back again.
def toggle_temp_view
- curView = current_view.name
+ curTag = Wmii.current_view.name
- if curView =~ /~\d+$/
- with_selection do |c|
+ if curTag =~ /~\d+$/
+ Wmii.selected_clients.each do |c|
c.with_tags do
- delete curView
+ delete curTag
push $` if empty?
end
end
- focus_view $`
+ Wmii.focus_view $`
else
- tmpView = "#{curView}~#{Time.now.to_i}"
+ tmpTag = "#{curTag}~#{Time.now.to_i}"
- with_selection do |c|
- c.with_tags do
- push tmpView
- end
+ Wmii.selected_clients.each do |c|
+ c.tag! tmpTag
end
- focus_view tmpView
- current_view.grid!
+ Wmii.focus_view tmpTag
+ Wmii.current_view.grid!
end
end
# Puts focus on an adjacent view (:left or :right).
def cycle_view aTarget
- tags = self.tags
- curTag = current_view.name
+ tags = Wmii.tags
+ curTag = Wmii.current_view.name
curIndex = tags.index(curTag)
newIndex =
@@ -136,7 +128,7 @@ def cycle_view aTarget
end % tags.length
- focus_view tags[newIndex]
+ Wmii.focus_view tags[newIndex]
end
@@ -146,16 +138,16 @@ DETACHED_TAG = 'status'
# Detach the current selection.
def detach_selection
- selected_clients.each do |c|
+ Wmii.selected_clients.each do |c|
c.tags = DETACHED_TAG
end
end
# Attach the most recently detached client
def attach_last_client
- if a = View.new("/#{DETACHED_TAG}").areas.last
+ if a = Wmii::View.new("/#{DETACHED_TAG}").areas.last
if c = a.clients.last
- c.tags = current_view.name
+ c.tags = Wmii.current_view.name
end
end
end
diff --git a/wm.rb b/wm.rb
@@ -19,11 +19,42 @@
require 'fs'
+# Encapsulates access to the window manager.
module Wmii
- SELECTION_TAG = 'SEL'
+ ## state access
+
+ # Returns the currently focused client.
+ def Wmii.current_client
+ Client.new("/view/sel/sel")
+ end
+
+ # Returns the currently focused area.
+ def Wmii.current_area
+ Area.new("/view/sel")
+ end
+
+ # Returns the currently focused view.
+ def Wmii.current_view
+ View.new("/view")
+ end
+
+ # Returns the current set of tags.
+ def Wmii.tags
+ Ixp.read('/tags').split
+ end
+
+ # Returns the current set of views.
+ def Wmii.views
+ tags.map {|v| View.new "/#{v}"}
+ end
+
+ # Returns the current set of clients.
+ def Wmii.clients
+ Area.new("/client").clients
+ end
# Searches for the client with the given ID and returns it. If the client is not found, *nil* is returned. The search is performed within the given places if they are specified.
- def find_client aClientId, aArea = nil, aView = nil
+ def Wmii.find_client aClientId, aArea = nil, aView = nil
aClientId = aClientId.to_i
needle = Client.new("/client/#{aClientId}")
@@ -32,8 +63,10 @@ module Wmii
if aArea && aArea.exist?
areas << aArea
+
elsif aView && aView.exist?
areas.concat aView.areas
+
else
needle.tags.map {|t| View.new("/#{t}")}.each do |v|
areas.concat v.areas
@@ -50,13 +83,16 @@ module Wmii
nil
end
+
+ ## state manipulation
+
# Focuses the view with the given name.
- def focus_view aName
+ def Wmii.focus_view aName
View.new("/#{aName}").focus!
end
# Focuses the client which has the given ID.
- def focus_client aClientId
+ def Wmii.focus_client aClientId
if c = find_client(aClientId)
v = (a = c.parent).parent
@@ -66,82 +102,35 @@ module Wmii
end
end
- # Encapsulates the window manager's state.
- module State
- # Returns the currently focused client.
- def current_client
- Client.new("/view/sel/sel")
- end
-
- # Returns the currently focused area.
- def current_area
- Area.new("/view/sel")
- end
-
- # Returns the currently focused view.
- def current_view
- View.new("/view")
- end
-
- # Returns the current set of tags.
- def tags
- Ixp.read('/tags').split
- end
-
- # Returns the current set of views.
- def views
- tags.map {|v| View.new "/#{v}"}
- end
-
- # Returns the current set of clients.
- def clients
- Area.new("/client").clients
- end
-
- ## Multiple client selection
-
- # Returns a list of all selected clients in the currently focused view. If there are no selected clients, then the currently focused client is returned in the list.
- def selected_clients
- list = current_view.areas.map do |a|
- a.clients.select {|c| c.selected?}
- end
- list.flatten!
+ ## Multiple client selection
- if list.empty?
- list << current_client
- end
+ SELECTION_TAG = 'SEL'
- list
+ # Returns a list of all selected clients in the currently focused view. If there are no selected clients, then the currently focused client is returned in the list.
+ def Wmii.selected_clients
+ list = current_view.areas.map do |a|
+ a.clients.select {|c| c.selected?}
end
+ list.flatten!
- # Un-selects all selected clients so that there is nothing selected.
- def select_none!
- View.new("/#{SELECTION_TAG}").unselect!
+ if list.empty?
+ list << current_client
end
- # Invokes the given block for each #selected_clients in a way that supports destructive operations, which change the number of areas in a view.
- def with_selection # :yields: client
- return unless block_given?
+ list
+ end
- curView = current_view
+ # Un-selects all selected clients so that there is nothing selected.
+ def Wmii.select_none!
+ View.new("/#{SELECTION_TAG}").unselect!
+ end
- selected_clients.each do |c|
- # resolve stale paths caused by destructive operations
- unless c.exist?
- c = find_client(c.basename, nil, curView)
- next unless c
- end
- yield c
- end
- end
- end
+ ## subclasses for abstraction
- # Head of the window manager's hierarchy.
+ # Head of IXP file system hierarchy.
class Root < Ixp::Node
- include State
-
def initialize
super '/'
end
@@ -149,8 +138,6 @@ module Wmii
# A region in the window manager's hierarchy.
class Node < Ixp::Node
- include Wmii
-
def initialize aParentClass, aChildClass, *aArgs
@parentClass = aParentClass
@childClass = aChildClass
@@ -300,7 +287,10 @@ module Wmii
# Inserts the given clients at the bottom of this area.
def push! *aClients
- clients.last.focus! if exist?
+ if target = clients.last
+ target.focus!
+ end
+
insert! aClients
end
@@ -322,7 +312,10 @@ module Wmii
aClients.flatten!
return if aClients.empty?
- clients.first.focus! if exist?
+ if target = clients.first
+ target.focus!
+ end
+
setup_for_insertion! aClients.shift
clients.first.ctl = 'swap down'
@@ -351,7 +344,7 @@ module Wmii
maxIdx = parent.indices.last
maxCol = parent[maxIdx]
- aFirstClient = find_client(aFirstClient.index, maxCol)
+ aFirstClient = Wmii.find_client(aFirstClient.index, maxCol)
# move *into* final destination
if maxCol.indices.length > 1
@@ -455,3 +448,23 @@ module Wmii
end
end
end
+
+class Array
+ alias original_each each
+
+ def each
+ return unless block_given?
+
+ original_each do |c|
+ if c.is_a? Wmii::Client
+ # resolve stale paths caused by destructive operations
+ unless c.exist?
+ c = Wmii.find_client(c.basename, nil, Wmii.current_view)
+ next unless c
+ end
+ end
+
+ yield c
+ end
+ end
+end
diff --git a/wmiirc b/wmiirc
@@ -24,37 +24,36 @@ require 'rc'
## WM STARTUP
-WM = Wmii::Root.new
-
+FS = Wmii::Root.new
PROGRAM_MENU = find_programs( ENV['PATH'].squeeze(':').split(':') )
ACTION_MENU = find_programs('~/dry/apps/wmii/etc/wmii-3', File.dirname(__FILE__))
# terminate existing wmiirc processes
-sleep 1 until WM.event = "Start wmiirc\n"
+sleep 1 until FS.event = "Start wmiirc\n"
## 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'
+ENV['FSII_FONT'] = '-misc-fixed-medium-r-normal--18-120-100-100-c-90-iso10646-1'
+ENV['FSII_SELCOLORS']='#ffffff #285577 #4c7899'
+ENV['FSII_NORMCOLORS']='#222222 #eeeeee #666666'
system %{xsetroot -solid '#333333'}
## WM CONFIGURATION
-WM.def.border = 2
+FS.def.border = 2
-WM.def.font = ENV['WMII_FONT']
-WM.def.selcolors = ENV['WMII_SELCOLORS']
-WM.def.normcolors = ENV['WMII_NORMCOLORS']
+FS.def.font = ENV['FSII_FONT']
+FS.def.selcolors = ENV['FSII_SELCOLORS']
+FS.def.normcolors = ENV['FSII_NORMCOLORS']
-WM.def.colmode = 'default'
-WM.def.colwidth = 0
+FS.def.colmode = 'default'
+FS.def.colwidth = 0
-WM.def.rules = <<EOS
+FS.def.rules = <<EOS
/jEdit.*/ -> code
/Buddy List.*/ -> chat
/XChat.*/ -> chat
@@ -122,80 +121,80 @@ SHORTCUTS = {
# focus previous area
"#{FOCUS}#{LEFT}" => lambda do
- current_view.ctl = 'select prev'
+ Wmii.current_view.ctl = 'select prev'
end,
# focus next area
"#{FOCUS}#{RIGHT}" => lambda do
- current_view.ctl = 'select next'
+ Wmii.current_view.ctl = 'select next'
end,
# focus floating area
"#{FOCUS}space" => lambda do
- current_view.ctl = 'select toggle'
+ Wmii.current_view.ctl = 'select toggle'
end,
# focus previous client
"#{FOCUS}#{UP}" => lambda do
- current_area.ctl = 'select prev'
+ Wmii.current_area.ctl = 'select prev'
end,
# focus next client
"#{FOCUS}#{DOWN}" => lambda do
- current_area.ctl = 'select next'
+ Wmii.current_area.ctl = 'select next'
end,
# apply equal spacing layout to currently focused column
"#{LAYOUT}w" => lambda do
- current_area.mode = 'default'
+ Wmii.current_area.mode = 'default'
end,
# apply stacked layout to currently focused column
"#{LAYOUT}v" => lambda do
- current_area.mode = 'stack'
+ Wmii.current_area.mode = 'stack'
end,
# apply maximized layout to currently focused column
"#{LAYOUT}m" => lambda do
- current_area.mode = 'max'
+ Wmii.current_area.mode = 'max'
end,
# maximize the floating area's focused client
"#{LAYOUT}z" => lambda do
- current_view[0].sel.geom = '0 0 east south'
+ Wmii.current_view[0].sel.geom = '0 0 east south'
end,
# apply tiling layout to the currently focused view
"#{LAYOUT}t" => lambda do
- current_view.tile!
+ Wmii.current_view.tile!
end,
# apply gridding layout to the currently focused view
"#{LAYOUT}g" => lambda do
- current_view.grid!
+ Wmii.current_view.grid!
end,
# add/remove the currently focused client from the selection
"#{GROUP}g" => lambda do
- current_client.invert_selection!
+ Wmii.current_client.invert_selection!
end,
# add all clients in the currently focused view to the selection
"#{GROUP}a" => lambda do
- current_view.select!
+ Wmii.current_view.select!
end,
# invert the selection in the currently focused view
"#{GROUP}i" => lambda do
- current_view.invert_selection!
+ Wmii.current_view.invert_selection!
end,
# nullify the selection
"#{GROUP}n" => lambda do
- select_none!
+ Wmii.select_none!
end,
@@ -213,7 +212,7 @@ SHORTCUTS = {
# focus any view by choosing from a menu
"#{MENU}Shift-v" => lambda do
- focus_view(show_menu(tags))
+ Wmii.focus_view(show_menu(Wmii.tags))
end,
"#{MENU}a" => lambda do
@@ -235,25 +234,25 @@ SHORTCUTS = {
"#{SEND}#{LEFT}" => lambda do
- with_selection do |c|
+ Wmii.selected_clients.each do |c|
c.ctl = 'sendto prev'
end
end,
"#{SEND}#{RIGHT}" => lambda do
- with_selection do |c|
+ Wmii.selected_clients.each do |c|
c.ctl = 'sendto next'
end
end,
"#{SEND}space" => lambda do
- with_selection do |c|
+ Wmii.selected_clients.each do |c|
c.ctl = 'sendto toggle'
end
end,
"#{SEND}Delete" => lambda do
- with_selection do |c|
+ Wmii.selected_clients.each do |c|
c.ctl = 'kill'
end
end,
@@ -264,8 +263,10 @@ SHORTCUTS = {
# remove currently focused view from current selection's tags
"#{SEND}Shift-minus" => lambda do
- with_selection do |c|
- c.untag! current_view.name
+ curTag = Wmii.current_view.name
+
+ Wmii.selected_clients.each do |c|
+ c.untag! curTag
end
end,
@@ -291,22 +292,22 @@ SHORTCUTS = {
# swap the currently focused client with the one to its left
"#{SWAP}#{LEFT}" => lambda do
- current_client.ctl = 'swap prev'
+ Wmii.current_client.ctl = 'swap prev'
end,
# swap the currently focused client with the one to its right
"#{SWAP}#{RIGHT}" => lambda do
- current_client.ctl = 'swap next'
+ Wmii.current_client.ctl = 'swap next'
end,
# swap the currently focused client with the one below it
"#{SWAP}#{DOWN}" => lambda do
- current_client.ctl = 'swap down'
+ Wmii.current_client.ctl = 'swap down'
end,
# swap the currently focused client with the one above it
"#{SWAP}#{UP}" => lambda do
- current_client.ctl = 'swap up'
+ Wmii.current_client.ctl = 'swap up'
end,
}
@@ -315,42 +316,42 @@ SHORTCUTS = {
# focus _i_th view
SHORTCUTS["#{FOCUS}#{i}"] = lambda do
- focus_view(tags[k] || i)
+ Wmii.focus_view Wmii.tags[k] || i
end
# send selection to _i_th view
SHORTCUTS["#{SEND}#{i}"] = lambda do
- with_selection do |c|
- c.tags = (tags[k] || i)
+ 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
- dst = current_view[i]
+ dstCol = Wmii.current_view[i]
- with_selection do |c|
- dst.insert! c
+ Wmii.selected_clients.each do |c|
+ dstCol.insert! c
end
end
# apply grid layout with _i_ clients per column
SHORTCUTS["#{LAYOUT}#{i}"] = lambda do
- current_view.grid! i
+ 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
- with_selection do |c|
- c.tag! tags[k] || i
+ 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
- with_selection do |c|
- c.untag! tags[k] || i
+ Wmii.selected_clients.each do |c|
+ c.untag! Wmii.tags[k] || i
end
end
end
@@ -358,31 +359,31 @@ end
# jump to view whose name begins with the pressed key
('a'..'z').each do |char|
SHORTCUTS["#{MENU}v,#{char}"] = lambda do
- choices = self.tags
- choices.delete current_view.name
+ choices = Wmii.tags
+ choices.delete Wmii.current_view.name
if view = choices.select {|t| t =~ /^#{char}/i}.first
- focus_view view
+ Wmii.focus_view view
end
end
end
-WM.def.grabmod = MODKEY
-WM.def.keys = SHORTCUTS.keys.join("\n")
+FS.def.grabmod = MODKEY
+FS.def.keys = SHORTCUTS.keys.join("\n")
## STATUS BAR
Thread.new do
- status = Ixp::Node.new("/bar/status", true)
- status.colors = ENV['WMII_NORMCOLORS']
+ sb = Ixp::Node.new('/bar/status', true)
+ sb.colors = ENV['FSII_NORMCOLORS']
loop do
cpuLoad = `uptime`.scan(/\d+\.\d+/).join(' ')
diskSpace = `df -h ~`.split[-3..-1].join(' ')
5.times do
- status.data = "#{Time.now.to_s} | #{cpuLoad} | #{diskSpace}"
+ sb.data = "#{Time.now.to_s} | #{cpuLoad} | #{diskSpace}"
sleep 1
end
end
@@ -405,17 +406,17 @@ begin
case mouseBtn.to_i
when PRIMARY
- focus_view viewId
+ Wmii.focus_view viewId
when MIDDLE
# add view to selection's tags
- with_selection do |c|
+ Wmii.selected_clients.each do |c|
c.tag! viewId
end
when SECONDARY
# remove view from selection's tags
- with_selection do |c|
+ Wmii.selected_clients.each do |c|
c.untag! viewId
end
end
@@ -425,7 +426,6 @@ begin
case mouseBtn.to_i
when MIDDLE, SECONDARY
- # add/remove client from selection
Wmii::Client.new("/client/#{clientId}").invert_selection!
end
diff --git a/wmiish b/wmiish
@@ -1,7 +1,9 @@
#!/usr/bin/ruby
# This is an interactive Ruby shell for wmii.
# - Press the TAB key for command completion.
+
=begin
+ Copyright 2004 Joel VanderWerf
Copyright 2006 Suraj N. Kurapati
This program is free software; you can redistribute it and/or
@@ -20,15 +22,51 @@
=end
-require 'rdoc/usage'
-RDoc::usage_no_exit
+## This code was adapted from ruby-talk:99201.
+require 'irb'
+require 'irb/completion'
-$:.unshift File.dirname(__FILE__)
-require 'rc'
+module IRB
+ # Starts IRB within the context of the given object.
+ def IRB.start_session aContextObj
+ IRB.setup nil unless $irb
+ ws = WorkSpace.new(aContextObj)
-require 'irb'
-require 'irb/completion'
+ $irb = if @CONF[:SCRIPT] # normally, set by parse_opts
+ Irb.new ws, @CONF[:SCRIPT]
+ else
+ Irb.new ws
+ end
+
+ @CONF[:IRB_RC].call($irb.context) if @CONF[:IRB_RC]
+ @CONF[:MAIN_CONTEXT] = $irb.context
+
+ trap 'INT' do
+ $irb.signal_handle
+ end
+
+ custom_configuration if defined? IRB.custom_configuration
+
+ catch :IRB_EXIT do
+ $irb.eval_input
+ end
+ end
+end
+
+class Object
+ include IRB::ExtendCommandBundle # so that Marshal.dump works
+end
+
+
+if __FILE__ == $0
+ # show usage info
+ require 'rdoc/usage'
+ RDoc::usage_no_exit
+
+ $:.unshift File.dirname(__FILE__)
+ require 'rc'
-IRB.start __FILE__
+ IRB.start_session Wmii
+end