rumai 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +23 -0
- data/README +1 -0
- data/Rakefile +58 -0
- data/bin/rumai +38 -0
- data/doc/api/classes/IO.html +120 -0
- data/doc/api/classes/Integer.html +142 -0
- data/doc/api/classes/Integer.src/M000002.html +18 -0
- data/doc/api/classes/Object.html +113 -0
- data/doc/api/classes/Rumai.html +530 -0
- data/doc/api/classes/Rumai.src/M000007.html +18 -0
- data/doc/api/classes/Rumai.src/M000008.html +18 -0
- data/doc/api/classes/Rumai.src/M000009.html +18 -0
- data/doc/api/classes/Rumai.src/M000010.html +18 -0
- data/doc/api/classes/Rumai.src/M000011.html +18 -0
- data/doc/api/classes/Rumai.src/M000012.html +18 -0
- data/doc/api/classes/Rumai.src/M000013.html +18 -0
- data/doc/api/classes/Rumai.src/M000014.html +20 -0
- data/doc/api/classes/Rumai.src/M000015.html +18 -0
- data/doc/api/classes/Rumai.src/M000016.html +18 -0
- data/doc/api/classes/Rumai.src/M000017.html +18 -0
- data/doc/api/classes/Rumai.src/M000018.html +18 -0
- data/doc/api/classes/Rumai.src/M000019.html +18 -0
- data/doc/api/classes/Rumai.src/M000020.html +18 -0
- data/doc/api/classes/Rumai.src/M000021.html +18 -0
- data/doc/api/classes/Rumai.src/M000022.html +18 -0
- data/doc/api/classes/Rumai.src/M000023.html +18 -0
- data/doc/api/classes/Rumai.src/M000024.html +18 -0
- data/doc/api/classes/Rumai.src/M000025.html +18 -0
- data/doc/api/classes/Rumai.src/M000026.html +18 -0
- data/doc/api/classes/Rumai/Area.html +461 -0
- data/doc/api/classes/Rumai/Area.src/M000080.html +19 -0
- data/doc/api/classes/Rumai/Area.src/M000081.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000082.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000083.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000084.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000085.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000086.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000087.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000088.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000089.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000090.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000091.html +22 -0
- data/doc/api/classes/Rumai/Area.src/M000093.html +23 -0
- data/doc/api/classes/Rumai/Area.src/M000094.html +28 -0
- data/doc/api/classes/Rumai/Area.src/M000095.html +18 -0
- data/doc/api/classes/Rumai/Area.src/M000096.html +31 -0
- data/doc/api/classes/Rumai/Chain.html +179 -0
- data/doc/api/classes/Rumai/Chain.src/M000077.html +18 -0
- data/doc/api/classes/Rumai/Chain.src/M000078.html +18 -0
- data/doc/api/classes/Rumai/Chain.src/M000079.html +18 -0
- data/doc/api/classes/Rumai/Client.html +463 -0
- data/doc/api/classes/Rumai/Client.src/M000114.html +18 -0
- data/doc/api/classes/Rumai/Client.src/M000115.html +18 -0
- data/doc/api/classes/Rumai/Client.src/M000116.html +18 -0
- data/doc/api/classes/Rumai/Client.src/M000117.html +39 -0
- data/doc/api/classes/Rumai/Client.src/M000118.html +28 -0
- data/doc/api/classes/Rumai/Client.src/M000119.html +19 -0
- data/doc/api/classes/Rumai/Client.src/M000120.html +18 -0
- data/doc/api/classes/Rumai/Client.src/M000121.html +18 -0
- data/doc/api/classes/Rumai/Client.src/M000122.html +18 -0
- data/doc/api/classes/Rumai/Client.src/M000123.html +19 -0
- data/doc/api/classes/Rumai/Client.src/M000124.html +20 -0
- data/doc/api/classes/Rumai/Client.src/M000125.html +20 -0
- data/doc/api/classes/Rumai/Client.src/M000126.html +22 -0
- data/doc/api/classes/Rumai/Client.src/M000127.html +18 -0
- data/doc/api/classes/Rumai/Client.src/M000128.html +20 -0
- data/doc/api/classes/Rumai/Client.src/M000129.html +18 -0
- data/doc/api/classes/Rumai/Client.src/M000130.html +22 -0
- data/doc/api/classes/Rumai/ClientContainer.html +180 -0
- data/doc/api/classes/Rumai/ClientContainer.src/M000027.html +18 -0
- data/doc/api/classes/Rumai/ClientContainer.src/M000028.html +18 -0
- data/doc/api/classes/Rumai/ClientContainer.src/M000029.html +18 -0
- data/doc/api/classes/Rumai/ExportInstMethods.html +119 -0
- data/doc/api/classes/Rumai/IXP.html +149 -0
- data/doc/api/classes/Rumai/IXP/Agent.html +447 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000046.html +47 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000047.html +44 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000048.html +39 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000049.html +20 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000050.html +22 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000051.html +20 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000052.html +33 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000053.html +19 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000054.html +18 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000055.html +21 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000056.html +20 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000057.html +20 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000058.html +22 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000059.html +23 -0
- data/doc/api/classes/Rumai/IXP/Agent.src/M000060.html +19 -0
- data/doc/api/classes/Rumai/IXP/Agent/FidStream.html +254 -0
- data/doc/api/classes/Rumai/IXP/Agent/FidStream.src/M000062.html +22 -0
- data/doc/api/classes/Rumai/IXP/Agent/FidStream.src/M000063.html +21 -0
- data/doc/api/classes/Rumai/IXP/Agent/FidStream.src/M000064.html +42 -0
- data/doc/api/classes/Rumai/IXP/Agent/FidStream.src/M000065.html +26 -0
- data/doc/api/classes/Rumai/IXP/Agent/FidStream.src/M000066.html +36 -0
- data/doc/api/classes/Rumai/IXP/Agent/MODES.html +130 -0
- data/doc/api/classes/Rumai/IXP/Agent/MODES.src/M000061.html +22 -0
- data/doc/api/classes/Rumai/IXP/Agent/RangedPool.html +203 -0
- data/doc/api/classes/Rumai/IXP/Agent/RangedPool.src/M000068.html +23 -0
- data/doc/api/classes/Rumai/IXP/Agent/RangedPool.src/M000069.html +32 -0
- data/doc/api/classes/Rumai/IXP/Agent/RangedPool.src/M000070.html +20 -0
- data/doc/api/classes/Rumai/IXP/Error.html +117 -0
- data/doc/api/classes/Rumai/IXP/Fcall.html +261 -0
- data/doc/api/classes/Rumai/IXP/Fcall.src/M000071.html +20 -0
- data/doc/api/classes/Rumai/IXP/Fcall.src/M000072.html +25 -0
- data/doc/api/classes/Rumai/IXP/Fcall.src/M000073.html +18 -0
- data/doc/api/classes/Rumai/IXP/Fcall.src/M000074.html +18 -0
- data/doc/api/classes/Rumai/IXP/Qid.html +184 -0
- data/doc/api/classes/Rumai/IXP/Rattach.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rauth.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rclunk.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rcreate.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rerror.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rflush.html +119 -0
- data/doc/api/classes/Rumai/IXP/Ropen.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rread.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rremove.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rstat.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rversion.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rwalk.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rwrite.html +119 -0
- data/doc/api/classes/Rumai/IXP/Rwstat.html +119 -0
- data/doc/api/classes/Rumai/IXP/Stat.html +248 -0
- data/doc/api/classes/Rumai/IXP/Stat.src/M000076.html +18 -0
- data/doc/api/classes/Rumai/IXP/Stream.html +158 -0
- data/doc/api/classes/Rumai/IXP/Stream.src/M000045.html +19 -0
- data/doc/api/classes/Rumai/IXP/Struct.html +257 -0
- data/doc/api/classes/Rumai/IXP/Struct.src/M000030.html +19 -0
- data/doc/api/classes/Rumai/IXP/Struct.src/M000031.html +18 -0
- data/doc/api/classes/Rumai/IXP/Struct.src/M000032.html +18 -0
- data/doc/api/classes/Rumai/IXP/Struct.src/M000033.html +18 -0
- data/doc/api/classes/Rumai/IXP/Struct.src/M000034.html +20 -0
- data/doc/api/classes/Rumai/IXP/Struct.src/M000035.html +57 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field.html +304 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field.src/M000036.html +21 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field.src/M000037.html +21 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field.src/M000038.html +20 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field.src/M000039.html +29 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field.src/M000040.html +18 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field.src/M000041.html +18 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field/CounteeField.html +152 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field/CounteeField.src/M000043.html +24 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field/CounteeField.src/M000044.html +25 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field/CounterField.html +137 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field/CounterField.src/M000042.html +18 -0
- data/doc/api/classes/Rumai/IXP/Tattach.html +120 -0
- data/doc/api/classes/Rumai/IXP/Tauth.html +119 -0
- data/doc/api/classes/Rumai/IXP/Tclunk.html +119 -0
- data/doc/api/classes/Rumai/IXP/Tcreate.html +120 -0
- data/doc/api/classes/Rumai/IXP/Terror.html +145 -0
- data/doc/api/classes/Rumai/IXP/Terror.src/M000075.html +18 -0
- data/doc/api/classes/Rumai/IXP/Tflush.html +119 -0
- data/doc/api/classes/Rumai/IXP/Topen.html +193 -0
- data/doc/api/classes/Rumai/IXP/Tread.html +119 -0
- data/doc/api/classes/Rumai/IXP/Tremove.html +119 -0
- data/doc/api/classes/Rumai/IXP/Tstat.html +119 -0
- data/doc/api/classes/Rumai/IXP/Tversion.html +137 -0
- data/doc/api/classes/Rumai/IXP/Twalk.html +120 -0
- data/doc/api/classes/Rumai/IXP/Twrite.html +120 -0
- data/doc/api/classes/Rumai/IXP/Twstat.html +119 -0
- data/doc/api/classes/Rumai/Node.html +461 -0
- data/doc/api/classes/Rumai/Node.src/M000097.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000098.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000099.html +22 -0
- data/doc/api/classes/Rumai/Node.src/M000100.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000101.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000102.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000103.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000104.html +22 -0
- data/doc/api/classes/Rumai/Node.src/M000105.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000106.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000107.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000108.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000109.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000110.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000111.html +18 -0
- data/doc/api/classes/Rumai/Node.src/M000112.html +20 -0
- data/doc/api/classes/Rumai/Node.src/M000113.html +27 -0
- data/doc/api/classes/Rumai/View.html +436 -0
- data/doc/api/classes/Rumai/View.src/M000131.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000132.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000133.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000134.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000135.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000136.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000137.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000138.html +28 -0
- data/doc/api/classes/Rumai/View.src/M000139.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000140.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000141.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000142.html +18 -0
- data/doc/api/classes/Rumai/View.src/M000143.html +29 -0
- data/doc/api/classes/Rumai/View.src/M000144.html +20 -0
- data/doc/api/classes/Rumai/View.src/M000145.html +33 -0
- data/doc/api/classes/Rumai/View.src/M000146.html +50 -0
- data/doc/api/classes/String.html +169 -0
- data/doc/api/classes/String.src/M000005.html +18 -0
- data/doc/api/classes/String.src/M000006.html +19 -0
- data/doc/api/classes/StringIO.html +120 -0
- data/doc/api/classes/Time.html +163 -0
- data/doc/api/classes/Time.src/M000003.html +18 -0
- data/doc/api/classes/Time.src/M000004.html +18 -0
- data/doc/api/created.rid +1 -0
- data/doc/api/files/lib/rumai/fs_rb.html +115 -0
- data/doc/api/files/lib/rumai/ixp/message_rb.html +120 -0
- data/doc/api/files/lib/rumai/ixp/message_spec_rb.html +175 -0
- data/doc/api/files/lib/rumai/ixp/message_spec_rb.src/M000001.html +37 -0
- data/doc/api/files/lib/rumai/ixp/transport_rb.html +115 -0
- data/doc/api/files/lib/rumai/ixp_rb.html +116 -0
- data/doc/api/files/lib/rumai/nfo_rb.html +107 -0
- data/doc/api/files/lib/rumai/wm_rb.html +115 -0
- data/doc/api/files/lib/rumai_rb.html +115 -0
- data/doc/api/fr_class_index.html +82 -0
- data/doc/api/fr_file_index.html +34 -0
- data/doc/api/fr_method_index.html +172 -0
- data/doc/api/index.html +24 -0
- data/doc/api/rdoc-style.css +208 -0
- data/doc/guide.erb +390 -0
- data/doc/guide.html +2035 -0
- data/doc/index.html +2035 -0
- data/lib/rumai.rb +9 -0
- data/lib/rumai/fs.rb +170 -0
- data/lib/rumai/ixp.rb +9 -0
- data/lib/rumai/ixp/message.rb +642 -0
- data/lib/rumai/ixp/message_spec.rb +247 -0
- data/lib/rumai/ixp/transport.rb +382 -0
- data/lib/rumai/nfo.rb +24 -0
- data/lib/rumai/wm.rb +780 -0
- metadata +320 -0
data/lib/rumai/nfo.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Project information.
|
|
2
|
+
#--
|
|
3
|
+
# Copyright 2007 Suraj N. Kurapati
|
|
4
|
+
# See the file named LICENSE for details.
|
|
5
|
+
|
|
6
|
+
module Rumai
|
|
7
|
+
NFO = {
|
|
8
|
+
:name => 'Rumai',
|
|
9
|
+
:version => '1.0.0',
|
|
10
|
+
:release => '2008-01-26',
|
|
11
|
+
:website => 'http://rumai.rubyforge.org',
|
|
12
|
+
:home => File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class << NFO
|
|
16
|
+
# Returns the name and version.
|
|
17
|
+
def to_s
|
|
18
|
+
self[:name] + ' ' + self[:version]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# throw an exception instead of returning nil
|
|
22
|
+
alias [] fetch
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/rumai/wm.rb
ADDED
|
@@ -0,0 +1,780 @@
|
|
|
1
|
+
# Abstractions for the window manager.
|
|
2
|
+
#--
|
|
3
|
+
# Copyright 2006 Suraj N. Kurapati
|
|
4
|
+
# See the file named LICENSE for details.
|
|
5
|
+
|
|
6
|
+
require 'fs'
|
|
7
|
+
require 'enumerator'
|
|
8
|
+
|
|
9
|
+
class Object
|
|
10
|
+
# prevent these deprecated properties from clashing with our usage below
|
|
11
|
+
undef id, type
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module Rumai
|
|
15
|
+
##
|
|
16
|
+
#
|
|
17
|
+
# access to global WM state
|
|
18
|
+
#
|
|
19
|
+
##
|
|
20
|
+
|
|
21
|
+
ROOT = Node.new '/'
|
|
22
|
+
|
|
23
|
+
# Returns the root of IXP file system hierarchy.
|
|
24
|
+
def fs
|
|
25
|
+
ROOT
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns the current set of tags.
|
|
29
|
+
def tags
|
|
30
|
+
fs.tag.entries.sort - %w[sel]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the current set of views.
|
|
34
|
+
def views
|
|
35
|
+
tags.map! {|t| View.new t}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module ClientContainer
|
|
39
|
+
# see definition below!
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
include ClientContainer
|
|
43
|
+
# Returns the IDs of the current set of clients.
|
|
44
|
+
def client_ids
|
|
45
|
+
fs.client.entries - %w[sel]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns the name of the currently focused tag.
|
|
49
|
+
def curr_tag
|
|
50
|
+
curr_view.id
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns the name of the next tag.
|
|
54
|
+
def next_tag
|
|
55
|
+
next_view.id
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Returns the name of the previous tag.
|
|
59
|
+
def prev_tag
|
|
60
|
+
prev_view.id
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
#
|
|
66
|
+
# multiple client grouping: allows you to group a set of clients
|
|
67
|
+
# together and perform operations on all of them simultaneously.
|
|
68
|
+
#
|
|
69
|
+
##
|
|
70
|
+
|
|
71
|
+
GROUPING_TAG = '@'
|
|
72
|
+
|
|
73
|
+
# Returns a list of all grouped clients in
|
|
74
|
+
# the currently focused view. If there are
|
|
75
|
+
# no grouped clients, then the currently
|
|
76
|
+
# focused client is returned in the list.
|
|
77
|
+
def grouping
|
|
78
|
+
list = curr_view.clients.select {|c| c.group? }
|
|
79
|
+
list << curr_client if list.empty? and curr_client.exist?
|
|
80
|
+
list
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
##
|
|
85
|
+
#
|
|
86
|
+
# abstraction of WM components
|
|
87
|
+
#
|
|
88
|
+
##
|
|
89
|
+
|
|
90
|
+
# NOTE: Inheritors must override the 'chain' method.
|
|
91
|
+
module Chain
|
|
92
|
+
# Returns an array of objects related to this one.
|
|
93
|
+
def chain
|
|
94
|
+
[self]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Returns the object after this one in the chain.
|
|
98
|
+
def next
|
|
99
|
+
sibling(+1)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Returns the object before this one in the chain.
|
|
103
|
+
def prev
|
|
104
|
+
sibling(-1)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def sibling aOffset
|
|
110
|
+
arr = chain
|
|
111
|
+
|
|
112
|
+
if pos = arr.index(self)
|
|
113
|
+
arr[(pos + aOffset) % arr.length]
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# The basic building block of the WM hierarchy.
|
|
119
|
+
#
|
|
120
|
+
# NOTE: Inheritors must have a 'current' class method.
|
|
121
|
+
# NOTE: Inheritors must override the 'focus' method.
|
|
122
|
+
#
|
|
123
|
+
module WidgetImpl #:nodoc:
|
|
124
|
+
attr_reader :id
|
|
125
|
+
|
|
126
|
+
def == aOther
|
|
127
|
+
@id == aOther.id
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Checks if this widget currently has focus.
|
|
131
|
+
def current?
|
|
132
|
+
self == self.class.curr
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
alias focus? current?
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# A widget that has a corresponding representation in the IXP file system.
|
|
139
|
+
class WidgetNode < Node #:nodoc:
|
|
140
|
+
include WidgetImpl
|
|
141
|
+
|
|
142
|
+
def initialize aId, aPathPrefix
|
|
143
|
+
super "#{aPathPrefix}/#{aId}"
|
|
144
|
+
|
|
145
|
+
if aId.to_s == 'sel' and ctl.exist?
|
|
146
|
+
@id = ctl.read
|
|
147
|
+
@path = File.join(File.dirname(@path), @id)
|
|
148
|
+
else
|
|
149
|
+
@id = File.basename(@path)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# A graphical program that is running in your current X Windows session.
|
|
155
|
+
class Client < WidgetNode
|
|
156
|
+
def initialize aClientId
|
|
157
|
+
super aClientId, '/client'
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Returns the currently focused client.
|
|
161
|
+
def self.curr
|
|
162
|
+
new :sel
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
include Chain
|
|
166
|
+
# Returns a list of clients in the current view.
|
|
167
|
+
def chain
|
|
168
|
+
View.curr.clients
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
##
|
|
172
|
+
#
|
|
173
|
+
# WM operations
|
|
174
|
+
#
|
|
175
|
+
##
|
|
176
|
+
|
|
177
|
+
# Focuses this client within the given view.
|
|
178
|
+
def focus aView = nil
|
|
179
|
+
if exist? and not focus?
|
|
180
|
+
(aView ? [aView] : self.views).each do |v|
|
|
181
|
+
if a = self.area(v)
|
|
182
|
+
v.focus
|
|
183
|
+
a.focus
|
|
184
|
+
|
|
185
|
+
# slide focus from the current client onto this client
|
|
186
|
+
arr = a.client_ids
|
|
187
|
+
src = arr.index Client.curr.id
|
|
188
|
+
dst = arr.index @id
|
|
189
|
+
|
|
190
|
+
distance = (src - dst).abs
|
|
191
|
+
direction = src < dst ? :down : :up
|
|
192
|
+
|
|
193
|
+
distance.times do
|
|
194
|
+
v.ctl.write "select #{direction}"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
break
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Sends this client to the given destination within the given view.
|
|
204
|
+
def send aAreaOrId, aView = View.curr
|
|
205
|
+
if aAreaOrId.to_s != 'toggle'
|
|
206
|
+
# XXX: it is an error to send a floating client directly to a
|
|
207
|
+
# managed area, so we gotta "ground" it first and then send it
|
|
208
|
+
# to the desired managed area. John-Galt will fix this someday.
|
|
209
|
+
if area(aView).float?
|
|
210
|
+
aView.ctl.write "send #{@id} toggle"
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
dst = area_to_id(aAreaOrId)
|
|
215
|
+
aView.ctl.write "send #{@id} #{dst}"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Swaps this client with the given destination within the given view.
|
|
219
|
+
def swap aAreaOrId, aView = View.curr
|
|
220
|
+
dst = area_to_id(aAreaOrId)
|
|
221
|
+
aView.ctl.write "swap #{@id} #{dst}"
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
##
|
|
225
|
+
#
|
|
226
|
+
# WM hierarchy
|
|
227
|
+
#
|
|
228
|
+
##
|
|
229
|
+
|
|
230
|
+
# Returns the area that contains this client within the given view.
|
|
231
|
+
def area aView = View.curr
|
|
232
|
+
aView.area_of_client self
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Returns the views that contain this client.
|
|
236
|
+
def views
|
|
237
|
+
tags.map! {|t| View.new t}
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
##
|
|
241
|
+
#
|
|
242
|
+
# tag manipulations
|
|
243
|
+
#
|
|
244
|
+
##
|
|
245
|
+
|
|
246
|
+
TAG_DELIMITER = '+'.freeze
|
|
247
|
+
|
|
248
|
+
# Returns the tags associated with this client.
|
|
249
|
+
def tags
|
|
250
|
+
self[:tags].read.split TAG_DELIMITER
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Modifies the tags associated with this client.
|
|
254
|
+
def tags= *aTags
|
|
255
|
+
arr = aTags.flatten.compact.uniq
|
|
256
|
+
self[:tags].write arr.join(TAG_DELIMITER)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Evaluates the given block within the
|
|
260
|
+
# context of this client's list of tags.
|
|
261
|
+
def with_tags &aBlock
|
|
262
|
+
arr = self.tags
|
|
263
|
+
arr.instance_eval(&aBlock)
|
|
264
|
+
self.tags = arr
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Adds the given tags to this client.
|
|
268
|
+
def tag *aTags
|
|
269
|
+
with_tags do
|
|
270
|
+
concat aTags
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Removes the given tags from this client.
|
|
275
|
+
def untag *aTags
|
|
276
|
+
with_tags do
|
|
277
|
+
aTags.flatten.each do |tag|
|
|
278
|
+
delete tag.to_s
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
##
|
|
284
|
+
#
|
|
285
|
+
# multiple client grouping
|
|
286
|
+
#
|
|
287
|
+
##
|
|
288
|
+
|
|
289
|
+
# Checks if this client is included in the current grouping.
|
|
290
|
+
def group?
|
|
291
|
+
tags.include? GROUPING_TAG
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Adds this client to the current grouping.
|
|
295
|
+
def group
|
|
296
|
+
with_tags do
|
|
297
|
+
push GROUPING_TAG
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Removes this client to the current grouping.
|
|
302
|
+
def ungroup
|
|
303
|
+
untag GROUPING_TAG
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# Toggles the presence of this client in the current grouping.
|
|
307
|
+
def toggle_group
|
|
308
|
+
if group?
|
|
309
|
+
ungroup
|
|
310
|
+
else
|
|
311
|
+
group
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
private
|
|
316
|
+
|
|
317
|
+
def area_to_id aAreaOrId
|
|
318
|
+
if aAreaOrId.respond_to? :id
|
|
319
|
+
# XXX: +1 until John-Galt fixes this: right now, index 1
|
|
320
|
+
# is floating area; but ~ (0) should be floating area.
|
|
321
|
+
aAreaOrId.id+1
|
|
322
|
+
else
|
|
323
|
+
aAreaOrId
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# NOTE: Inheritors should override the 'client_ids' method.
|
|
329
|
+
module ClientContainer
|
|
330
|
+
# Returns the IDs of the clients in this container.
|
|
331
|
+
def client_ids
|
|
332
|
+
[]
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
# Returns the clients contained in this container.
|
|
336
|
+
def clients
|
|
337
|
+
client_ids.map! {|i| Client.new i}
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# multiple client grouping
|
|
341
|
+
%w[group ungroup toggle_group].each do |meth|
|
|
342
|
+
define_method meth do
|
|
343
|
+
clients.each do |c|
|
|
344
|
+
c.__send__ meth
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Returns all grouped clients in this container.
|
|
350
|
+
def grouping
|
|
351
|
+
clients.select {|c| c.group? }
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# A region that contains clients. This can be either
|
|
356
|
+
# the floating area or a column in the managed area.
|
|
357
|
+
class Area
|
|
358
|
+
attr_reader :view
|
|
359
|
+
|
|
360
|
+
# aView:: the view which contains this area.
|
|
361
|
+
def initialize aAreaId, aView = View.curr
|
|
362
|
+
@id = aAreaId.to_i
|
|
363
|
+
@view = aView
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Checks if this area is the floating area.
|
|
367
|
+
def float?
|
|
368
|
+
@id == 0
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Checks if this area is a column in the managed area.
|
|
372
|
+
def column?
|
|
373
|
+
not float?
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
include WidgetImpl
|
|
377
|
+
# Returns the currently focused area.
|
|
378
|
+
def self.curr
|
|
379
|
+
View.curr.area_of_client Client.curr
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
include Chain
|
|
383
|
+
def chain
|
|
384
|
+
@view.areas
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Checks if this object exists in the chain.
|
|
388
|
+
def exist?
|
|
389
|
+
chain.include? self
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
include ClientContainer
|
|
393
|
+
# Returns the IDs of the clients in this area.
|
|
394
|
+
def client_ids
|
|
395
|
+
@view.client_ids ctl_id
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
include Enumerable
|
|
399
|
+
# Iterates through each client in this container.
|
|
400
|
+
def each &aBlock
|
|
401
|
+
clients.each(&aBlock)
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# Sets the layout of clients in this column.
|
|
405
|
+
def layout= aMode
|
|
406
|
+
@view.ctl.write "colmode #{ctl_id} #{aMode}"
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
##
|
|
410
|
+
#
|
|
411
|
+
# WM operations
|
|
412
|
+
#
|
|
413
|
+
##
|
|
414
|
+
|
|
415
|
+
# Puts focus on this area.
|
|
416
|
+
def focus
|
|
417
|
+
@view.ctl.write "select #{ctl_id}"
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
##
|
|
421
|
+
#
|
|
422
|
+
# array abstraction: area is an array of clients
|
|
423
|
+
#
|
|
424
|
+
##
|
|
425
|
+
|
|
426
|
+
# Returns the number of clients in this area.
|
|
427
|
+
def length
|
|
428
|
+
client_ids.length
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
# Inserts the given clients at the bottom of this area.
|
|
432
|
+
def push *aClients
|
|
433
|
+
if target = clients.last
|
|
434
|
+
target.focus
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
insert aClients
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
alias << push
|
|
441
|
+
|
|
442
|
+
# Inserts the given clients after the currently focused client in this area.
|
|
443
|
+
def insert *aClients
|
|
444
|
+
aClients.flatten!
|
|
445
|
+
return if aClients.empty?
|
|
446
|
+
|
|
447
|
+
aClients.each do |c|
|
|
448
|
+
import_client c
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
# Inserts the given clients at the top of this area.
|
|
453
|
+
def unshift *aClients
|
|
454
|
+
aClients.flatten!
|
|
455
|
+
return if aClients.empty?
|
|
456
|
+
|
|
457
|
+
if target = clients.first
|
|
458
|
+
target.focus
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
aClients.each do |c|
|
|
462
|
+
import_client c
|
|
463
|
+
c.send :up if target
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
# Concatenates the given area to the bottom of this area.
|
|
468
|
+
def concat aArea
|
|
469
|
+
push aArea.clients
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
# Ensures that this area has at most the given number of clients.
|
|
473
|
+
# Areas to the right of this one serve as a buffer into which excess
|
|
474
|
+
# clients are evicted and from which deficit clients are imported.
|
|
475
|
+
def length= aMaxClients
|
|
476
|
+
return unless aMaxClients > 0
|
|
477
|
+
len, out = length, fringe
|
|
478
|
+
|
|
479
|
+
if len > aMaxClients
|
|
480
|
+
out.unshift clients[aMaxClients..-1].reverse
|
|
481
|
+
|
|
482
|
+
elsif len < aMaxClients
|
|
483
|
+
until (diff = aMaxClients - length) == 0
|
|
484
|
+
immigrants = out.clients.first(diff)
|
|
485
|
+
break if immigrants.empty?
|
|
486
|
+
|
|
487
|
+
push immigrants
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
private
|
|
493
|
+
|
|
494
|
+
# Makes the ID usable in wmii's /ctl commands.
|
|
495
|
+
def ctl_id
|
|
496
|
+
float? ? '~' : @id
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
# Moves the given client into this area.
|
|
500
|
+
def import_client c
|
|
501
|
+
if exist?
|
|
502
|
+
c.send self
|
|
503
|
+
|
|
504
|
+
else
|
|
505
|
+
# move the client to the nearest existing column
|
|
506
|
+
src = c.area
|
|
507
|
+
dst = chain.last
|
|
508
|
+
|
|
509
|
+
c.send dst unless src == dst
|
|
510
|
+
|
|
511
|
+
# slide the client over to this column
|
|
512
|
+
c.send :right
|
|
513
|
+
@id = dst.id.next
|
|
514
|
+
|
|
515
|
+
raise 'column should exist now' unless exist?
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
# Returns the next area, which may or may not exist.
|
|
520
|
+
def fringe
|
|
521
|
+
Area.new @id.next, @view
|
|
522
|
+
end
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
# The visualization of a tag.
|
|
526
|
+
class View < WidgetNode
|
|
527
|
+
include WidgetImpl
|
|
528
|
+
# Returns the currently focused view.
|
|
529
|
+
def self.curr
|
|
530
|
+
new :sel
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
# Focuses this view.
|
|
534
|
+
def focus
|
|
535
|
+
Rumai.fs.ctl.write "view #{@id}"
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
include Chain
|
|
539
|
+
def chain
|
|
540
|
+
Rumai.views
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
include ClientContainer
|
|
544
|
+
# Returns the IDs of the clients contained
|
|
545
|
+
# in the given area within this view.
|
|
546
|
+
def client_ids aAreaId = '\S+'
|
|
547
|
+
manifest.scan(/^#{aAreaId} (0x\S+)/).flatten
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
include Enumerable
|
|
551
|
+
# Iterates through each area in this view.
|
|
552
|
+
def each &aBlock
|
|
553
|
+
areas.each(&aBlock)
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
def initialize aViewId
|
|
557
|
+
super aViewId, '/tag'
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
# Returns the manifest of all areas and clients in this view.
|
|
561
|
+
def manifest
|
|
562
|
+
index.read || ''
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
##
|
|
566
|
+
#
|
|
567
|
+
# WM hierarchy
|
|
568
|
+
#
|
|
569
|
+
##
|
|
570
|
+
|
|
571
|
+
# Returns the area which contains the given client in this view.
|
|
572
|
+
def area_of_client aClientOrId
|
|
573
|
+
arg =
|
|
574
|
+
if aClientOrId.respond_to? :id
|
|
575
|
+
aClientOrId.id
|
|
576
|
+
else
|
|
577
|
+
aClientOrId
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
manifest =~ /^(\S+) #{arg}/
|
|
581
|
+
if areaId = $1
|
|
582
|
+
Area.new areaId, self
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
# Returns the IDs of all areas in this view.
|
|
587
|
+
def area_ids
|
|
588
|
+
manifest.scan(/^# (\S+)/).flatten
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
# Returns all areas in this view.
|
|
592
|
+
def areas
|
|
593
|
+
area_ids.map! {|i| Area.new i, self}
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
# Returns the floating area of this view.
|
|
597
|
+
def floating_area
|
|
598
|
+
areas.first
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
# Returns all columns (managed areas) in this view.
|
|
602
|
+
def columns
|
|
603
|
+
areas[1..-1]
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
# Resiliently iterates through possibly destructive changes to
|
|
607
|
+
# each column. That is, if the given block creates new
|
|
608
|
+
# columns, then those will also be processed in the iteration.
|
|
609
|
+
def each_column aStartingColumnId = 1
|
|
610
|
+
i = aStartingColumnId
|
|
611
|
+
loop do
|
|
612
|
+
a = Area.new i, self
|
|
613
|
+
|
|
614
|
+
if a.exist?
|
|
615
|
+
yield a
|
|
616
|
+
else
|
|
617
|
+
break
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
i += 1
|
|
621
|
+
end
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
##
|
|
625
|
+
#
|
|
626
|
+
# visual arrangement of clients
|
|
627
|
+
#
|
|
628
|
+
##
|
|
629
|
+
|
|
630
|
+
# Arranges the clients in this view, while maintaining
|
|
631
|
+
# their relative order, in the tiling fashion of
|
|
632
|
+
# LarsWM. Only the first client in the primary column
|
|
633
|
+
# is kept; all others are evicted to the *top* of the
|
|
634
|
+
# secondary column. Any subsequent columns are
|
|
635
|
+
# squeezed into the *bottom* of the secondary column.
|
|
636
|
+
def arrange_as_larswm
|
|
637
|
+
float, main, *extra = areas
|
|
638
|
+
main.length = 1
|
|
639
|
+
squeeze extra
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
# Arranges the clients in this view, while maintaining
|
|
643
|
+
# their relative order, in a (at best) square grid.
|
|
644
|
+
def arrange_in_grid aMaxClientsPerColumn = nil
|
|
645
|
+
# compute client distribution
|
|
646
|
+
unless aMaxClientsPerColumn
|
|
647
|
+
numClients = num_managed_clients
|
|
648
|
+
return unless numClients > 0
|
|
649
|
+
|
|
650
|
+
numColumns = Math.sqrt(numClients)
|
|
651
|
+
aMaxClientsPerColumn = (numClients / numColumns).round
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
return unless aMaxClientsPerColumn > 1
|
|
655
|
+
|
|
656
|
+
# apply the distribution
|
|
657
|
+
each_column do |a|
|
|
658
|
+
a.length = aMaxClientsPerColumn
|
|
659
|
+
a.layout = :default
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
# Arranges the clients in this view, while maintaining their relative order,
|
|
664
|
+
# in a (at best) equilateral triangle. However, the resulting arrangement
|
|
665
|
+
# appears like a diamond because wmii does not waste screen space.
|
|
666
|
+
def arrange_in_diamond
|
|
667
|
+
numClients = num_managed_clients
|
|
668
|
+
return unless numClients > 1
|
|
669
|
+
|
|
670
|
+
# determine dimensions of the rising sub-triangle
|
|
671
|
+
rise = numClients / 2
|
|
672
|
+
|
|
673
|
+
span = sum = 0
|
|
674
|
+
1.upto rise do |h|
|
|
675
|
+
if sum + h > rise
|
|
676
|
+
break
|
|
677
|
+
else
|
|
678
|
+
sum += h
|
|
679
|
+
span += 1
|
|
680
|
+
end
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
peak = numClients - (sum * 2)
|
|
684
|
+
|
|
685
|
+
# describe the overall triangle as a sequence of heights
|
|
686
|
+
riseSeq = (1..span).to_a
|
|
687
|
+
fallSeq = riseSeq.reverse
|
|
688
|
+
|
|
689
|
+
heights = riseSeq
|
|
690
|
+
heights << peak if peak > 0
|
|
691
|
+
heights.concat fallSeq
|
|
692
|
+
|
|
693
|
+
# apply the heights
|
|
694
|
+
each_column do |col|
|
|
695
|
+
if h = heights.shift
|
|
696
|
+
col.length = h
|
|
697
|
+
col.layout = :default
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
private
|
|
703
|
+
|
|
704
|
+
# Returns the number of clients in the non-floating areas of this view.
|
|
705
|
+
def num_managed_clients
|
|
706
|
+
manifest.scan(/^\d+ 0x/).length
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
# Smashes the given list of areas into the first one.
|
|
710
|
+
# The relative ordering of clients is preserved.
|
|
711
|
+
def squeeze aAreas
|
|
712
|
+
aAreas.reverse.each_cons(2) do |src, dst|
|
|
713
|
+
dst.concat src
|
|
714
|
+
end
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
##
|
|
720
|
+
#
|
|
721
|
+
# shortcuts for interactive WM manipulation (via IRB)
|
|
722
|
+
#
|
|
723
|
+
##
|
|
724
|
+
|
|
725
|
+
# provide easy access to container state information
|
|
726
|
+
[Client, Area, View].each do |c|
|
|
727
|
+
c.extend ExportInstMethods
|
|
728
|
+
end
|
|
729
|
+
|
|
730
|
+
def curr_client
|
|
731
|
+
Client.curr
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
def next_client
|
|
735
|
+
curr_client.next
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
def prev_client
|
|
739
|
+
curr_client.prev
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
def curr_area
|
|
743
|
+
Area.curr
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
def next_area
|
|
747
|
+
curr_area.next
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
def prev_area
|
|
751
|
+
curr_area.prev
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
def curr_view
|
|
755
|
+
View.curr
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
def next_view
|
|
759
|
+
curr_view.next
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
def prev_view
|
|
763
|
+
curr_view.prev
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
def focus_client aId
|
|
767
|
+
Client.focus(aId)
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
def focus_area aId
|
|
771
|
+
Area.focus(aId)
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
def focus_view aId
|
|
775
|
+
View.focus(aId)
|
|
776
|
+
end
|
|
777
|
+
|
|
778
|
+
# provide easy access to this module's instance methods
|
|
779
|
+
module_function(*instance_methods)
|
|
780
|
+
end
|