rumai 2.0.2 → 2.1.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/CREDITS +2 -0
- data/bin/rumai +20 -8
- data/doc/api/classes/IO.html +72 -0
- data/doc/api/classes/Integer.html +110 -0
- data/doc/api/classes/Object.html +60 -0
- data/doc/api/classes/Rumai.html +867 -0
- data/doc/api/classes/Rumai/Area.html +836 -0
- data/doc/api/classes/Rumai/Chain.html +197 -0
- data/doc/api/classes/Rumai/Client.html +865 -0
- data/doc/api/classes/Rumai/ClientContainer.html +191 -0
- data/doc/api/classes/Rumai/ExportInstanceMethods.html +69 -0
- data/doc/api/classes/Rumai/IXP.html +131 -0
- data/doc/api/classes/Rumai/IXP/Agent.html +836 -0
- data/doc/api/classes/Rumai/IXP/Agent/FidStream.html +456 -0
- data/doc/api/classes/Rumai/IXP/Agent/MODES.html +108 -0
- data/doc/api/classes/Rumai/IXP/Agent/RangedPool.html +241 -0
- data/doc/api/classes/Rumai/IXP/Error.html +67 -0
- data/doc/api/classes/Rumai/IXP/Fcall.html +323 -0
- data/doc/api/classes/Rumai/IXP/Qid.html +153 -0
- data/doc/api/classes/Rumai/IXP/Rattach.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rauth.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rclunk.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rcreate.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rerror.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rflush.html +67 -0
- data/doc/api/classes/Rumai/IXP/Ropen.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rread.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rremove.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rstat.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rversion.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rwalk.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rwrite.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rwstat.html +67 -0
- data/doc/api/classes/Rumai/IXP/Stat.html +252 -0
- data/doc/api/classes/Rumai/IXP/Stream.html +131 -0
- data/doc/api/classes/Rumai/IXP/Struct.html +315 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field.html +415 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field/CounteeField.html +153 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field/CounterField.html +104 -0
- data/doc/api/classes/Rumai/IXP/Tattach.html +68 -0
- data/doc/api/classes/Rumai/IXP/Tauth.html +67 -0
- data/doc/api/classes/Rumai/IXP/Tclunk.html +67 -0
- data/doc/api/classes/Rumai/IXP/Tcreate.html +68 -0
- data/doc/api/classes/Rumai/IXP/Terror.html +110 -0
- data/doc/api/classes/Rumai/IXP/Tflush.html +67 -0
- data/doc/api/classes/Rumai/IXP/Topen.html +165 -0
- data/doc/api/classes/Rumai/IXP/Tread.html +67 -0
- data/doc/api/classes/Rumai/IXP/Tremove.html +67 -0
- data/doc/api/classes/Rumai/IXP/Tstat.html +67 -0
- data/doc/api/classes/Rumai/IXP/Tversion.html +86 -0
- data/doc/api/classes/Rumai/IXP/Twalk.html +68 -0
- data/doc/api/classes/Rumai/IXP/Twrite.html +68 -0
- data/doc/api/classes/Rumai/IXP/Twstat.html +67 -0
- data/doc/api/classes/Rumai/Node.html +817 -0
- data/doc/api/classes/Rumai/View.html +818 -0
- data/doc/api/classes/Rumai/WidgetImpl.html +65 -0
- data/doc/api/classes/Rumai/WidgetNode.html +68 -0
- data/doc/api/classes/String.html +163 -0
- data/doc/api/classes/StringIO.html +72 -0
- data/doc/api/classes/Time.html +156 -0
- data/doc/api/created.rid +1 -0
- data/doc/api/css/main.css +263 -0
- data/doc/api/css/panel.css +383 -0
- data/doc/api/css/reset.css +53 -0
- data/doc/api/files/CREDITS.html +64 -0
- data/doc/api/files/LICENSE.html +76 -0
- data/doc/api/files/lib/rumai/fs_rb.html +75 -0
- data/doc/api/files/lib/rumai/ixp/message_rb.html +91 -0
- data/doc/api/files/lib/rumai/ixp/transport_rb.html +75 -0
- data/doc/api/files/lib/rumai/ixp_rb.html +69 -0
- data/doc/api/files/lib/rumai/wm_rb.html +77 -0
- data/doc/api/files/lib/rumai_rb.html +65 -0
- data/doc/api/i/arrows.png +0 -0
- data/doc/api/i/results_bg.png +0 -0
- data/doc/api/i/tree_bg.png +0 -0
- data/doc/api/index.html +14 -18
- data/doc/api/js/jquery-1.3.2.min.js +19 -0
- data/doc/api/js/jquery-effect.js +593 -0
- data/doc/api/js/main.js +22 -0
- data/doc/api/js/searchdoc.js +605 -0
- data/doc/api/panel/index.html +63 -0
- data/doc/api/panel/search_index.js +1 -0
- data/doc/api/panel/tree.js +1 -0
- data/doc/history.erb +41 -16
- data/doc/index.erb +14 -11
- data/doc/index.xhtml +519 -846
- data/doc/intro.erb +33 -32
- data/doc/setup.erb +14 -13
- data/doc/usage.erb +69 -35
- data/lib/rumai.rb +13 -5
- data/lib/rumai/fs.rb +71 -27
- data/lib/rumai/ixp.rb +4 -0
- data/lib/rumai/ixp/message.rb +178 -81
- data/lib/rumai/ixp/transport.rb +144 -91
- data/lib/rumai/wm.rb +717 -593
- data/rakefile +14 -0
- data/test/rumai/ixp/message.rb +42 -54
- metadata +110 -89
- data/Rakefile +0 -8
- data/doc/api/IO.html +0 -53
- data/doc/api/Integer.html +0 -102
- data/doc/api/Object.html +0 -23
- data/doc/api/Rumai.html +0 -1218
- data/doc/api/Rumai/Area.html +0 -1088
- data/doc/api/Rumai/Chain.html +0 -230
- data/doc/api/Rumai/Client.html +0 -1264
- data/doc/api/Rumai/ClientContainer.html +0 -227
- data/doc/api/Rumai/ExportInstMethods.html +0 -115
- data/doc/api/Rumai/IXP.html +0 -23
- data/doc/api/Rumai/IXP/Agent.html +0 -1222
- data/doc/api/Rumai/IXP/Agent/FidStream.html +0 -602
- data/doc/api/Rumai/IXP/Agent/RangedPool.html +0 -263
- data/doc/api/Rumai/IXP/Error.html +0 -32
- data/doc/api/Rumai/IXP/Fcall.html +0 -398
- data/doc/api/Rumai/IXP/Qid.html +0 -99
- data/doc/api/Rumai/IXP/Rattach.html +0 -71
- data/doc/api/Rumai/IXP/Rauth.html +0 -71
- data/doc/api/Rumai/IXP/Rclunk.html +0 -71
- data/doc/api/Rumai/IXP/Rcreate.html +0 -71
- data/doc/api/Rumai/IXP/Rerror.html +0 -71
- data/doc/api/Rumai/IXP/Rflush.html +0 -71
- data/doc/api/Rumai/IXP/Ropen.html +0 -71
- data/doc/api/Rumai/IXP/Rread.html +0 -71
- data/doc/api/Rumai/IXP/Rremove.html +0 -71
- data/doc/api/Rumai/IXP/Rstat.html +0 -71
- data/doc/api/Rumai/IXP/Rversion.html +0 -71
- data/doc/api/Rumai/IXP/Rwalk.html +0 -71
- data/doc/api/Rumai/IXP/Rwrite.html +0 -71
- data/doc/api/Rumai/IXP/Rwstat.html +0 -71
- data/doc/api/Rumai/IXP/Stat.html +0 -188
- data/doc/api/Rumai/IXP/Stream.html +0 -112
- data/doc/api/Rumai/IXP/Struct.html +0 -348
- data/doc/api/Rumai/IXP/Struct/ClassField.html +0 -177
- data/doc/api/Rumai/IXP/Struct/Field.html +0 -549
- data/doc/api/Rumai/IXP/Struct/Field/CounteeField.html +0 -175
- data/doc/api/Rumai/IXP/Struct/Field/CounterField.html +0 -95
- data/doc/api/Rumai/IXP/Struct/Integer8Field.html +0 -181
- data/doc/api/Rumai/IXP/Struct/StringField.html +0 -128
- data/doc/api/Rumai/IXP/Tattach.html +0 -71
- data/doc/api/Rumai/IXP/Tauth.html +0 -71
- data/doc/api/Rumai/IXP/Tclunk.html +0 -71
- data/doc/api/Rumai/IXP/Tcreate.html +0 -71
- data/doc/api/Rumai/IXP/Terror.html +0 -156
- data/doc/api/Rumai/IXP/Tflush.html +0 -71
- data/doc/api/Rumai/IXP/Topen.html +0 -113
- data/doc/api/Rumai/IXP/Tread.html +0 -71
- data/doc/api/Rumai/IXP/Tremove.html +0 -71
- data/doc/api/Rumai/IXP/Tstat.html +0 -71
- data/doc/api/Rumai/IXP/Tversion.html +0 -83
- data/doc/api/Rumai/IXP/Twalk.html +0 -71
- data/doc/api/Rumai/IXP/Twrite.html +0 -71
- data/doc/api/Rumai/IXP/Twstat.html +0 -71
- data/doc/api/Rumai/Node.html +0 -1139
- data/doc/api/Rumai/View.html +0 -1280
- data/doc/api/Rumai/WidgetImpl.html +0 -196
- data/doc/api/Rumai/WidgetNode.html +0 -184
- data/doc/api/String.html +0 -180
- data/doc/api/StringIO.html +0 -53
- data/doc/api/Time.html +0 -175
- data/doc/api/all-methods.html +0 -1436
- data/doc/api/all-namespaces.html +0 -140
- data/doc/api/app.js +0 -18
- data/doc/api/jquery.js +0 -11
- data/doc/api/readme.html +0 -38
- data/doc/api/style.css +0 -68
- data/doc/api/syntax_highlight.css +0 -21
- data/doc/theory.erb +0 -3
data/lib/rumai/wm.rb
CHANGED
|
@@ -1,770 +1,894 @@
|
|
|
1
1
|
# Abstractions for the window manager.
|
|
2
|
+
#--
|
|
3
|
+
# Copyright 2006 Suraj N. Kurapati
|
|
4
|
+
# See the LICENSE file for details.
|
|
5
|
+
#++
|
|
2
6
|
|
|
3
7
|
require 'rumai/fs'
|
|
4
8
|
require 'enumerator'
|
|
5
9
|
|
|
6
|
-
class Object
|
|
7
|
-
# prevent these deprecated properties
|
|
8
|
-
|
|
10
|
+
class Object #:nodoc:
|
|
11
|
+
# prevent these deprecated properties
|
|
12
|
+
# from clashing with our usage below
|
|
13
|
+
undef id if respond_to? :id
|
|
9
14
|
undef type if respond_to? :type
|
|
10
15
|
end
|
|
11
16
|
|
|
12
17
|
module Rumai
|
|
13
|
-
##
|
|
14
|
-
#
|
|
15
18
|
# access to global WM state
|
|
16
|
-
#
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
ROOT = Node.new '/'
|
|
20
|
-
|
|
21
|
-
# Returns the root of IXP file system hierarchy.
|
|
22
|
-
def fs
|
|
23
|
-
ROOT
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Returns the current set of tags.
|
|
27
|
-
def tags
|
|
28
|
-
fs.tag.entries.sort - %w[sel]
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Returns the current set of views.
|
|
32
|
-
def views
|
|
33
|
-
tags.map! {|t| View.new t}
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
module ClientContainer
|
|
37
|
-
# see definition below!
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
include ClientContainer
|
|
41
|
-
# Returns the IDs of the current set of clients.
|
|
42
|
-
def client_ids
|
|
43
|
-
fs.client.entries - %w[sel]
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Returns the name of the currently focused tag.
|
|
47
|
-
def curr_tag
|
|
48
|
-
curr_view.id
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Returns the name of the next tag.
|
|
52
|
-
def next_tag
|
|
53
|
-
next_view.id
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Returns the name of the previous tag.
|
|
57
|
-
def prev_tag
|
|
58
|
-
prev_view.id
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
##
|
|
63
|
-
#
|
|
64
|
-
# multiple client grouping: allows you to group a set of clients
|
|
65
|
-
# together and perform operations on all of them simultaneously.
|
|
66
|
-
#
|
|
67
|
-
##
|
|
68
19
|
|
|
69
|
-
|
|
20
|
+
ROOT = Node.new '/'
|
|
70
21
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# focused client is returned in the list.
|
|
75
|
-
def grouping
|
|
76
|
-
list = curr_view.clients.select {|c| c.group? }
|
|
77
|
-
list << curr_client if list.empty? and curr_client.exist?
|
|
78
|
-
list
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
##
|
|
83
|
-
#
|
|
84
|
-
# abstraction of WM components
|
|
85
|
-
#
|
|
86
|
-
##
|
|
87
|
-
|
|
88
|
-
# NOTE: Inheritors must override the 'chain' method.
|
|
89
|
-
module Chain
|
|
90
|
-
# Returns an array of objects related to this one.
|
|
91
|
-
def chain
|
|
92
|
-
[self]
|
|
22
|
+
# Returns the root of IXP file system hierarchy.
|
|
23
|
+
def fs
|
|
24
|
+
ROOT
|
|
93
25
|
end
|
|
94
26
|
|
|
95
|
-
# Returns the
|
|
96
|
-
def
|
|
97
|
-
|
|
27
|
+
# Returns the current set of tags.
|
|
28
|
+
def tags
|
|
29
|
+
fs.tag.entries.sort - %w[sel]
|
|
98
30
|
end
|
|
99
31
|
|
|
100
|
-
# Returns the
|
|
101
|
-
def
|
|
102
|
-
|
|
32
|
+
# Returns the current set of views.
|
|
33
|
+
def views
|
|
34
|
+
tags.map! {|t| View.new t }
|
|
103
35
|
end
|
|
104
36
|
|
|
105
|
-
|
|
37
|
+
module ClientContainer
|
|
38
|
+
# see definition below!
|
|
39
|
+
end
|
|
106
40
|
|
|
107
|
-
|
|
108
|
-
arr = chain
|
|
41
|
+
include ClientContainer
|
|
109
42
|
|
|
110
|
-
|
|
111
|
-
|
|
43
|
+
# Returns the IDs of the current set of clients.
|
|
44
|
+
def client_ids
|
|
45
|
+
fs.client.entries - %w[sel]
|
|
112
46
|
end
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
#
|
|
118
|
-
# NOTE: Inheritors must have a 'current' class method.
|
|
119
|
-
# NOTE: Inheritors must override the 'focus' method.
|
|
120
|
-
#
|
|
121
|
-
module WidgetImpl #:nodoc:
|
|
122
|
-
attr_reader :id
|
|
123
|
-
|
|
124
|
-
def == aOther
|
|
125
|
-
@id == aOther.id
|
|
47
|
+
|
|
48
|
+
# Returns the name of the currently focused tag.
|
|
49
|
+
def curr_tag
|
|
50
|
+
curr_view.id
|
|
126
51
|
end
|
|
127
52
|
|
|
128
|
-
#
|
|
129
|
-
def
|
|
130
|
-
|
|
53
|
+
# Returns the name of the next tag.
|
|
54
|
+
def next_tag
|
|
55
|
+
next_view.id
|
|
131
56
|
end
|
|
132
57
|
|
|
133
|
-
|
|
134
|
-
|
|
58
|
+
# Returns the name of the previous tag.
|
|
59
|
+
def prev_tag
|
|
60
|
+
prev_view.id
|
|
61
|
+
end
|
|
135
62
|
|
|
136
|
-
# A widget that has a corresponding representation in the IXP file system.
|
|
137
|
-
class WidgetNode < Node #:nodoc:
|
|
138
|
-
include WidgetImpl
|
|
139
63
|
|
|
140
|
-
|
|
141
|
-
|
|
64
|
+
# multiple client grouping: allows you to group a set of clients
|
|
65
|
+
# together and perform operations on all of them simultaneously.
|
|
142
66
|
|
|
143
|
-
|
|
144
|
-
@id = ctl.read.split.first
|
|
145
|
-
@path = File.join(File.dirname(@path), @id)
|
|
146
|
-
else
|
|
147
|
-
@id = File.basename(@path)
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
|
67
|
+
GROUPING_TAG = '@'
|
|
151
68
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
69
|
+
# Returns a list of all grouped clients in
|
|
70
|
+
# the currently focused view. If there are
|
|
71
|
+
# no grouped clients, then the currently
|
|
72
|
+
# focused client is returned in the list.
|
|
73
|
+
def grouping
|
|
74
|
+
list = curr_view.clients.select {|c| c.group? }
|
|
75
|
+
list << curr_client if list.empty? and curr_client.exist?
|
|
76
|
+
list
|
|
156
77
|
end
|
|
157
78
|
|
|
158
|
-
# Returns the currently focused client.
|
|
159
|
-
def self.curr
|
|
160
|
-
new :sel
|
|
161
|
-
end
|
|
162
79
|
|
|
163
|
-
|
|
164
|
-
# Returns a list of clients in the current view.
|
|
165
|
-
def chain
|
|
166
|
-
View.curr.clients
|
|
167
|
-
end
|
|
80
|
+
# abstraction of WM components
|
|
168
81
|
|
|
169
82
|
##
|
|
83
|
+
# NOTE: Inheritors must override the 'chain' method.
|
|
170
84
|
#
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
85
|
+
module Chain
|
|
86
|
+
##
|
|
87
|
+
# Returns an array of objects related to this one.
|
|
88
|
+
#
|
|
89
|
+
def chain
|
|
90
|
+
[self]
|
|
91
|
+
end
|
|
174
92
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
a.focus
|
|
93
|
+
##
|
|
94
|
+
# Returns the object after this one in the chain.
|
|
95
|
+
#
|
|
96
|
+
def next
|
|
97
|
+
sibling(+1)
|
|
98
|
+
end
|
|
182
99
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
100
|
+
##
|
|
101
|
+
# Returns the object before this one in the chain.
|
|
102
|
+
#
|
|
103
|
+
def prev
|
|
104
|
+
sibling(-1)
|
|
105
|
+
end
|
|
187
106
|
|
|
188
|
-
|
|
189
|
-
direction = src < dst ? :down : :up
|
|
107
|
+
private
|
|
190
108
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
end
|
|
109
|
+
def sibling offset
|
|
110
|
+
arr = chain
|
|
194
111
|
|
|
195
|
-
|
|
196
|
-
|
|
112
|
+
if pos = arr.index(self)
|
|
113
|
+
arr[(pos + offset) % arr.length]
|
|
197
114
|
end
|
|
198
115
|
end
|
|
199
116
|
end
|
|
200
117
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
118
|
+
##
|
|
119
|
+
# The basic building block of the WM hierarchy.
|
|
120
|
+
#
|
|
121
|
+
# NOTE: Inheritors must have a 'current' class method.
|
|
122
|
+
# NOTE: Inheritors must override the 'focus' method.
|
|
123
|
+
#
|
|
124
|
+
module WidgetImpl #:nodoc:
|
|
125
|
+
attr_reader :id
|
|
206
126
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
127
|
+
def == other
|
|
128
|
+
@id == other.id
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
##
|
|
132
|
+
# Checks if this widget currently has focus.
|
|
133
|
+
#
|
|
134
|
+
def current?
|
|
135
|
+
self == self.class.curr
|
|
136
|
+
end
|
|
212
137
|
|
|
213
|
-
|
|
214
|
-
def kill
|
|
215
|
-
ctl.write :kill
|
|
138
|
+
alias focus? current?
|
|
216
139
|
end
|
|
217
140
|
|
|
218
141
|
##
|
|
142
|
+
# A widget that has a corresponding representation in the IXP file system.
|
|
219
143
|
#
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
##
|
|
144
|
+
class WidgetNode < Node #:nodoc:
|
|
145
|
+
include WidgetImpl
|
|
223
146
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
aView.area_of_client self
|
|
227
|
-
end
|
|
147
|
+
def initialize id, path_prefix
|
|
148
|
+
super "#{path_prefix}/#{id}"
|
|
228
149
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
150
|
+
if id.to_s == 'sel' and ctl.exist?
|
|
151
|
+
@id = ctl.read.split.first
|
|
152
|
+
@path = File.join(File.dirname(@path), @id)
|
|
153
|
+
else
|
|
154
|
+
@id = File.basename(@path)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
232
157
|
end
|
|
233
158
|
|
|
234
159
|
##
|
|
160
|
+
# A graphical program that is running in your current X Windows session.
|
|
235
161
|
#
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
162
|
+
class Client < WidgetNode
|
|
163
|
+
def initialize client_id
|
|
164
|
+
super client_id, '/client'
|
|
165
|
+
end
|
|
239
166
|
|
|
240
|
-
|
|
167
|
+
##
|
|
168
|
+
# Returns the currently focused client.
|
|
169
|
+
#
|
|
170
|
+
def self.curr
|
|
171
|
+
new :sel
|
|
172
|
+
end
|
|
241
173
|
|
|
242
|
-
|
|
243
|
-
def tags
|
|
244
|
-
self[:tags].read.split TAG_DELIMITER
|
|
245
|
-
end
|
|
174
|
+
include Chain
|
|
246
175
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
176
|
+
##
|
|
177
|
+
# Returns a list of all clients in the current view.
|
|
178
|
+
#
|
|
179
|
+
def chain
|
|
180
|
+
View.curr.clients
|
|
181
|
+
end
|
|
252
182
|
|
|
253
|
-
|
|
254
|
-
# context of this client's list of tags.
|
|
255
|
-
def with_tags &aBlock
|
|
256
|
-
arr = self.tags
|
|
257
|
-
arr.instance_eval(&aBlock)
|
|
258
|
-
self.tags = arr
|
|
259
|
-
end
|
|
183
|
+
# WM operations
|
|
260
184
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
185
|
+
##
|
|
186
|
+
# Focuses this client within the given view.
|
|
187
|
+
#
|
|
188
|
+
def focus view = nil
|
|
189
|
+
if exist? and not focus?
|
|
190
|
+
Array(view || self.views).each do |v|
|
|
191
|
+
if a = self.area(v) and a.exist?
|
|
192
|
+
v.focus
|
|
193
|
+
a.focus
|
|
267
194
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
195
|
+
# slide focus from the current client onto this client
|
|
196
|
+
arr = a.client_ids
|
|
197
|
+
src = arr.index Client.curr.id
|
|
198
|
+
dst = arr.index @id
|
|
199
|
+
|
|
200
|
+
distance = (src - dst).abs
|
|
201
|
+
direction = src < dst ? :down : :up
|
|
202
|
+
|
|
203
|
+
distance.times do
|
|
204
|
+
v.ctl.write "select #{direction}"
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
break
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
273
211
|
end
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
212
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
213
|
+
##
|
|
214
|
+
# Sends this client to the given destination within the given view.
|
|
215
|
+
#
|
|
216
|
+
def send area_or_id, view = View.curr
|
|
217
|
+
dst = area_to_id(area_or_id)
|
|
218
|
+
view.ctl.write "send #{@id} #{dst}"
|
|
219
|
+
end
|
|
282
220
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
221
|
+
##
|
|
222
|
+
# Swaps this client with the given destination within the given view.
|
|
223
|
+
#
|
|
224
|
+
def swap area_or_id, view = View.curr
|
|
225
|
+
dst = area_to_id(area_or_id)
|
|
226
|
+
view.ctl.write "swap #{@id} #{dst}"
|
|
227
|
+
end
|
|
287
228
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
229
|
+
##
|
|
230
|
+
# Terminates this client nicely (requests this window to be closed).
|
|
231
|
+
#
|
|
232
|
+
def kill
|
|
233
|
+
ctl.write :kill
|
|
234
|
+
end
|
|
294
235
|
|
|
295
|
-
|
|
296
|
-
def ungroup
|
|
297
|
-
untag GROUPING_TAG
|
|
298
|
-
end
|
|
236
|
+
# WM hierarchy
|
|
299
237
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
end
|
|
307
|
-
end
|
|
238
|
+
##
|
|
239
|
+
# Returns the area that contains this client within the given view.
|
|
240
|
+
#
|
|
241
|
+
def area view = View.curr
|
|
242
|
+
view.area_of_client self
|
|
243
|
+
end
|
|
308
244
|
|
|
309
|
-
|
|
245
|
+
##
|
|
246
|
+
# Returns the views that contain this client.
|
|
247
|
+
#
|
|
248
|
+
def views
|
|
249
|
+
tags.map! {|t| View.new t }
|
|
250
|
+
end
|
|
310
251
|
|
|
311
|
-
|
|
312
|
-
if aAreaOrId.respond_to? :id
|
|
313
|
-
id = aAreaOrId.id
|
|
314
|
-
id == '~' ? :toggle : id
|
|
315
|
-
else
|
|
316
|
-
aAreaOrId
|
|
317
|
-
end
|
|
318
|
-
end
|
|
319
|
-
end
|
|
252
|
+
# tag manipulations
|
|
320
253
|
|
|
321
|
-
|
|
322
|
-
module ClientContainer
|
|
323
|
-
# Returns the IDs of the clients in this container.
|
|
324
|
-
def client_ids
|
|
325
|
-
[]
|
|
326
|
-
end
|
|
254
|
+
TAG_DELIMITER = '+'.freeze
|
|
327
255
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
256
|
+
##
|
|
257
|
+
# Returns the tags associated with this client.
|
|
258
|
+
#
|
|
259
|
+
def tags
|
|
260
|
+
self[:tags].read.split TAG_DELIMITER
|
|
261
|
+
end
|
|
332
262
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
263
|
+
##
|
|
264
|
+
# Modifies the tags associated with this client.
|
|
265
|
+
#
|
|
266
|
+
def tags= *tags
|
|
267
|
+
arr = tags.flatten.compact.uniq
|
|
268
|
+
self[:tags].write arr.join(TAG_DELIMITER)
|
|
338
269
|
end
|
|
339
|
-
end
|
|
340
|
-
end
|
|
341
270
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
271
|
+
##
|
|
272
|
+
# Evaluates the given block within the
|
|
273
|
+
# context of this client's list of tags.
|
|
274
|
+
#
|
|
275
|
+
def with_tags &block
|
|
276
|
+
arr = self.tags
|
|
277
|
+
arr.instance_eval(&block)
|
|
278
|
+
self.tags = arr
|
|
279
|
+
end
|
|
347
280
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
281
|
+
##
|
|
282
|
+
# Adds the given tags to this client.
|
|
283
|
+
#
|
|
284
|
+
def tag *tags
|
|
285
|
+
with_tags do
|
|
286
|
+
concat tags
|
|
287
|
+
end
|
|
288
|
+
end
|
|
352
289
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
290
|
+
##
|
|
291
|
+
# Removes the given tags from this client.
|
|
292
|
+
#
|
|
293
|
+
def untag *tags
|
|
294
|
+
with_tags do
|
|
295
|
+
tags.flatten.each do |tag|
|
|
296
|
+
delete tag.to_s
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
358
300
|
|
|
359
|
-
|
|
360
|
-
def float?
|
|
361
|
-
@id == '~'
|
|
362
|
-
end
|
|
301
|
+
# multiple client grouping
|
|
363
302
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
303
|
+
##
|
|
304
|
+
# Checks if this client is included in the current grouping.
|
|
305
|
+
#
|
|
306
|
+
def group?
|
|
307
|
+
tags.include? GROUPING_TAG
|
|
308
|
+
end
|
|
368
309
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
310
|
+
##
|
|
311
|
+
# Adds this client to the current grouping.
|
|
312
|
+
#
|
|
313
|
+
def group
|
|
314
|
+
with_tags do
|
|
315
|
+
push GROUPING_TAG
|
|
316
|
+
end
|
|
317
|
+
end
|
|
374
318
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
319
|
+
##
|
|
320
|
+
# Removes this client to the current grouping.
|
|
321
|
+
#
|
|
322
|
+
def ungroup
|
|
323
|
+
untag GROUPING_TAG
|
|
324
|
+
end
|
|
379
325
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
326
|
+
##
|
|
327
|
+
# Toggles the presence of this client in the current grouping.
|
|
328
|
+
#
|
|
329
|
+
def toggle_group
|
|
330
|
+
if group?
|
|
331
|
+
ungroup
|
|
332
|
+
else
|
|
333
|
+
group
|
|
334
|
+
end
|
|
335
|
+
end
|
|
384
336
|
|
|
385
|
-
|
|
386
|
-
# Returns the IDs of the clients in this area.
|
|
387
|
-
def client_ids
|
|
388
|
-
@view.client_ids @id
|
|
389
|
-
end
|
|
337
|
+
private
|
|
390
338
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
339
|
+
def area_to_id area_or_id
|
|
340
|
+
if area_or_id.respond_to? :id
|
|
341
|
+
id = area_or_id.id
|
|
342
|
+
id == '~' ? :toggle : id
|
|
343
|
+
else
|
|
344
|
+
area_or_id
|
|
345
|
+
end
|
|
395
346
|
end
|
|
396
|
-
|
|
397
|
-
# Sets the layout of clients in this column.
|
|
398
|
-
def layout= aMode
|
|
399
|
-
@view.ctl.write "colmode #{@id} #{aMode}"
|
|
400
347
|
end
|
|
401
348
|
|
|
402
349
|
##
|
|
350
|
+
# NOTE: Inheritors should override the 'client_ids' method.
|
|
403
351
|
#
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
352
|
+
module ClientContainer
|
|
353
|
+
##
|
|
354
|
+
# Returns the IDs of the clients in this container.
|
|
355
|
+
#
|
|
356
|
+
def client_ids
|
|
357
|
+
[]
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
##
|
|
361
|
+
# Returns the clients contained in this container.
|
|
362
|
+
#
|
|
363
|
+
def clients
|
|
364
|
+
client_ids.map! {|i| Client.new i }
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# multiple client grouping
|
|
368
|
+
%w[group ungroup toggle_group].each do |meth|
|
|
369
|
+
define_method meth do
|
|
370
|
+
clients.each do |c|
|
|
371
|
+
c.__send__ meth
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
end
|
|
407
375
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
376
|
+
##
|
|
377
|
+
# Returns all grouped clients in this container.
|
|
378
|
+
#
|
|
379
|
+
def grouping
|
|
380
|
+
clients.select {|c| c.group? }
|
|
381
|
+
end
|
|
411
382
|
end
|
|
412
383
|
|
|
413
384
|
##
|
|
385
|
+
# A region that contains clients. This can be either
|
|
386
|
+
# the floating area or a column in the managed area.
|
|
414
387
|
#
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
##
|
|
388
|
+
class Area
|
|
389
|
+
attr_reader :view
|
|
418
390
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
391
|
+
##
|
|
392
|
+
# [view] the view object which contains this area
|
|
393
|
+
#
|
|
394
|
+
def initialize area_id, view = View.curr
|
|
395
|
+
@id = Integer(area_id) rescue area_id
|
|
396
|
+
@view = view
|
|
397
|
+
end
|
|
423
398
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
399
|
+
##
|
|
400
|
+
# Checks if this area is the floating area.
|
|
401
|
+
#
|
|
402
|
+
def float?
|
|
403
|
+
@id == '~'
|
|
428
404
|
end
|
|
429
405
|
|
|
430
|
-
|
|
431
|
-
|
|
406
|
+
##
|
|
407
|
+
# Checks if this is a managed area (a column).
|
|
408
|
+
#
|
|
409
|
+
def column?
|
|
410
|
+
not float?
|
|
411
|
+
end
|
|
432
412
|
|
|
433
|
-
|
|
413
|
+
include WidgetImpl
|
|
434
414
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
415
|
+
##
|
|
416
|
+
# Returns the currently focused area.
|
|
417
|
+
#
|
|
418
|
+
def self.curr
|
|
419
|
+
View.curr.area_of_client Client.curr
|
|
420
|
+
end
|
|
439
421
|
|
|
440
|
-
|
|
441
|
-
import_client c
|
|
442
|
-
end
|
|
443
|
-
end
|
|
422
|
+
include Chain
|
|
444
423
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
424
|
+
##
|
|
425
|
+
# Returns a list of all areas in the current view.
|
|
426
|
+
#
|
|
427
|
+
def chain
|
|
428
|
+
@view.areas
|
|
429
|
+
end
|
|
449
430
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
431
|
+
##
|
|
432
|
+
# Checks if this object exists in the chain.
|
|
433
|
+
#
|
|
434
|
+
def exist?
|
|
435
|
+
chain.include? self
|
|
436
|
+
end
|
|
453
437
|
|
|
454
|
-
|
|
455
|
-
import_client c
|
|
456
|
-
c.send :up if target
|
|
457
|
-
end
|
|
458
|
-
end
|
|
438
|
+
include ClientContainer
|
|
459
439
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
440
|
+
##
|
|
441
|
+
# Returns the IDs of the clients in this area.
|
|
442
|
+
#
|
|
443
|
+
def client_ids
|
|
444
|
+
@view.client_ids @id
|
|
445
|
+
end
|
|
464
446
|
|
|
465
|
-
|
|
466
|
-
# Areas to the right of this one serve as a buffer into which excess
|
|
467
|
-
# clients are evicted and from which deficit clients are imported.
|
|
468
|
-
def length= aMaxClients
|
|
469
|
-
return unless aMaxClients > 0
|
|
470
|
-
len, out = length, fringe
|
|
447
|
+
include Enumerable
|
|
471
448
|
|
|
472
|
-
|
|
473
|
-
|
|
449
|
+
##
|
|
450
|
+
# Iterates through each client in this container.
|
|
451
|
+
#
|
|
452
|
+
def each &block
|
|
453
|
+
clients.each(&block)
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
##
|
|
457
|
+
# Sets the layout of clients in this column.
|
|
458
|
+
#
|
|
459
|
+
def layout= mode
|
|
460
|
+
@view.ctl.write "colmode #{@id} #{mode}"
|
|
461
|
+
end
|
|
474
462
|
|
|
475
|
-
|
|
476
|
-
until (diff = aMaxClients - length) == 0
|
|
477
|
-
immigrants = out.clients.first(diff)
|
|
478
|
-
break if immigrants.empty?
|
|
463
|
+
# WM operations
|
|
479
464
|
|
|
480
|
-
|
|
465
|
+
##
|
|
466
|
+
# Puts focus on this area.
|
|
467
|
+
#
|
|
468
|
+
def focus
|
|
469
|
+
@view.ctl.write "select #{@id}"
|
|
481
470
|
end
|
|
482
|
-
end
|
|
483
|
-
end
|
|
484
471
|
|
|
485
|
-
|
|
472
|
+
# array abstraction: area is an array of clients
|
|
486
473
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
474
|
+
##
|
|
475
|
+
# Returns the number of clients in this area.
|
|
476
|
+
#
|
|
477
|
+
def length
|
|
478
|
+
client_ids.length
|
|
479
|
+
end
|
|
491
480
|
|
|
492
|
-
|
|
493
|
-
#
|
|
494
|
-
|
|
495
|
-
|
|
481
|
+
##
|
|
482
|
+
# Inserts the given clients at the bottom of this area.
|
|
483
|
+
#
|
|
484
|
+
def push *clients
|
|
485
|
+
clients.flatten!
|
|
486
|
+
return if clients.empty?
|
|
496
487
|
|
|
497
|
-
|
|
488
|
+
insert clients
|
|
498
489
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
490
|
+
# adjust the order of clients in this
|
|
491
|
+
# area to reflect the tail-wise insertion
|
|
492
|
+
clients.each_with_index do |c, i|
|
|
493
|
+
until c.id == self.client_ids[-i.succ]
|
|
494
|
+
c.swap :down
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
end
|
|
502
498
|
|
|
503
|
-
|
|
504
|
-
end
|
|
505
|
-
end
|
|
499
|
+
alias << push
|
|
506
500
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
501
|
+
##
|
|
502
|
+
# Inserts the given clients after the
|
|
503
|
+
# currently focused client in this area.
|
|
504
|
+
#
|
|
505
|
+
def insert *clients
|
|
506
|
+
clients.flatten!
|
|
507
|
+
return if clients.empty?
|
|
512
508
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
def self.curr
|
|
518
|
-
new :sel
|
|
519
|
-
end
|
|
509
|
+
clients.each do |c|
|
|
510
|
+
import_client c
|
|
511
|
+
end
|
|
512
|
+
end
|
|
520
513
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
514
|
+
##
|
|
515
|
+
# Inserts the given clients at the top of this area.
|
|
516
|
+
#
|
|
517
|
+
def unshift *clients
|
|
518
|
+
clients.flatten!
|
|
519
|
+
return if clients.empty?
|
|
525
520
|
|
|
526
|
-
|
|
527
|
-
def chain
|
|
528
|
-
Rumai.views
|
|
529
|
-
end
|
|
521
|
+
insert clients
|
|
530
522
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
523
|
+
# adjust the order of clients in this
|
|
524
|
+
# area to reflect the head-wise insertion
|
|
525
|
+
clients.each_with_index do |c, i|
|
|
526
|
+
until c.id == self.client_ids[i]
|
|
527
|
+
c.swap :up
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
end
|
|
537
531
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
532
|
+
##
|
|
533
|
+
# Concatenates the given area to the bottom of this area.
|
|
534
|
+
#
|
|
535
|
+
def concat area
|
|
536
|
+
push area.clients
|
|
537
|
+
end
|
|
543
538
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
539
|
+
##
|
|
540
|
+
# Ensures that this area has at most the given number of clients.
|
|
541
|
+
#
|
|
542
|
+
# Areas to the right of this one serve as a buffer into which excess
|
|
543
|
+
# clients are evicted and from which deficit clients are imported.
|
|
544
|
+
#
|
|
545
|
+
def length= max_clients
|
|
546
|
+
return unless max_clients > 0
|
|
547
|
+
len, out = length, fringe
|
|
548
|
+
|
|
549
|
+
if len > max_clients
|
|
550
|
+
out.unshift clients[max_clients..-1]
|
|
551
|
+
|
|
552
|
+
elsif len < max_clients
|
|
553
|
+
until (diff = max_clients - length) == 0
|
|
554
|
+
importable = out.clients[0, diff]
|
|
555
|
+
break if importable.empty?
|
|
556
|
+
|
|
557
|
+
push importable
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
end
|
|
547
561
|
|
|
548
|
-
|
|
549
|
-
def manifest
|
|
550
|
-
index.read || ''
|
|
551
|
-
end
|
|
562
|
+
private
|
|
552
563
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
564
|
+
##
|
|
565
|
+
# Moves the given client into this area.
|
|
566
|
+
#
|
|
567
|
+
def import_client c
|
|
568
|
+
if exist?
|
|
569
|
+
c.send self
|
|
558
570
|
|
|
559
|
-
# Returns the area which contains the given client in this view.
|
|
560
|
-
def area_of_client aClientOrId
|
|
561
|
-
arg =
|
|
562
|
-
if aClientOrId.respond_to? :id
|
|
563
|
-
aClientOrId.id
|
|
564
571
|
else
|
|
565
|
-
|
|
572
|
+
# move the client to the nearest existing column
|
|
573
|
+
src = c.area
|
|
574
|
+
dst = chain.last
|
|
575
|
+
|
|
576
|
+
c.send dst unless src == dst
|
|
577
|
+
|
|
578
|
+
# slide the client over to this column
|
|
579
|
+
c.send :right
|
|
580
|
+
@id = dst.id.next
|
|
581
|
+
|
|
582
|
+
raise 'column should exist now' unless exist?
|
|
566
583
|
end
|
|
584
|
+
end
|
|
567
585
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
586
|
+
##
|
|
587
|
+
# Returns the next area, which may or may not exist.
|
|
588
|
+
#
|
|
589
|
+
def fringe
|
|
590
|
+
Area.new @id.next, @view
|
|
571
591
|
end
|
|
572
592
|
end
|
|
573
593
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
594
|
+
##
|
|
595
|
+
# The visualization of a tag.
|
|
596
|
+
#
|
|
597
|
+
class View < WidgetNode
|
|
598
|
+
include WidgetImpl
|
|
599
|
+
|
|
600
|
+
##
|
|
601
|
+
# Returns the currently focused view.
|
|
602
|
+
#
|
|
603
|
+
def self.curr
|
|
604
|
+
new :sel
|
|
605
|
+
end
|
|
580
606
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
607
|
+
##
|
|
608
|
+
# Focuses this view.
|
|
609
|
+
#
|
|
610
|
+
def focus
|
|
611
|
+
Rumai.fs.ctl.write "view #{@id}"
|
|
612
|
+
end
|
|
585
613
|
|
|
586
|
-
|
|
587
|
-
def floater
|
|
588
|
-
areas.first
|
|
589
|
-
end
|
|
614
|
+
include Chain
|
|
590
615
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
616
|
+
##
|
|
617
|
+
# Returns a list of all views.
|
|
618
|
+
#
|
|
619
|
+
def chain
|
|
620
|
+
Rumai.views
|
|
621
|
+
end
|
|
595
622
|
|
|
596
|
-
|
|
597
|
-
# each column. That is, if the given block creates new
|
|
598
|
-
# columns, then those will also be processed in the iteration.
|
|
599
|
-
def each_column aStartingColumnId = 1
|
|
600
|
-
i = aStartingColumnId
|
|
601
|
-
loop do
|
|
602
|
-
a = Area.new i, self
|
|
623
|
+
include ClientContainer
|
|
603
624
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
625
|
+
##
|
|
626
|
+
# Returns the IDs of the clients contained
|
|
627
|
+
# in the given area within this view.
|
|
628
|
+
#
|
|
629
|
+
def client_ids area_id = '\S+'
|
|
630
|
+
manifest.scan(/^#{area_id} (0x\S+)/).flatten
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
include Enumerable
|
|
634
|
+
|
|
635
|
+
##
|
|
636
|
+
# Iterates through each area in this view.
|
|
637
|
+
#
|
|
638
|
+
def each &block
|
|
639
|
+
areas.each(&block)
|
|
608
640
|
end
|
|
609
641
|
|
|
610
|
-
|
|
642
|
+
def initialize view_id
|
|
643
|
+
super view_id, '/tag'
|
|
611
644
|
end
|
|
612
|
-
end
|
|
613
645
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
646
|
+
##
|
|
647
|
+
# Returns the manifest of all areas and clients in this view.
|
|
648
|
+
#
|
|
649
|
+
def manifest
|
|
650
|
+
index.read || ''
|
|
651
|
+
end
|
|
619
652
|
|
|
620
|
-
|
|
621
|
-
# their relative order, in the tiling fashion of
|
|
622
|
-
# LarsWM. Only the first client in the primary column
|
|
623
|
-
# is kept; all others are evicted to the *top* of the
|
|
624
|
-
# secondary column. Any subsequent columns are
|
|
625
|
-
# squeezed into the *bottom* of the secondary column.
|
|
626
|
-
def arrange_as_larswm
|
|
627
|
-
float, main, *extra = areas
|
|
628
|
-
main.length = 1
|
|
629
|
-
squeeze extra
|
|
630
|
-
end
|
|
653
|
+
# WM hierarchy
|
|
631
654
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
655
|
+
##
|
|
656
|
+
# Returns the area which contains the given client in this view.
|
|
657
|
+
#
|
|
658
|
+
def area_of_client client_or_id
|
|
659
|
+
arg =
|
|
660
|
+
if client_or_id.respond_to? :id
|
|
661
|
+
client_or_id.id
|
|
662
|
+
else
|
|
663
|
+
client_or_id
|
|
664
|
+
end
|
|
639
665
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
666
|
+
manifest =~ /^(\S+) #{arg}/
|
|
667
|
+
if area_id = $1
|
|
668
|
+
Area.new area_id, self
|
|
669
|
+
end
|
|
670
|
+
end
|
|
643
671
|
|
|
644
|
-
|
|
672
|
+
##
|
|
673
|
+
# Returns the IDs of all areas in this view.
|
|
674
|
+
#
|
|
675
|
+
def area_ids
|
|
676
|
+
ids = manifest.scan(/^# (\d+)/).flatten
|
|
677
|
+
ids.unshift '~' # the floating area
|
|
678
|
+
ids
|
|
679
|
+
end
|
|
645
680
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
681
|
+
##
|
|
682
|
+
# Returns all areas in this view.
|
|
683
|
+
#
|
|
684
|
+
def areas
|
|
685
|
+
area_ids.map! {|i| Area.new i, self }
|
|
686
|
+
end
|
|
652
687
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
688
|
+
##
|
|
689
|
+
# Returns the floating area of this view.
|
|
690
|
+
#
|
|
691
|
+
def floater
|
|
692
|
+
areas.first
|
|
693
|
+
end
|
|
659
694
|
|
|
660
|
-
|
|
661
|
-
|
|
695
|
+
##
|
|
696
|
+
# Returns all columns (managed areas) in this view.
|
|
697
|
+
#
|
|
698
|
+
def columns
|
|
699
|
+
areas[1..-1]
|
|
700
|
+
end
|
|
662
701
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
if
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
702
|
+
##
|
|
703
|
+
# Resiliently iterates through possibly destructive changes to
|
|
704
|
+
# each column. That is, if the given block creates new
|
|
705
|
+
# columns, then those will also be processed in the iteration.
|
|
706
|
+
#
|
|
707
|
+
def each_column starting_column_id = 1
|
|
708
|
+
i = starting_column_id
|
|
709
|
+
loop do
|
|
710
|
+
a = Area.new i, self
|
|
711
|
+
|
|
712
|
+
if a.exist?
|
|
713
|
+
yield a
|
|
714
|
+
else
|
|
715
|
+
break
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
i += 1
|
|
719
|
+
end
|
|
670
720
|
end
|
|
671
|
-
end
|
|
672
721
|
|
|
673
|
-
|
|
722
|
+
# visual arrangement of clients
|
|
723
|
+
|
|
724
|
+
##
|
|
725
|
+
# Arranges the clients in this view, while maintaining
|
|
726
|
+
# their relative order, in the tiling fashion of LarsWM.
|
|
727
|
+
#
|
|
728
|
+
# Only the first client in the primary column is kept; all others
|
|
729
|
+
# are evicted to the *top* of the secondary column. Any subsequent
|
|
730
|
+
# columns are squeezed into the *bottom* of the secondary column.
|
|
731
|
+
#
|
|
732
|
+
def arrange_as_larswm
|
|
733
|
+
maintain_focus do
|
|
734
|
+
float, main, *extra = areas
|
|
735
|
+
|
|
736
|
+
# keep only one client in the primary column
|
|
737
|
+
main.length = 1
|
|
738
|
+
|
|
739
|
+
if extra.length > 1
|
|
740
|
+
# collapse remaining areas into secondary column
|
|
741
|
+
extra.reverse.each_cons(2) do |src, dst|
|
|
742
|
+
dst.concat src
|
|
743
|
+
end
|
|
744
|
+
end
|
|
745
|
+
end
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
##
|
|
749
|
+
# Arranges the clients in this view, while maintaining
|
|
750
|
+
# their relative order, in a (at best) square grid.
|
|
751
|
+
#
|
|
752
|
+
def arrange_in_grid max_clients_per_column = nil
|
|
753
|
+
# compute client distribution
|
|
754
|
+
unless max_clients_per_column
|
|
755
|
+
num_clients = num_managed_clients
|
|
756
|
+
return unless num_clients > 0
|
|
757
|
+
|
|
758
|
+
num_columns = Math.sqrt(num_clients)
|
|
759
|
+
max_clients_per_column = (num_clients / num_columns).round
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
return if max_clients_per_column < 1
|
|
763
|
+
|
|
764
|
+
# apply the distribution
|
|
765
|
+
maintain_focus do
|
|
766
|
+
each_column do |a|
|
|
767
|
+
a.length = max_clients_per_column
|
|
768
|
+
a.layout = :default
|
|
769
|
+
end
|
|
770
|
+
end
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
##
|
|
774
|
+
# Arranges the clients in this view, while
|
|
775
|
+
# maintaining their relative order, in a (at
|
|
776
|
+
# best) equilateral triangle. However, the
|
|
777
|
+
# resulting arrangement appears like a diamond
|
|
778
|
+
# because wmii does not waste screen space.
|
|
779
|
+
#
|
|
780
|
+
def arrange_in_diamond
|
|
781
|
+
num_clients = num_managed_clients
|
|
782
|
+
return unless num_clients > 1
|
|
783
|
+
|
|
784
|
+
# determine dimensions of the rising sub-triangle
|
|
785
|
+
rise = num_clients / 2
|
|
786
|
+
|
|
787
|
+
span = sum = 0
|
|
788
|
+
1.upto rise do |h|
|
|
789
|
+
if sum + h > rise
|
|
790
|
+
break
|
|
791
|
+
else
|
|
792
|
+
sum += h
|
|
793
|
+
span += 1
|
|
794
|
+
end
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
peak = num_clients - (sum * 2)
|
|
674
798
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
799
|
+
# describe the overall triangle as a sequence of heights
|
|
800
|
+
rise_seq = (1..span).to_a
|
|
801
|
+
fall_seq = rise_seq.reverse
|
|
678
802
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
803
|
+
heights = rise_seq
|
|
804
|
+
heights << peak if peak > 0
|
|
805
|
+
heights.concat fall_seq
|
|
682
806
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
807
|
+
# apply the heights
|
|
808
|
+
maintain_focus do
|
|
809
|
+
each_column do |col|
|
|
810
|
+
if h = heights.shift
|
|
811
|
+
col.length = h
|
|
812
|
+
col.layout = :default
|
|
813
|
+
end
|
|
814
|
+
end
|
|
815
|
+
end
|
|
688
816
|
end
|
|
689
|
-
end
|
|
690
|
-
end
|
|
691
817
|
|
|
692
|
-
|
|
818
|
+
private
|
|
693
819
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
820
|
+
##
|
|
821
|
+
# Executes the given block and restores
|
|
822
|
+
# focus to the client that had focus
|
|
823
|
+
# before the given block was executed.
|
|
824
|
+
#
|
|
825
|
+
def maintain_focus
|
|
826
|
+
c = Rumai.curr_client
|
|
827
|
+
yield
|
|
828
|
+
c.focus
|
|
829
|
+
end
|
|
698
830
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
831
|
+
##
|
|
832
|
+
# Returns the number of clients in the non-floating areas of this view.
|
|
833
|
+
#
|
|
834
|
+
def num_managed_clients
|
|
835
|
+
manifest.scan(/^\d+ 0x/).length
|
|
704
836
|
end
|
|
705
837
|
end
|
|
706
|
-
end
|
|
707
|
-
|
|
708
838
|
|
|
709
|
-
##
|
|
710
|
-
#
|
|
711
839
|
# shortcuts for interactive WM manipulation (via IRB)
|
|
712
|
-
#
|
|
713
|
-
##
|
|
714
840
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
c.extend ExportInstMethods
|
|
718
|
-
end
|
|
841
|
+
# provide easy access to container state information
|
|
842
|
+
[Client, Area, View].each {|c| c.extend ExportInstanceMethods }
|
|
719
843
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
844
|
+
def curr_client
|
|
845
|
+
Client.curr
|
|
846
|
+
end
|
|
723
847
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
848
|
+
def next_client
|
|
849
|
+
curr_client.next
|
|
850
|
+
end
|
|
727
851
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
852
|
+
def prev_client
|
|
853
|
+
curr_client.prev
|
|
854
|
+
end
|
|
731
855
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
856
|
+
def curr_area
|
|
857
|
+
Area.curr
|
|
858
|
+
end
|
|
735
859
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
860
|
+
def next_area
|
|
861
|
+
curr_area.next
|
|
862
|
+
end
|
|
739
863
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
864
|
+
def prev_area
|
|
865
|
+
curr_area.prev
|
|
866
|
+
end
|
|
743
867
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
868
|
+
def curr_view
|
|
869
|
+
View.curr
|
|
870
|
+
end
|
|
747
871
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
872
|
+
def next_view
|
|
873
|
+
curr_view.next
|
|
874
|
+
end
|
|
751
875
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
876
|
+
def prev_view
|
|
877
|
+
curr_view.prev
|
|
878
|
+
end
|
|
755
879
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
880
|
+
def focus_client id
|
|
881
|
+
Client.focus id
|
|
882
|
+
end
|
|
759
883
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
884
|
+
def focus_area id
|
|
885
|
+
Area.focus id
|
|
886
|
+
end
|
|
763
887
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
888
|
+
def focus_view id
|
|
889
|
+
View.focus id
|
|
890
|
+
end
|
|
767
891
|
|
|
768
|
-
|
|
769
|
-
|
|
892
|
+
# provide easy access to this module's instance methods
|
|
893
|
+
module_function(*instance_methods)
|
|
770
894
|
end
|