rumai
- Ruby interface to the wmii window manager
Rumai is a pure Ruby interface to the wmii window manager. Its name is a portmanteau of "Ruby" and "wmii" (which I pronounce as "vim eye").
Provides an interactive shell for live experimentation.
Arranges clients, columns, views, and tags dynamically.
Talks directly to wmii's IXP filesystem interface.
Includes a pure Ruby client for the 9P2000 protocol.
Powers my personal wmiirc and many others like it.
Prerequisites:
Installing:
gem install rumai
Upgrading:
gem update rumai
Removing:
gem uninstall rumai
rumai
[OPTIONS] [IRB_OPTIONS]
Starts an interactive Ruby shell (IRB) session by passing the given IRB_OPTIONS to irb(1). This puts you at a command prompt as follows:
irb(Rumai):001:0>
The irb(Rumai)
token in the command prompt indicates that commands will be
evaluated inside the Rumai
module. As a result, you can omit the "Rumai"
prefix from your commands if you wish.
For example, to get the currently selected client, you can type curr_client
instead of Rumai.curr_client
at the prompt. Both commands achieve the same
effect.
The next thing to notice is that TAB completion is enabled. So you can type part of a command and press the TAB key to see a list of possible completions.
-h
, --help
Display this manual and exit.
-v
, --version
Print version number and exit.
Now that you know how to start the interactive shell (see DESCRIPTION above) let us walk through a series of examples that highlight the main features of Rumai. You can follow along by copying & pasting the presented commands into the interactive shell.
Launch a few terminals so that we have something to work with:
colors = %w[ red green blue black orange brown gray navy gold ]
colors.each {|c| system "xterm -bg #{c} -title #{c} -e sh -c read &" }
Arrange all clients in a grid:
curr_view.arrange_in_grid
Arrange all clients in a diamond shape:
curr_view.arrange_in_diamond
Arrange all clients like LarsWM does:
curr_view.arrange_as_larswm
Close the terminals we launched earlier:
terms = curr_view.clients.select {|c| colors.include? c.label.read }
terms.each {|c| c.kill }
Launch a few terminals so that we have something to work with:
colors = %w[ red green blue black orange brown gray navy gold ]
colors.each {|c| system "xterm -bg #{c} -title #{c} -e sh -c read &" }
Add the red, green, and blue terminals into the "grouping":
terms = curr_view.clients.select do |c|
%w[red green blue].include? c.label.read
end
terms.each {|c| c.group }
You should now see a new button labelled as "@" on the left-hand side of wmii's bar, indicating that there is now a new view labelled "@" in wmii. Let us inspect what clients this mysterious view contains:
v = View.new "@"
puts v.clients.map {|c| c.label.read }
Aha! The mysterious view contains the red, green, and blue clients we recently "grouped". Thus, by adding a client to the "grouping", we are simply tagging the client with the "@" token.
Now that we have put some clients into the "grouping", let us move all clients in the grouping to the floating area in the current view:
grouping.each {|c| c.send "toggle" }
Neat! Let us bring them back into the managed area:
grouping.each {|c| c.send "toggle" }
Close the terminals we launched earlier:
terms = curr_view.clients.select {|c| colors.include? c.label.read }
terms.each {|c| c.kill }
In summary, you can select multiple clients (by adding them to the "grouping") and perform operations on them. This is useful when you want to do something with a group of clients but do not want to manually focus one, perform the action, focus the next one, and so on.
Another important aspect is that selected clients stay selected until they are unselected. This allows you to continue performing tasks on the selection without having to reselect the same clients after every operation.
Launch a few terminals so that we have something to work with:
colors = %w[ red green blue black orange brown gray navy gold ]
colors.each {|c| system "xterm -bg #{c} -title #{c} -e sh -c read &" }
You can insert a group of clients to the top, bottom, or after the currently focused client of any column using Array-like methods.
Give each client its own column (one client per column):
curr_view.each_column {|c| c.length = 1 }
Put (at most) three clients in every column:
curr_view.each_column {|c| c.length = 3 }
Move the red, green, and blue clients into the floating area:
rgb = %w[red green blue]
terms = curr_view.clients.select {|c| rgb.include? c.label.read }
curr_view.areas[0].push terms
Slurp all floating clients into the last column:
list = curr_view.areas
a, b = list.first, list.last
b.concat a
Set the last column's layout to stacking mode:
b.layout = 'stack'
Move the red, green, and blue clients to the top of the second column:
curr_view.areas[2].unshift terms
Move the red, green, and blue clients to the bottom of the third column:
curr_view.areas[3].push terms
Close the terminals we launched earlier:
terms = curr_view.clients.select {|c| colors.include? c.label.read }
terms.each {|c| c.kill }
Launch a few terminals so that we have something to work with:
colors = %w[ red green blue black orange brown gray navy gold ]
colors.each {|c| system "xterm -bg #{c} -title #{c} -e sh -c read &" }
Obtain a reference to the red client:
red = curr_view.clients.find {|c| c.label.read == "red" }
Show the red client's current tags:
red.tags
Add the "foo" and "bar" tags to the red client:
red.tag "foo", "bar"
Remove the "bar" tag from the red client:
red.untag "bar"
Do complex operations on the red client's tags:
red.with_tags { concat %w[a b c]; push 'z'; delete 'c' }
Focus the next client after the red client:
red.next.focus
curr_client == red.next #=> true
Notice that by focusing a client, we make it the current client.
Focus the red client on a different view:
orig = curr_view
v = red.views.last
red.focus v
Return to the original view:
orig.focus
Send the red client to the last column:
red.send curr_view.areas.last
Close the terminals we launched earlier:
terms = curr_view.clients.select {|c| colors.include? c.label.read }
terms.each {|c| c.kill }
Show the root node of wmii's IXP file system:
fs
Show the names of all files at the root level:
fs.entries
Show the parent of the root node:
fs.parent
Show the children of the root node:
fs.children
Navigate into to the /lbar/
directory:
n1 = fs.lbar
n2 = fs['lbar']
n1 == n2 #=> true
left_bar = n1
Notice that you can traverse the file system hierarchy by simply calling
methods on node objects. Alternatively, you can traverse by specifying an
arbitrary sub-path (relative path) using the []
operator on a node.
Create a new temporary button:
b = left_bar.rumai_example # path of new button
b.exist? #=> false
b.create
b.exist? #=> true
You should now see an empty button on the left-hand side of the wmii bar.
Color the button black-on-white and label it as "hello world":
content = "#000000 #ffffff #000000 hello world"
b.write content
b.read == content #=> true
Remove the temporary button:
b.remove
b.exist? #=> false
This section is meant for people who want to develop Rumai's source code.
Install Ruby libraries necessary for development:
gem install rumai --development
Inochi serves as the project infrastructure for Rumai. It handles tasks such as building this help manual and API documentation, and packaging, announcing, and publishing new releases. See its help manual and list of tasks to get started:
inochi --help # display help manual
inochi --tasks # list available tasks
Ensure that the lib/
directory is listed in Ruby's $LOAD_PATH
before you
use any libraries therein or run any executables in the bin/
directory.
This can be achieved by passing an option to Ruby:
ruby -Ilib bin/rumai
irb -Ilib -r rumai
Or by setting the $RUBYLIB
environment variable:
export RUBYLIB=lib # bash, ksh, zsh
setenv RUBYLIB lib # csh
set -x RUBYLIB lib # fish
ruby bin/rumai
irb -r rumai
Or by installing the ruby-wrapper tool.
If you use Ruby 1.8 or older, then ensure that RubyGems is activated before
you use any libraries in the lib/
directory or run any executables in the
bin/
directory.
This can be achieved by passing an option to Ruby:
ruby -rubygems bin/rumai
irb -rubygems -r rumai
Or by setting the $RUBYOPT
environment variable:
export RUBYOPT=-rubygems # bash, ksh, zsh
setenv RUBYOPT -rubygems # csh
set -x RUBYOPT -rubygems # fish
Simply execute the included test runner, which sets up Ruby's $LOAD_PATH
for
testing, loads the included test/test_helper.rb
file, and then evaluates all
test/**/*_test.rb
files:
test/runner
Its exit status will indicate whether all tests have passed. It may also
print additional pass/fail information depending on the testing library used
in the test/test_helper.rb
file.
Fork this project on GitHub (see Resources above) and send a pull request.
This section contains release notes of current and past releases.
This release adds support for growing and nudging clients, adds an abstraction for status bar applets, and beautifies the source code.
New features:
Add Rumai::Barlet
class for easier status bar applets. It exposes the
new, independent colors
and label
attributes introduced into the bar
file format by wmii-hg2743. It is also backwards-compatible with older
wmii versions where the aforementioned attributes were conjoined.
Add Rumai::Client#grow
and Rumai::Client#nudge
methods requested by Nathan Neff. See "The
/tag/ Hierarchy" in the wmii manpage for usage information.
Housekeeping:
Add workaround for wmii-hg2734 color tuple bug in the test suite.
Found real names for some anonymous contributors.
Clean up the source code formatting and organization.
This release fixes an IXP transport layer bug under Ruby 1.8.7.
Bug fixes:
IO#ungetc
does not accept a one-character string in Ruby 1.8.7.
Thanks to Sebastian Chmielewski for reporting this issue.
This release adds a UNIX manual page and requires wmii 3.9 or newer.
Bug fixes:
Rumai::Area#unshift
needs wmii 3.9 or newer.
The help manual has been corrected accordingly.
Thanks to Mattia Gheda for reporting this issue.
Housekeeping:
Upgrade to Inochi 3.0.0. Run rumai --help
to see the UNIX manual page!
Move IRB session creation code from rumai(1) into rumai/irb
sub-library.
This release fixes some warnings that appeared during installation and performs some minor housekeeping.
Bug fixes:
Unrecognized directive '...' in lib/rumai/inochi.yaml
Thanks to Mattia Gheda for reporting this.
Housekeeping:
This release improves multi-threading support in Rumai's pure-Ruby implementation of the IXP file-system interface.
Thank you:
Bug fixes:
Rumai::IXP::Agent#recv
only if recieve buffer is empty. This gives
other threads a chance to check the recieve buffer for their response.
instead of being blocked by us as we greedily hold on to the 9P2000
message stream until our expected response arrives.Housekeeping:
This release adds a new automated view arrangement, simplifies the IXP transport layer, and cleans up the code and API documentation.
New features:
Add Rumai::View#arrange_in_stacks
automated view arrangement.
Convert :stack
and :max
arguments into wmii 3.9 syntax in
Rumai::Area#layout=
.
Bug fixes:
Rumai::IXP::Agent
) to not use a
background thread, according to the XCB cookie approach.Housekeeping:
Clean up some code and API docs.
Reduce amount of string concatenation in Struct#to_9p
.
This release fixes bugs in automated view arrangements and updates the user manual.
Thank you:
Bug fixes:
The relative order of clients was not being preserved during view arrangements.
Focus on the current view was lost after automated view arrangement was applied if the current view was not the first view on which the initially focused (before the automated arrangement was applied) client appeared.
This release adds new methods, fixes some bugs, and revises the manual.
New features:
Add Client#float
methods to manipulate floating status.
Add Client#manage
methods to manipulate managed status.
The Client#tags=
method now accepts '~' and '!' tag prefixes.
Bug fixes:
There is no View#move_focus
method, only View#select
.
Assertion failure in test suite because all files in /rbar
(inside wmii's IXP filesystem) contain an automatic color header when
read.
Housekeeping:
Use simpler Copyright reminder at the top of every file.
Open source is for fun, so be nice: speak of "related works" instead of "competitors".
This release revises method names, adds new methods, and fixes a bug.
Incompatible changes:
Rename #toggle_
methods to use !
suffix in their names.
Rename #float
methods to #floating
.
Rename View#floater
method to View#floating_area
.
New features:
Add Client#stick
methods to manipulate sticky status.
Add Client#fullscreen
methods to manipulate fullscreen status.
Add Client#slay
method which is a forceful version of #kill
.
Add View#select
method to move focus relatively inside a view.
Add Area::floating
method for symmetry with Area::curr
.
Add View#managed_area
aliases for View#column
methods.
Bug fixes:
Fix error when unzooming clients from temporary view.
Fix code that launches temporary terminals in the Tutorial.
Use the /bin/sh
version of the read command for portability.
Housekeeping:
Use Client#send
instead of #swap
in automated arrangements because
it causes less traffic on /event/.
Add old release notes from blog to user manual.
This release improves client arrangement, fixes several bugs, and cleans up the code.
Thank you:
New features:
Focus is now restored on the initially focused client after applying automated client arrangements.
The push(), insert(), and unshift() instance methods of the
Rumai::Area
class now preserve the order of inserted clients.
The Rumai::View#arrange_in_grid()
method now accepts 1 as a parameter.
This invocation causes every column to contain at most 1 client.
Bug fixes:
Fix error caused by focusing the top/bottom client in the destination area before sending new clients into that area.
Fix error when importing clients into an empty area.
Housekeeping:
Use snake_case instead of camelCase for variable names.
Add copyright notice at the top of every file.
Plenty of code formatting and beautification.
This release fixes a connection bug.
Thank you:
$DISPLAY
bug.Bug fixes:
$DISPLAY
in its socket file path.
Rumai was trying to connect with the entire $DISPLAY
value (including
the fractional portion) and thus could not find wmii's socket file.This release simplifies project administrivia using Inochi, improves the unit tests, and revises the user manual.
Bug fixes:
/rbar/status
did not already exist in wmii.Housekeeping:
Store IXP socket address in Rumai::IXP_SOCK_ADDR
.
Added missing test cases for (TR)create and (TR)remove messages in the unit test for the rumai/ixp/message library.
This release adds support for wmii 3.6, improves the performance of the IXP library, and fixes some bugs.
Thank you:
Incompatible changes:
wmii version 3.6 or newer is now required.
The Rumai::IXP::Agent::FidStream#read_partial
method has been replaced
by Rumai::IXP::Agent::FidStream#read(true)
for efficiency.
The Rumai::IXP::Agent::FidStream#write
method no longer writes to
the beginning of the stream. Instead, it writes to the current position
in the stream.
The Rumai::View#floating_area
method has been renamed to
Rumai::View#floater
for brevity.
New features:
Added several more methods (such as rewind, pos=, eof?, and so on) from
Ruby's IO class to the Rumai::IXP::Agent::FidStream
class.
Added the Rumai::Client#kill
method to simplify client termination.
Bug fixes:
Rumai::Agent#talk
which would cause Rumai to
hang when multiple threads used it.This is the first release of Rumai, the evolution of wmii-irb, which lets you manipulate the wmii window manager through Ruby. Enjoy!
Suraj N. Kurapati
Christoph Blank, Kenneth De Winter, Mattia Gheda, Michael Andrus, Nathan Neff, Sebastian Chmielewski, Simon Hafner
(the ISC license)
Copyright 2006 Suraj N. Kurapati sunaku@gmail.com
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 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.
irb(1), wmiir(1), wmii(1)