rumai 3.2.4 → 3.3.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 +4 -9
- data/lib/rumai/fs.rb +16 -8
- data/lib/rumai/inochi.rb +7 -7
- data/lib/rumai/ixp/transport.rb +9 -19
- data/lib/rumai/wm.rb +966 -866
- data/man.html +105 -91
- data/man/man1/rumai.1.gz +0 -0
- metadata +15 -5
data/CREDITS
CHANGED
@@ -9,17 +9,12 @@ Suraj N. Kurapati
|
|
9
9
|
%#----------------------------------------------------------------------------
|
10
10
|
|
11
11
|
Christoph Blank,
|
12
|
-
|
12
|
+
Kenneth De Winter,
|
13
|
+
Mattia Gheda,
|
13
14
|
Michael Andrus,
|
14
15
|
Nathan Neff,
|
15
|
-
|
16
|
-
|
17
|
-
[skirge]
|
18
|
-
|
19
|
-
%# XXX: only link to these contributors because they do not have real names
|
20
|
-
[Gigamo]: http://github.com/gigamo
|
21
|
-
[ghedamat]: http://github.com/ghedamat
|
22
|
-
[skirge]: http://github.com/skirge
|
16
|
+
Sebastian Chmielewski,
|
17
|
+
Simon Hafner
|
23
18
|
|
24
19
|
%#----------------------------------------------------------------------------
|
25
20
|
## LICENSE
|
data/lib/rumai/fs.rb
CHANGED
@@ -15,12 +15,11 @@ module Rumai
|
|
15
15
|
IXP_AGENT = IXP::Agent.new(UNIXSocket.new(IXP_SOCK_ADDR))
|
16
16
|
|
17
17
|
rescue => error
|
18
|
-
error.message <<
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
error.message <<EOF
|
19
|
+
Ensure that (1) the WMII_ADDRESS environment variable is set and that (2) it
|
20
|
+
correctly specifies the absolute filesystem path to wmii's IXP socket file,
|
21
|
+
which is typically located at "/tmp/ns.$USER.:$DISPLAY/wmii".
|
22
|
+
EOF
|
24
23
|
raise error
|
25
24
|
end
|
26
25
|
|
@@ -28,8 +27,6 @@ module Rumai
|
|
28
27
|
# An entry in the IXP file system.
|
29
28
|
#
|
30
29
|
class Node
|
31
|
-
@@cache = Hash.new {|h,k| h[k] = Node.new(k) }
|
32
|
-
|
33
30
|
attr_reader :path
|
34
31
|
|
35
32
|
def initialize path
|
@@ -59,6 +56,8 @@ module Rumai
|
|
59
56
|
##
|
60
57
|
# Tests if this node is a directory.
|
61
58
|
#
|
59
|
+
# @see Rumai::IXP::Agent#stat
|
60
|
+
#
|
62
61
|
def directory?
|
63
62
|
exist? and stat.directory?
|
64
63
|
end
|
@@ -66,6 +65,8 @@ module Rumai
|
|
66
65
|
##
|
67
66
|
# Returns the names of all files in this directory.
|
68
67
|
#
|
68
|
+
# @see Rumai::IXP::Agent#entries
|
69
|
+
#
|
69
70
|
def entries
|
70
71
|
begin
|
71
72
|
IXP_AGENT.entries @path
|
@@ -98,6 +99,7 @@ module Rumai
|
|
98
99
|
# @yieldparam [String] line
|
99
100
|
#
|
100
101
|
def each_line &block
|
102
|
+
raise ArgumentError unless block_given?
|
101
103
|
open do |file|
|
102
104
|
until (chunk = file.read(true)).empty?
|
103
105
|
chunk.each_line(&block)
|
@@ -108,6 +110,8 @@ module Rumai
|
|
108
110
|
##
|
109
111
|
# Writes the given content to this node.
|
110
112
|
#
|
113
|
+
# @see Rumai::IXP::Agent#write
|
114
|
+
#
|
111
115
|
def write content
|
112
116
|
IXP_AGENT.write @path, content
|
113
117
|
end
|
@@ -124,10 +128,14 @@ module Rumai
|
|
124
128
|
##
|
125
129
|
# Deletes the file corresponding to this node on the IXP server.
|
126
130
|
#
|
131
|
+
# @see Rumai::IXP::Agent#remove
|
132
|
+
#
|
127
133
|
def remove
|
128
134
|
IXP_AGENT.remove @path
|
129
135
|
end
|
130
136
|
|
137
|
+
@@cache = Hash.new {|h,k| h[k] = Node.new(k) }
|
138
|
+
|
131
139
|
##
|
132
140
|
# Returns the given sub-path as a Node object.
|
133
141
|
#
|
data/lib/rumai/inochi.rb
CHANGED
@@ -3,27 +3,27 @@ module Rumai
|
|
3
3
|
##
|
4
4
|
# Official name of this project.
|
5
5
|
#
|
6
|
-
PROJECT =
|
6
|
+
PROJECT = 'Rumai'
|
7
7
|
|
8
8
|
##
|
9
9
|
# Short single-line description of this project.
|
10
10
|
#
|
11
|
-
TAGLINE =
|
11
|
+
TAGLINE = 'Ruby interface to the wmii window manager'
|
12
12
|
|
13
13
|
##
|
14
14
|
# Address of this project's official home page.
|
15
15
|
#
|
16
|
-
WEBSITE =
|
16
|
+
WEBSITE = 'http://snk.tuxfamily.org/lib/rumai/'
|
17
17
|
|
18
18
|
##
|
19
19
|
# Number of this release of this project.
|
20
20
|
#
|
21
|
-
VERSION =
|
21
|
+
VERSION = '3.3.0'
|
22
22
|
|
23
23
|
##
|
24
24
|
# Date of this release of this project.
|
25
25
|
#
|
26
|
-
RELDATE =
|
26
|
+
RELDATE = '2010-07-16'
|
27
27
|
|
28
28
|
##
|
29
29
|
# Description of this release of this project.
|
@@ -74,8 +74,8 @@ module Rumai
|
|
74
74
|
# }
|
75
75
|
#
|
76
76
|
DEVTIME = {
|
77
|
-
|
78
|
-
|
77
|
+
'inochi' => [ '>= 3.0.0', '< 4' ],
|
78
|
+
'dfect' => [ '~> 2' ], # for unit testing
|
79
79
|
}
|
80
80
|
|
81
81
|
# establish gem version dependencies
|
data/lib/rumai/ixp/transport.rb
CHANGED
@@ -76,8 +76,8 @@ module Rumai
|
|
76
76
|
rescue ThreadError
|
77
77
|
# pool is empty, so fill it
|
78
78
|
FILL_RATE.times do
|
79
|
-
if @pos != @lim
|
80
|
-
@pool
|
79
|
+
if @pos != @lim then
|
80
|
+
@pool.enq @pos
|
81
81
|
@pos = @pos.succ
|
82
82
|
else
|
83
83
|
# range is exhausted, so give other threads
|
@@ -96,7 +96,7 @@ module Rumai
|
|
96
96
|
# that it may be occupied again in the future.
|
97
97
|
#
|
98
98
|
def release member
|
99
|
-
@pool
|
99
|
+
@pool.enq member
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
@@ -192,7 +192,7 @@ module Rumai
|
|
192
192
|
#
|
193
193
|
def MODES.parse mode
|
194
194
|
if mode.respond_to? :split
|
195
|
-
mode.split(//).inject(0) {|
|
195
|
+
mode.split(//).inject(0) {|acc,chr| acc | self[chr].to_i }
|
196
196
|
else
|
197
197
|
mode.to_i
|
198
198
|
end
|
@@ -206,16 +206,12 @@ module Rumai
|
|
206
206
|
# @see File::open
|
207
207
|
#
|
208
208
|
def open path, mode = 'r'
|
209
|
-
mode = MODES.parse(mode)
|
210
|
-
|
211
209
|
# open the file
|
212
210
|
path_fid = walk(path)
|
213
|
-
|
214
211
|
talk Topen.new(
|
215
212
|
:fid => path_fid,
|
216
|
-
:mode => mode
|
213
|
+
:mode => MODES.parse(mode)
|
217
214
|
)
|
218
|
-
|
219
215
|
stream = FidStream.new(self, path_fid, @msize)
|
220
216
|
|
221
217
|
# return the file stream
|
@@ -355,9 +351,7 @@ module Rumai
|
|
355
351
|
# Returns the content of the file/directory at the given path.
|
356
352
|
#
|
357
353
|
def read path, *args
|
358
|
-
open
|
359
|
-
f.read(*args)
|
360
|
-
end
|
354
|
+
open(path) {|f| f.read(*args) }
|
361
355
|
end
|
362
356
|
|
363
357
|
##
|
@@ -371,7 +365,7 @@ module Rumai
|
|
371
365
|
raise ArgumentError, "#{path.inspect} is not a directory"
|
372
366
|
end
|
373
367
|
|
374
|
-
read(path).map! {|t| t.name}
|
368
|
+
read(path).map! {|t| t.name }
|
375
369
|
end
|
376
370
|
|
377
371
|
##
|
@@ -379,9 +373,7 @@ module Rumai
|
|
379
373
|
# the file at the given path.
|
380
374
|
#
|
381
375
|
def write path, content
|
382
|
-
open
|
383
|
-
f << content
|
384
|
-
end
|
376
|
+
open(path, 'w') {|f| f.write content }
|
385
377
|
end
|
386
378
|
|
387
379
|
##
|
@@ -392,8 +384,6 @@ module Rumai
|
|
392
384
|
prefix = File.dirname(path)
|
393
385
|
target = File.basename(path)
|
394
386
|
|
395
|
-
mode = MODES.parse(mode)
|
396
|
-
|
397
387
|
with_fid do |prefix_fid|
|
398
388
|
walk_fid prefix_fid, prefix
|
399
389
|
|
@@ -402,7 +392,7 @@ module Rumai
|
|
402
392
|
:fid => prefix_fid,
|
403
393
|
:name => target,
|
404
394
|
:perm => perm,
|
405
|
-
:mode => mode
|
395
|
+
:mode => MODES.parse(mode)
|
406
396
|
)
|
407
397
|
end
|
408
398
|
end
|
data/lib/rumai/wm.rb
CHANGED
@@ -21,1079 +21,1179 @@ module Rumai
|
|
21
21
|
# abstraction of WM components
|
22
22
|
#---------------------------------------------------------------------------
|
23
23
|
|
24
|
+
##
|
25
|
+
# @note Inheritors must override the {Chain#chain} method.
|
26
|
+
#
|
27
|
+
module Chain
|
24
28
|
##
|
25
|
-
#
|
29
|
+
# Returns an array of objects related to this one.
|
26
30
|
#
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
#
|
31
|
-
def chain
|
32
|
-
[self]
|
33
|
-
end
|
31
|
+
def chain
|
32
|
+
[self]
|
33
|
+
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
##
|
36
|
+
# Returns the object after this one in the chain.
|
37
|
+
#
|
38
|
+
def next
|
39
|
+
sibling(+1)
|
40
|
+
end
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
##
|
43
|
+
# Returns the object before this one in the chain.
|
44
|
+
#
|
45
|
+
def prev
|
46
|
+
sibling(-1)
|
47
|
+
end
|
48
48
|
|
49
|
-
|
49
|
+
private
|
50
50
|
|
51
|
-
|
52
|
-
|
51
|
+
def sibling offset
|
52
|
+
arr = chain
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
end
|
54
|
+
if pos = arr.index(self)
|
55
|
+
arr[(pos + offset) % arr.length]
|
57
56
|
end
|
58
57
|
end
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# The basic building block of the WM hierarchy.
|
62
|
+
#
|
63
|
+
# @note Inheritors must define a {curr} class method.
|
64
|
+
# @note Inheritors must override the {focus} method.
|
65
|
+
#
|
66
|
+
module WidgetImpl
|
67
|
+
attr_reader :id
|
68
|
+
|
69
|
+
def == other
|
70
|
+
@id == other.id
|
71
|
+
end
|
59
72
|
|
60
73
|
##
|
61
|
-
#
|
62
|
-
#
|
63
|
-
# @note Inheritors must define a {curr} class method.
|
64
|
-
# @note Inheritors must override the {focus} method.
|
74
|
+
# Checks if this widget currently has focus.
|
65
75
|
#
|
66
|
-
|
67
|
-
|
76
|
+
def current?
|
77
|
+
self == self.class.curr
|
78
|
+
end
|
68
79
|
|
69
|
-
|
70
|
-
|
71
|
-
end
|
80
|
+
alias focus? current?
|
81
|
+
end
|
72
82
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
83
|
+
##
|
84
|
+
# A widget that has a corresponding representation in the IXP file system.
|
85
|
+
#
|
86
|
+
class WidgetNode < Node
|
87
|
+
include WidgetImpl
|
88
|
+
|
89
|
+
def initialize id, path_prefix
|
90
|
+
super "#{path_prefix}/#{id}"
|
91
|
+
|
92
|
+
if id == FOCUSED_WIDGET_ID and ctl.exist?
|
93
|
+
@id = ctl.read.split.first
|
94
|
+
super "#{path_prefix}/#{@id}"
|
95
|
+
else
|
96
|
+
@id = id.to_s
|
78
97
|
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# A graphical program that is running in your current X Windows session.
|
103
|
+
#
|
104
|
+
class Client < WidgetNode
|
105
|
+
def initialize client_id
|
106
|
+
super client_id, '/client'
|
107
|
+
end
|
79
108
|
|
80
|
-
|
109
|
+
##
|
110
|
+
# Returns the currently focused client.
|
111
|
+
#
|
112
|
+
def self.curr
|
113
|
+
new FOCUSED_WIDGET_ID
|
81
114
|
end
|
82
115
|
|
116
|
+
#-------------------------------------------------------------------------
|
117
|
+
include Chain
|
118
|
+
#-------------------------------------------------------------------------
|
119
|
+
|
83
120
|
##
|
84
|
-
#
|
121
|
+
# Returns a list of all clients in the current view.
|
85
122
|
#
|
86
|
-
|
87
|
-
|
123
|
+
def chain
|
124
|
+
View.curr.clients
|
125
|
+
end
|
88
126
|
|
89
|
-
|
90
|
-
|
127
|
+
#-------------------------------------------------------------------------
|
128
|
+
# WM operations
|
129
|
+
#-------------------------------------------------------------------------
|
91
130
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
131
|
+
##
|
132
|
+
# Focuses this client within the given view.
|
133
|
+
#
|
134
|
+
def focus view = nil
|
135
|
+
if exist? and not focus?
|
136
|
+
(view ? [view] : self.views).each do |v|
|
137
|
+
if a = self.area(v) and a.exist?
|
138
|
+
v.focus
|
139
|
+
a.focus
|
140
|
+
|
141
|
+
# slide focus from the current client onto this client
|
142
|
+
arr = a.client_ids
|
143
|
+
src = arr.index Client.curr.id
|
144
|
+
dst = arr.index @id
|
145
|
+
|
146
|
+
distance = (src - dst).abs
|
147
|
+
direction = src < dst ? :down : :up
|
148
|
+
|
149
|
+
distance.times { v.select direction }
|
150
|
+
break
|
151
|
+
end
|
97
152
|
end
|
98
153
|
end
|
99
154
|
end
|
100
155
|
|
101
156
|
##
|
102
|
-
#
|
157
|
+
# Sends this client to the given destination within the given view.
|
103
158
|
#
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
##
|
110
|
-
# Returns the currently focused client.
|
111
|
-
#
|
112
|
-
def self.curr
|
113
|
-
new FOCUSED_WIDGET_ID
|
114
|
-
end
|
115
|
-
|
116
|
-
include Chain
|
159
|
+
def send area_or_id, view = View.curr
|
160
|
+
dst = area_to_id(area_or_id)
|
161
|
+
view.ctl.write "send #{@id} #{dst}"
|
162
|
+
end
|
117
163
|
|
118
|
-
|
119
|
-
# Returns a list of all clients in the current view.
|
120
|
-
#
|
121
|
-
def chain
|
122
|
-
View.curr.clients
|
123
|
-
end
|
164
|
+
alias move send
|
124
165
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
def focus view = nil
|
133
|
-
if exist? and not focus?
|
134
|
-
(view ? [view] : self.views).each do |v|
|
135
|
-
if a = self.area(v) and a.exist?
|
136
|
-
v.focus
|
137
|
-
a.focus
|
138
|
-
|
139
|
-
# slide focus from the current client onto this client
|
140
|
-
arr = a.client_ids
|
141
|
-
src = arr.index Client.curr.id
|
142
|
-
dst = arr.index @id
|
143
|
-
|
144
|
-
distance = (src - dst).abs
|
145
|
-
direction = src < dst ? :down : :up
|
146
|
-
|
147
|
-
distance.times { v.select direction }
|
148
|
-
break
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
166
|
+
##
|
167
|
+
# Swaps this client with the given destination within the given view.
|
168
|
+
#
|
169
|
+
def swap area_or_id, view = View.curr
|
170
|
+
dst = area_to_id(area_or_id)
|
171
|
+
view.ctl.write "swap #{@id} #{dst}"
|
172
|
+
end
|
153
173
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
end
|
174
|
+
##
|
175
|
+
# Moves this client in the given direction on the given view.
|
176
|
+
#
|
177
|
+
def nudge direction, view = View.curr
|
178
|
+
reshape :nudge, direction, view
|
179
|
+
end
|
161
180
|
|
162
|
-
|
181
|
+
##
|
182
|
+
# Grows this client in the given direction on the given view.
|
183
|
+
#
|
184
|
+
def grow direction, view = View.curr
|
185
|
+
reshape :grow, direction, view
|
186
|
+
end
|
163
187
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
end
|
188
|
+
##
|
189
|
+
# Terminates this client nicely (requests this window to be closed).
|
190
|
+
#
|
191
|
+
def kill
|
192
|
+
ctl.write :kill
|
193
|
+
end
|
171
194
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
195
|
+
##
|
196
|
+
# Terminates this client forcefully.
|
197
|
+
#
|
198
|
+
def slay
|
199
|
+
ctl.write :slay
|
200
|
+
end
|
178
201
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
202
|
+
##
|
203
|
+
# Maximizes this client to occupy the
|
204
|
+
# entire screen on the current view.
|
205
|
+
#
|
206
|
+
def fullscreen
|
207
|
+
ctl.write 'Fullscreen on'
|
208
|
+
end
|
185
209
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
end
|
210
|
+
##
|
211
|
+
# Restores this client back to its original size on the current view.
|
212
|
+
#
|
213
|
+
def unfullscreen
|
214
|
+
ctl.write 'Fullscreen off'
|
215
|
+
end
|
193
216
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
217
|
+
##
|
218
|
+
# Toggles the fullscreen status of this client on the current view.
|
219
|
+
#
|
220
|
+
def fullscreen!
|
221
|
+
ctl.write 'Fullscreen toggle'
|
222
|
+
end
|
200
223
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
224
|
+
##
|
225
|
+
# Checks if this client is currently fullscreen on the current view.
|
226
|
+
#
|
227
|
+
def fullscreen?
|
228
|
+
#
|
229
|
+
# If the client's dimensions match those of the
|
230
|
+
# floating area, then we know it is fullscreen.
|
231
|
+
#
|
232
|
+
View.curr.manifest =~ /^# #{FLOATING_AREA_ID} (\d+) (\d+)\n.*^#{FLOATING_AREA_ID} #{@id} \d+ \d+ \1 \2 /m
|
233
|
+
end
|
207
234
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
# floating area, then we know it is fullscreen.
|
215
|
-
#
|
216
|
-
View.curr.manifest =~ /^# #{FLOATING_AREA_ID} (\d+) (\d+)\n.*^#{FLOATING_AREA_ID} #{@id} \d+ \d+ \1 \2 /m
|
217
|
-
end
|
235
|
+
##
|
236
|
+
# Checks if this client is sticky (appears in all views).
|
237
|
+
#
|
238
|
+
def stick?
|
239
|
+
tags.include? CLIENT_STICKY_TAG
|
240
|
+
end
|
218
241
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
242
|
+
##
|
243
|
+
# Makes this client sticky (appears in all views).
|
244
|
+
#
|
245
|
+
def stick
|
246
|
+
tag CLIENT_STICKY_TAG
|
247
|
+
end
|
225
248
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
249
|
+
##
|
250
|
+
# Makes this client unsticky (does not appear in all views).
|
251
|
+
#
|
252
|
+
def unstick
|
253
|
+
untag CLIENT_STICKY_TAG
|
254
|
+
end
|
232
255
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
256
|
+
##
|
257
|
+
# Toggles the stickyness of this client.
|
258
|
+
#
|
259
|
+
def stick!
|
260
|
+
if stick?
|
261
|
+
unstick
|
262
|
+
else
|
263
|
+
stick
|
264
|
+
end
|
265
|
+
end
|
239
266
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
else
|
247
|
-
stick
|
248
|
-
end
|
249
|
-
end
|
267
|
+
##
|
268
|
+
# Checks if this client is in the floating area of the given view.
|
269
|
+
#
|
270
|
+
def float? view = View.curr
|
271
|
+
area(view).floating?
|
272
|
+
end
|
250
273
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
274
|
+
##
|
275
|
+
# Puts this client into the floating area of the given view.
|
276
|
+
#
|
277
|
+
def float view = View.curr
|
278
|
+
send :toggle, view unless float? view
|
279
|
+
end
|
257
280
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
281
|
+
##
|
282
|
+
# Puts this client into the managed area of the given view.
|
283
|
+
#
|
284
|
+
def unfloat view = View.curr
|
285
|
+
send :toggle, view if float? view
|
286
|
+
end
|
264
287
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
288
|
+
##
|
289
|
+
# Toggles the floating status of this client in the given view.
|
290
|
+
#
|
291
|
+
def float! view = View.curr
|
292
|
+
send :toggle, view
|
293
|
+
end
|
271
294
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
end
|
295
|
+
##
|
296
|
+
# Checks if this client is in the managed area of the given view.
|
297
|
+
def manage? view = View.curr
|
298
|
+
not float? view
|
299
|
+
end
|
278
300
|
|
279
|
-
|
280
|
-
# Checks if this client is in the managed area of the given view.
|
281
|
-
def manage? view = View.curr
|
282
|
-
not float? view
|
283
|
-
end
|
301
|
+
alias manage unfloat
|
284
302
|
|
285
|
-
|
303
|
+
alias unmanage float
|
286
304
|
|
287
|
-
|
305
|
+
alias manage! float!
|
288
306
|
|
289
|
-
|
307
|
+
#-------------------------------------------------------------------------
|
308
|
+
# WM hierarchy
|
309
|
+
#-------------------------------------------------------------------------
|
290
310
|
|
291
|
-
|
292
|
-
|
293
|
-
|
311
|
+
##
|
312
|
+
# Returns the area that contains this client within the given view.
|
313
|
+
#
|
314
|
+
def area view = View.curr
|
315
|
+
view.area_of_client self
|
316
|
+
end
|
294
317
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
318
|
+
##
|
319
|
+
# Returns the views that contain this client.
|
320
|
+
#
|
321
|
+
def views
|
322
|
+
tags.map! {|t| View.new t }
|
323
|
+
end
|
301
324
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
def views
|
306
|
-
tags.map! {|t| View.new t }
|
307
|
-
end
|
325
|
+
#-------------------------------------------------------------------------
|
326
|
+
# tag manipulations
|
327
|
+
#-------------------------------------------------------------------------
|
308
328
|
|
309
|
-
|
310
|
-
# tag manipulations
|
311
|
-
#-----------------------------------------------------------------------
|
329
|
+
TAG_DELIMITER = '+'.freeze
|
312
330
|
|
313
|
-
|
331
|
+
##
|
332
|
+
# Returns the tags associated with this client.
|
333
|
+
#
|
334
|
+
def tags
|
335
|
+
self[:tags].read.split TAG_DELIMITER
|
336
|
+
end
|
314
337
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
338
|
+
##
|
339
|
+
# Modifies the tags associated with this client.
|
340
|
+
#
|
341
|
+
# If a tag name is '~', this client is placed
|
342
|
+
# into the floating layer of the current view.
|
343
|
+
#
|
344
|
+
# If a tag name begins with '~', then this
|
345
|
+
# client is placed into the floating layer
|
346
|
+
# of the view corresponding to that tag.
|
347
|
+
#
|
348
|
+
# If a tag name is '!', this client is placed
|
349
|
+
# into the managed layer of the current view.
|
350
|
+
#
|
351
|
+
# If a tag name begins with '!', then this
|
352
|
+
# client is placed into the managed layer
|
353
|
+
# of the view corresponding to that tag.
|
354
|
+
#
|
355
|
+
def tags= *tags
|
356
|
+
float = []
|
357
|
+
manage = []
|
358
|
+
inherit = []
|
359
|
+
|
360
|
+
tags.join(TAG_DELIMITER).split(TAG_DELIMITER).each do |tag|
|
361
|
+
case tag
|
362
|
+
when '~' then float << Rumai.curr_tag
|
363
|
+
when /^~/ then float << $'
|
364
|
+
when '!' then manage << Rumai.curr_tag
|
365
|
+
when /^!/ then manage << $'
|
366
|
+
else inherit << tag
|
320
367
|
end
|
368
|
+
end
|
321
369
|
|
322
|
-
|
323
|
-
# Modifies the tags associated with this client.
|
324
|
-
#
|
325
|
-
# If a tag name is '~', this client is placed
|
326
|
-
# into the floating layer of the current view.
|
327
|
-
#
|
328
|
-
# If a tag name begins with '~', then this
|
329
|
-
# client is placed into the floating layer
|
330
|
-
# of the view corresponding to that tag.
|
331
|
-
#
|
332
|
-
# If a tag name is '!', this client is placed
|
333
|
-
# into the managed layer of the current view.
|
334
|
-
#
|
335
|
-
# If a tag name begins with '!', then this
|
336
|
-
# client is placed into the managed layer
|
337
|
-
# of the view corresponding to that tag.
|
338
|
-
#
|
339
|
-
def tags= *tags
|
340
|
-
float = []
|
341
|
-
manage = []
|
342
|
-
inherit = []
|
343
|
-
|
344
|
-
tags.join(TAG_DELIMITER).split(TAG_DELIMITER).each do |tag|
|
345
|
-
case tag
|
346
|
-
when '~' then float << Rumai.curr_tag
|
347
|
-
when /^~/ then float << $'
|
348
|
-
when '!' then manage << Rumai.curr_tag
|
349
|
-
when /^!/ then manage << $'
|
350
|
-
else inherit << tag
|
351
|
-
end
|
352
|
-
end
|
370
|
+
self[:tags].write((float + manage + inherit).uniq.join(TAG_DELIMITER))
|
353
371
|
|
354
|
-
|
372
|
+
float.each do |tag|
|
373
|
+
self.float View.new(tag)
|
374
|
+
end
|
355
375
|
|
356
|
-
|
357
|
-
|
358
|
-
|
376
|
+
manage.each do |tag|
|
377
|
+
self.manage View.new(tag)
|
378
|
+
end
|
379
|
+
end
|
359
380
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
381
|
+
##
|
382
|
+
# Evaluates the given block within the
|
383
|
+
# context of this client's list of tags.
|
384
|
+
#
|
385
|
+
def with_tags &block
|
386
|
+
arr = self.tags
|
387
|
+
arr.instance_eval(&block)
|
388
|
+
self.tags = arr
|
389
|
+
end
|
364
390
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
end
|
391
|
+
##
|
392
|
+
# Adds the given tags to this client.
|
393
|
+
#
|
394
|
+
def tag *tags
|
395
|
+
with_tags do
|
396
|
+
concat tags
|
397
|
+
end
|
398
|
+
end
|
374
399
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
400
|
+
##
|
401
|
+
# Removes the given tags from this client.
|
402
|
+
#
|
403
|
+
def untag *tags
|
404
|
+
with_tags do
|
405
|
+
tags.flatten.each do |tag|
|
406
|
+
delete tag.to_s
|
382
407
|
end
|
408
|
+
end
|
409
|
+
end
|
383
410
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
def untag *tags
|
388
|
-
with_tags do
|
389
|
-
tags.flatten.each do |tag|
|
390
|
-
delete tag.to_s
|
391
|
-
end
|
392
|
-
end
|
393
|
-
end
|
411
|
+
#-------------------------------------------------------------------------
|
412
|
+
# multiple client grouping
|
413
|
+
#-------------------------------------------------------------------------
|
394
414
|
|
395
|
-
|
396
|
-
|
397
|
-
|
415
|
+
##
|
416
|
+
# Checks if this client is included in the current grouping.
|
417
|
+
#
|
418
|
+
def group?
|
419
|
+
tags.include? CLIENT_GROUPING_TAG
|
420
|
+
end
|
398
421
|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
422
|
+
##
|
423
|
+
# Adds this client to the current grouping.
|
424
|
+
#
|
425
|
+
def group
|
426
|
+
with_tags do
|
427
|
+
push CLIENT_GROUPING_TAG
|
428
|
+
end
|
429
|
+
end
|
405
430
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
end
|
413
|
-
end
|
431
|
+
##
|
432
|
+
# Removes this client to the current grouping.
|
433
|
+
#
|
434
|
+
def ungroup
|
435
|
+
untag CLIENT_GROUPING_TAG
|
436
|
+
end
|
414
437
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
438
|
+
##
|
439
|
+
# Toggles the presence of this client in the current grouping.
|
440
|
+
#
|
441
|
+
def group!
|
442
|
+
if group?
|
443
|
+
ungroup
|
444
|
+
else
|
445
|
+
group
|
446
|
+
end
|
447
|
+
end
|
421
448
|
|
422
|
-
|
423
|
-
# Toggles the presence of this client in the current grouping.
|
424
|
-
#
|
425
|
-
def group!
|
426
|
-
if group?
|
427
|
-
ungroup
|
428
|
-
else
|
429
|
-
group
|
430
|
-
end
|
431
|
-
end
|
449
|
+
private
|
432
450
|
|
433
|
-
|
451
|
+
def reshape method, direction, view
|
452
|
+
area = self.area(view)
|
453
|
+
index = area.client_ids.index(@id) + 1 # numbered as 1..N
|
454
|
+
view.ctl.write "#{method} #{area.id} #{index} #{direction}"
|
455
|
+
end
|
434
456
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
end
|
457
|
+
##
|
458
|
+
# Returns the wmii ID of the given area.
|
459
|
+
#
|
460
|
+
def area_to_id area_or_id
|
461
|
+
if area_or_id.respond_to? :id
|
462
|
+
id = area_or_id.id
|
463
|
+
id == FLOATING_AREA_ID ? :toggle : id
|
464
|
+
else
|
465
|
+
area_or_id
|
445
466
|
end
|
446
467
|
end
|
468
|
+
end
|
447
469
|
|
470
|
+
##
|
471
|
+
# @note Inheritors should override the {client_ids} method.
|
472
|
+
#
|
473
|
+
module ClientContainer
|
448
474
|
##
|
449
|
-
#
|
475
|
+
# Returns the IDs of the clients in this container.
|
450
476
|
#
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
#
|
455
|
-
def client_ids
|
456
|
-
[]
|
457
|
-
end
|
477
|
+
def client_ids
|
478
|
+
[]
|
479
|
+
end
|
458
480
|
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
481
|
+
##
|
482
|
+
# Returns the clients contained in this container.
|
483
|
+
#
|
484
|
+
def clients
|
485
|
+
client_ids.map! {|i| Client.new i }
|
486
|
+
end
|
465
487
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
end
|
488
|
+
# multiple client grouping
|
489
|
+
%w[group ungroup group!].each do |meth|
|
490
|
+
define_method meth do
|
491
|
+
clients.each do |c|
|
492
|
+
c.__send__ meth
|
472
493
|
end
|
473
494
|
end
|
495
|
+
end
|
474
496
|
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
end
|
497
|
+
##
|
498
|
+
# Returns all grouped clients in this container.
|
499
|
+
#
|
500
|
+
def grouping
|
501
|
+
clients.select {|c| c.group? }
|
481
502
|
end
|
503
|
+
end
|
504
|
+
|
505
|
+
##
|
506
|
+
# A region that contains clients. This can be either
|
507
|
+
# the floating area or a column in the managed area.
|
508
|
+
#
|
509
|
+
class Area
|
510
|
+
attr_reader :view
|
482
511
|
|
483
512
|
##
|
484
|
-
#
|
485
|
-
#
|
513
|
+
# @param [Rumai::View] view
|
514
|
+
# the view object which contains this area
|
486
515
|
#
|
487
|
-
|
488
|
-
|
516
|
+
def initialize area_id, view = View.curr
|
517
|
+
@id = Integer(area_id) rescue area_id
|
518
|
+
@view = view
|
519
|
+
end
|
489
520
|
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
@view = view
|
497
|
-
end
|
521
|
+
##
|
522
|
+
# Checks if this area is the floating area.
|
523
|
+
#
|
524
|
+
def floating?
|
525
|
+
@id == FLOATING_AREA_ID
|
526
|
+
end
|
498
527
|
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
528
|
+
##
|
529
|
+
# Checks if this is a managed area (a column).
|
530
|
+
#
|
531
|
+
def column?
|
532
|
+
not floating?
|
533
|
+
end
|
505
534
|
|
506
|
-
|
507
|
-
# Checks if this is a managed area (a column).
|
508
|
-
#
|
509
|
-
def column?
|
510
|
-
not floating?
|
511
|
-
end
|
535
|
+
alias managed? column?
|
512
536
|
|
513
|
-
|
537
|
+
#-------------------------------------------------------------------------
|
538
|
+
include WidgetImpl
|
539
|
+
#-------------------------------------------------------------------------
|
514
540
|
|
515
|
-
|
541
|
+
##
|
542
|
+
# Returns the currently focused area.
|
543
|
+
#
|
544
|
+
def self.curr
|
545
|
+
View.curr.area_of_client Client.curr
|
546
|
+
end
|
516
547
|
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
548
|
+
##
|
549
|
+
# Returns the floating area in the given view.
|
550
|
+
#
|
551
|
+
def self.floating view = View.curr
|
552
|
+
new FLOATING_AREA_ID, view
|
553
|
+
end
|
523
554
|
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
def self.floating view = View.curr
|
528
|
-
new FLOATING_AREA_ID, view
|
529
|
-
end
|
555
|
+
#-------------------------------------------------------------------------
|
556
|
+
include Chain
|
557
|
+
#-------------------------------------------------------------------------
|
530
558
|
|
531
|
-
|
559
|
+
##
|
560
|
+
# Returns a list of all areas in the current view.
|
561
|
+
#
|
562
|
+
def chain
|
563
|
+
@view.areas
|
564
|
+
end
|
532
565
|
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
566
|
+
##
|
567
|
+
# Checks if this object exists in the chain.
|
568
|
+
#
|
569
|
+
def exist?
|
570
|
+
chain.include? self
|
571
|
+
end
|
539
572
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
def exist?
|
544
|
-
chain.include? self
|
545
|
-
end
|
573
|
+
#-------------------------------------------------------------------------
|
574
|
+
include ClientContainer
|
575
|
+
#-------------------------------------------------------------------------
|
546
576
|
|
547
|
-
|
577
|
+
##
|
578
|
+
# Returns the IDs of the clients in this area.
|
579
|
+
#
|
580
|
+
def client_ids
|
581
|
+
@view.client_ids @id
|
582
|
+
end
|
548
583
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
def client_ids
|
553
|
-
@view.client_ids @id
|
554
|
-
end
|
584
|
+
#-------------------------------------------------------------------------
|
585
|
+
include Enumerable
|
586
|
+
#-------------------------------------------------------------------------
|
555
587
|
|
556
|
-
|
588
|
+
##
|
589
|
+
# Iterates through each client in this container.
|
590
|
+
#
|
591
|
+
def each &block
|
592
|
+
clients.each(&block)
|
593
|
+
end
|
557
594
|
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
def each &block
|
562
|
-
clients.each(&block)
|
563
|
-
end
|
595
|
+
#-------------------------------------------------------------------------
|
596
|
+
# WM operations
|
597
|
+
#-------------------------------------------------------------------------
|
564
598
|
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
when :max then mode = 'stack+max'
|
572
|
-
end
|
599
|
+
##
|
600
|
+
# Puts focus on this area.
|
601
|
+
#
|
602
|
+
def focus
|
603
|
+
@view.ctl.write "select #{@id}"
|
604
|
+
end
|
573
605
|
|
574
|
-
|
606
|
+
##
|
607
|
+
# Sets the layout of clients in this column.
|
608
|
+
#
|
609
|
+
def layout= mode
|
610
|
+
case mode
|
611
|
+
when :stack then mode = 'stack-max'
|
612
|
+
when :max then mode = 'stack+max'
|
575
613
|
end
|
576
614
|
|
577
|
-
|
578
|
-
|
579
|
-
#-----------------------------------------------------------------------
|
615
|
+
@view.ctl.write "colmode #{@id} #{mode}"
|
616
|
+
end
|
580
617
|
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
618
|
+
#-------------------------------------------------------------------------
|
619
|
+
# array abstraction: area is an array of clients
|
620
|
+
#-------------------------------------------------------------------------
|
621
|
+
|
622
|
+
##
|
623
|
+
# Returns the number of clients in this area.
|
624
|
+
#
|
625
|
+
def length
|
626
|
+
client_ids.length
|
627
|
+
end
|
587
628
|
|
588
|
-
|
589
|
-
|
590
|
-
|
629
|
+
##
|
630
|
+
# Inserts the given clients at the bottom of this area.
|
631
|
+
#
|
632
|
+
def push *clients
|
633
|
+
clients.flatten!
|
634
|
+
return if clients.empty?
|
591
635
|
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
636
|
+
insert clients
|
637
|
+
|
638
|
+
# move inserted clients to bottom
|
639
|
+
clients.reverse.each_with_index do |c, i|
|
640
|
+
until c.id == self.client_ids[-i.succ]
|
641
|
+
c.send :down
|
597
642
|
end
|
643
|
+
end
|
644
|
+
end
|
598
645
|
|
599
|
-
|
600
|
-
# Inserts the given clients at the bottom of this area.
|
601
|
-
#
|
602
|
-
def push *clients
|
603
|
-
clients.flatten!
|
604
|
-
return if clients.empty?
|
646
|
+
alias << push
|
605
647
|
|
606
|
-
|
648
|
+
##
|
649
|
+
# Inserts the given clients after the
|
650
|
+
# currently focused client in this area.
|
651
|
+
#
|
652
|
+
def insert *clients
|
653
|
+
clients.flatten!
|
654
|
+
return if clients.empty?
|
607
655
|
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
end
|
613
|
-
end
|
614
|
-
end
|
656
|
+
clients.each do |c|
|
657
|
+
import_client c
|
658
|
+
end
|
659
|
+
end
|
615
660
|
|
616
|
-
|
661
|
+
##
|
662
|
+
# Inserts the given clients at the top of this area.
|
663
|
+
#
|
664
|
+
def unshift *clients
|
665
|
+
clients.flatten!
|
666
|
+
return if clients.empty?
|
617
667
|
|
618
|
-
|
619
|
-
# Inserts the given clients after the
|
620
|
-
# currently focused client in this area.
|
621
|
-
#
|
622
|
-
def insert *clients
|
623
|
-
clients.flatten!
|
624
|
-
return if clients.empty?
|
668
|
+
insert clients
|
625
669
|
|
626
|
-
|
627
|
-
|
628
|
-
|
670
|
+
# move inserted clients to top
|
671
|
+
clients.each_with_index do |c, i|
|
672
|
+
until c.id == self.client_ids[i]
|
673
|
+
c.send :up
|
629
674
|
end
|
675
|
+
end
|
676
|
+
end
|
630
677
|
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
678
|
+
##
|
679
|
+
# Concatenates the given area to the bottom of this area.
|
680
|
+
#
|
681
|
+
def concat area
|
682
|
+
push area.clients
|
683
|
+
end
|
637
684
|
|
638
|
-
|
685
|
+
##
|
686
|
+
# Ensures that this area has at most the given number of clients.
|
687
|
+
#
|
688
|
+
# Areas to the right of this one serve as a buffer into which excess
|
689
|
+
# clients are evicted and from which deficit clients are imported.
|
690
|
+
#
|
691
|
+
def length= max_clients
|
692
|
+
return unless max_clients > 0
|
693
|
+
len, out = length, fringe
|
639
694
|
|
640
|
-
|
641
|
-
|
642
|
-
until c.id == self.client_ids[i]
|
643
|
-
c.send :up
|
644
|
-
end
|
645
|
-
end
|
646
|
-
end
|
695
|
+
if len > max_clients
|
696
|
+
out.unshift clients[max_clients..-1]
|
647
697
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
push area.clients
|
653
|
-
end
|
698
|
+
elsif len < max_clients
|
699
|
+
until (diff = max_clients - length) == 0
|
700
|
+
importable = out.clients[0, diff]
|
701
|
+
break if importable.empty?
|
654
702
|
|
655
|
-
|
656
|
-
# Ensures that this area has at most the given number of clients.
|
657
|
-
#
|
658
|
-
# Areas to the right of this one serve as a buffer into which excess
|
659
|
-
# clients are evicted and from which deficit clients are imported.
|
660
|
-
#
|
661
|
-
def length= max_clients
|
662
|
-
return unless max_clients > 0
|
663
|
-
len, out = length, fringe
|
664
|
-
|
665
|
-
if len > max_clients
|
666
|
-
out.unshift clients[max_clients..-1]
|
667
|
-
|
668
|
-
elsif len < max_clients
|
669
|
-
until (diff = max_clients - length) == 0
|
670
|
-
importable = out.clients[0, diff]
|
671
|
-
break if importable.empty?
|
672
|
-
|
673
|
-
push importable
|
674
|
-
end
|
675
|
-
end
|
703
|
+
push importable
|
676
704
|
end
|
705
|
+
end
|
706
|
+
end
|
677
707
|
|
678
|
-
|
708
|
+
private
|
679
709
|
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
else
|
688
|
-
# move the client to the nearest existing column
|
689
|
-
src = c.area
|
690
|
-
dst = chain.last
|
710
|
+
##
|
711
|
+
# Moves the given client into this area.
|
712
|
+
#
|
713
|
+
def import_client c
|
714
|
+
if exist?
|
715
|
+
c.send self
|
691
716
|
|
692
|
-
|
717
|
+
else
|
718
|
+
# move the client to the nearest existing column
|
719
|
+
src = c.area
|
720
|
+
dst = chain.last
|
693
721
|
|
694
|
-
|
695
|
-
c.send :right
|
696
|
-
@id = dst.id.next
|
722
|
+
c.send dst unless src == dst
|
697
723
|
|
698
|
-
|
699
|
-
|
700
|
-
|
724
|
+
# slide the client over to this column
|
725
|
+
c.send :right
|
726
|
+
@id = dst.id.next
|
701
727
|
|
702
|
-
|
703
|
-
# Returns the next area, which may or may not exist.
|
704
|
-
#
|
705
|
-
def fringe
|
706
|
-
Area.new @id.next, @view
|
728
|
+
raise 'column should exist now' unless exist?
|
707
729
|
end
|
708
730
|
end
|
709
731
|
|
710
732
|
##
|
711
|
-
#
|
733
|
+
# Returns the next area, which may or may not exist.
|
712
734
|
#
|
713
|
-
|
714
|
-
|
735
|
+
def fringe
|
736
|
+
Area.new @id.next, @view
|
737
|
+
end
|
738
|
+
end
|
739
|
+
|
740
|
+
##
|
741
|
+
# The visualization of a tag.
|
742
|
+
#
|
743
|
+
class View < WidgetNode
|
744
|
+
def initialize view_id
|
745
|
+
super view_id, '/tag'
|
746
|
+
end
|
715
747
|
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
def self.curr
|
720
|
-
new FOCUSED_WIDGET_ID
|
721
|
-
end
|
748
|
+
#-------------------------------------------------------------------------
|
749
|
+
include WidgetImpl
|
750
|
+
#-------------------------------------------------------------------------
|
722
751
|
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
752
|
+
##
|
753
|
+
# Returns the currently focused view.
|
754
|
+
#
|
755
|
+
def self.curr
|
756
|
+
new FOCUSED_WIDGET_ID
|
757
|
+
end
|
729
758
|
|
730
|
-
|
759
|
+
##
|
760
|
+
# Focuses this view.
|
761
|
+
#
|
762
|
+
def focus
|
763
|
+
IXP_FS_ROOT.ctl.write "view #{@id}"
|
764
|
+
end
|
731
765
|
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
def chain
|
736
|
-
Rumai.views
|
737
|
-
end
|
766
|
+
#-------------------------------------------------------------------------
|
767
|
+
include Chain
|
768
|
+
#-------------------------------------------------------------------------
|
738
769
|
|
739
|
-
|
770
|
+
##
|
771
|
+
# Returns a list of all views.
|
772
|
+
#
|
773
|
+
def chain
|
774
|
+
Rumai.views
|
775
|
+
end
|
740
776
|
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
#
|
745
|
-
def client_ids area_id = '\S+'
|
746
|
-
manifest.scan(/^#{area_id} (0x\S+)/).flatten
|
747
|
-
end
|
777
|
+
#-------------------------------------------------------------------------
|
778
|
+
include ClientContainer
|
779
|
+
#-------------------------------------------------------------------------
|
748
780
|
|
749
|
-
|
781
|
+
##
|
782
|
+
# Returns the IDs of the clients contained
|
783
|
+
# in the given area within this view.
|
784
|
+
#
|
785
|
+
def client_ids area_id = '\S+'
|
786
|
+
manifest.scan(/^#{area_id} (0x\S+)/).flatten
|
787
|
+
end
|
750
788
|
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
def each &block
|
755
|
-
areas.each(&block)
|
756
|
-
end
|
789
|
+
#-------------------------------------------------------------------------
|
790
|
+
include Enumerable
|
791
|
+
#-------------------------------------------------------------------------
|
757
792
|
|
758
|
-
|
759
|
-
|
760
|
-
|
793
|
+
##
|
794
|
+
# Iterates through each area in this view.
|
795
|
+
#
|
796
|
+
def each &block
|
797
|
+
areas.each(&block)
|
798
|
+
end
|
761
799
|
|
762
|
-
|
763
|
-
|
764
|
-
|
800
|
+
#-----------------------------------------------------------------------
|
801
|
+
# WM operations
|
802
|
+
#-----------------------------------------------------------------------
|
765
803
|
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
804
|
+
##
|
805
|
+
# Returns the manifest of all areas and clients in this view.
|
806
|
+
#
|
807
|
+
def manifest
|
808
|
+
index.read || ''
|
809
|
+
end
|
772
810
|
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
811
|
+
##
|
812
|
+
# Moves the focus from the current client in the given direction.
|
813
|
+
#
|
814
|
+
def select direction
|
815
|
+
ctl.write "select #{direction}"
|
816
|
+
end
|
779
817
|
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
##
|
785
|
-
# Returns the area which contains the given client in this view.
|
786
|
-
#
|
787
|
-
def area_of_client client_or_id
|
788
|
-
arg =
|
789
|
-
if client_or_id.respond_to? :id
|
790
|
-
client_or_id.id
|
791
|
-
else
|
792
|
-
client_or_id
|
793
|
-
end
|
794
|
-
|
795
|
-
manifest =~ /^(\S+) #{arg}/
|
796
|
-
if area_id = $1
|
797
|
-
Area.new area_id, self
|
798
|
-
end
|
799
|
-
end
|
818
|
+
#-----------------------------------------------------------------------
|
819
|
+
# WM hierarchy
|
820
|
+
#-----------------------------------------------------------------------
|
800
821
|
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
822
|
+
##
|
823
|
+
# Returns the area which contains the given client in this view.
|
824
|
+
#
|
825
|
+
def area_of_client client_or_id
|
826
|
+
arg =
|
827
|
+
if client_or_id.respond_to? :id
|
828
|
+
client_or_id.id
|
829
|
+
else
|
830
|
+
client_or_id
|
806
831
|
end
|
807
832
|
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
end
|
833
|
+
manifest =~ /^(\S+) #{arg}/
|
834
|
+
if area_id = $1
|
835
|
+
Area.new area_id, self
|
836
|
+
end
|
837
|
+
end
|
814
838
|
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
839
|
+
##
|
840
|
+
# Returns the IDs of all areas in this view.
|
841
|
+
#
|
842
|
+
def area_ids
|
843
|
+
manifest.scan(/^# (\d+)/).flatten.unshift(FLOATING_AREA_ID)
|
844
|
+
end
|
821
845
|
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
846
|
+
##
|
847
|
+
# Returns all areas in this view.
|
848
|
+
#
|
849
|
+
def areas
|
850
|
+
area_ids.map! {|i| Area.new i, self }
|
851
|
+
end
|
828
852
|
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
#
|
836
|
-
def each_column starting_column_id = 1
|
837
|
-
i = starting_column_id
|
838
|
-
loop do
|
839
|
-
a = Area.new i, self
|
840
|
-
|
841
|
-
if a.exist?
|
842
|
-
yield a
|
843
|
-
else
|
844
|
-
break
|
845
|
-
end
|
846
|
-
|
847
|
-
i += 1
|
848
|
-
end
|
849
|
-
end
|
853
|
+
##
|
854
|
+
# Returns the floating area of this view.
|
855
|
+
#
|
856
|
+
def floating_area
|
857
|
+
Area.floating self
|
858
|
+
end
|
850
859
|
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
##
|
858
|
-
# Arranges the clients in this view, while maintaining
|
859
|
-
# their relative order, in the tiling fashion of LarsWM.
|
860
|
-
#
|
861
|
-
# Only the first client in the primary column is kept; all others
|
862
|
-
# are evicted to the *top* of the secondary column. Any subsequent
|
863
|
-
# columns are squeezed into the *bottom* of the secondary column.
|
864
|
-
#
|
865
|
-
def arrange_as_larswm
|
866
|
-
maintain_focus do
|
867
|
-
# keep only one client in the primary column
|
868
|
-
main = Area.new(1, self)
|
869
|
-
main.length = 1
|
870
|
-
main.layout = :default
|
871
|
-
|
872
|
-
# collapse remaining areas into secondary column
|
873
|
-
extra = squeeze_columns(1..-1)
|
874
|
-
|
875
|
-
if dock = extra.first
|
876
|
-
dock.layout = :default
|
877
|
-
end
|
878
|
-
end
|
879
|
-
end
|
860
|
+
##
|
861
|
+
# Returns all columns (managed areas) in this view.
|
862
|
+
#
|
863
|
+
def columns
|
864
|
+
areas[1..-1]
|
865
|
+
end
|
880
866
|
|
881
|
-
|
882
|
-
# Arranges the clients in this view, while maintaining
|
883
|
-
# their relative order, in a (at best) square grid.
|
884
|
-
#
|
885
|
-
def arrange_in_grid max_clients_per_column = nil
|
886
|
-
# compute client distribution
|
887
|
-
unless max_clients_per_column
|
888
|
-
num_clients = num_managed_clients
|
889
|
-
return unless num_clients > 0
|
890
|
-
|
891
|
-
num_columns = Math.sqrt(num_clients)
|
892
|
-
max_clients_per_column = (num_clients / num_columns).round
|
893
|
-
end
|
867
|
+
alias managed_areas columns
|
894
868
|
|
895
|
-
|
869
|
+
##
|
870
|
+
# Resiliently iterates through possibly destructive changes to
|
871
|
+
# each column. That is, if the given block creates new
|
872
|
+
# columns, then those will also be processed in the iteration.
|
873
|
+
#
|
874
|
+
def each_column starting_column_id = 1
|
875
|
+
i = starting_column_id
|
876
|
+
loop do
|
877
|
+
a = Area.new i, self
|
896
878
|
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
a.layout = :default
|
902
|
-
end
|
903
|
-
end
|
879
|
+
if a.exist?
|
880
|
+
yield a
|
881
|
+
else
|
882
|
+
break
|
904
883
|
end
|
905
884
|
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
#
|
910
|
-
def arrange_in_stacks num_stacks
|
911
|
-
return if num_stacks < 1
|
912
|
-
|
913
|
-
# compute client distribution
|
914
|
-
num_clients = num_managed_clients
|
915
|
-
return unless num_clients > 0
|
885
|
+
i += 1
|
886
|
+
end
|
887
|
+
end
|
916
888
|
|
917
|
-
|
918
|
-
return if stack_length < 1
|
889
|
+
alias each_managed_area each_column
|
919
890
|
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
a.length = stack_length
|
924
|
-
a.layout = :stack
|
925
|
-
end
|
891
|
+
#-------------------------------------------------------------------------
|
892
|
+
# visual arrangement of clients
|
893
|
+
#-----------------------------------------------------------------------
|
926
894
|
|
927
|
-
|
928
|
-
|
929
|
-
|
895
|
+
##
|
896
|
+
# Arranges the clients in this view, while maintaining
|
897
|
+
# their relative order, in the tiling fashion of LarsWM.
|
898
|
+
#
|
899
|
+
# Only the first client in the primary column is kept; all others
|
900
|
+
# are evicted to the *top* of the secondary column. Any subsequent
|
901
|
+
# columns are squeezed into the *bottom* of the secondary column.
|
902
|
+
#
|
903
|
+
def arrange_as_larswm
|
904
|
+
maintain_focus do
|
905
|
+
# keep only one client in the primary column
|
906
|
+
main = Area.new(1, self)
|
907
|
+
main.length = 1
|
908
|
+
main.layout = :default
|
930
909
|
|
931
|
-
|
932
|
-
|
933
|
-
# maintaining their relative order, in a (at
|
934
|
-
# best) equilateral triangle. However, the
|
935
|
-
# resulting arrangement appears like a diamond
|
936
|
-
# because wmii does not waste screen space.
|
937
|
-
#
|
938
|
-
def arrange_in_diamond
|
939
|
-
num_clients = num_managed_clients
|
940
|
-
return unless num_clients > 1
|
941
|
-
|
942
|
-
# determine dimensions of the rising sub-triangle
|
943
|
-
rise = num_clients / 2
|
944
|
-
|
945
|
-
span = sum = 0
|
946
|
-
1.upto rise do |h|
|
947
|
-
if sum + h > rise
|
948
|
-
break
|
949
|
-
else
|
950
|
-
sum += h
|
951
|
-
span += 1
|
952
|
-
end
|
953
|
-
end
|
910
|
+
# collapse remaining areas into secondary column
|
911
|
+
extra = squeeze_columns(1..-1)
|
954
912
|
|
955
|
-
|
913
|
+
if dock = extra.first
|
914
|
+
dock.layout = :default
|
915
|
+
end
|
916
|
+
end
|
917
|
+
end
|
956
918
|
|
957
|
-
|
958
|
-
|
959
|
-
|
919
|
+
##
|
920
|
+
# Arranges the clients in this view, while maintaining
|
921
|
+
# their relative order, in a (at best) square grid.
|
922
|
+
#
|
923
|
+
def arrange_in_grid max_clients_per_column = nil
|
924
|
+
# compute client distribution
|
925
|
+
unless max_clients_per_column
|
926
|
+
num_clients = num_managed_clients
|
927
|
+
return unless num_clients > 0
|
928
|
+
|
929
|
+
num_columns = Math.sqrt(num_clients)
|
930
|
+
max_clients_per_column = (num_clients / num_columns).round
|
931
|
+
end
|
960
932
|
|
961
|
-
|
962
|
-
heights << peak if peak > 0
|
963
|
-
heights.concat fall_seq
|
933
|
+
return if max_clients_per_column < 1
|
964
934
|
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
col.layout = :default
|
971
|
-
end
|
972
|
-
end
|
973
|
-
end
|
935
|
+
# apply the distribution
|
936
|
+
maintain_focus do
|
937
|
+
each_column do |a|
|
938
|
+
a.length = max_clients_per_column
|
939
|
+
a.layout = :default
|
974
940
|
end
|
941
|
+
end
|
942
|
+
end
|
975
943
|
|
976
|
-
|
944
|
+
##
|
945
|
+
# Arranges the clients in this view, while maintaining
|
946
|
+
# their relative order, in the given number of columns.
|
947
|
+
#
|
948
|
+
def arrange_in_stacks num_stacks
|
949
|
+
return if num_stacks < 1
|
977
950
|
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
def squeeze_columns range
|
982
|
-
extra = columns[range]
|
951
|
+
# compute client distribution
|
952
|
+
num_clients = num_managed_clients
|
953
|
+
return unless num_clients > 0
|
983
954
|
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
955
|
+
stack_length = num_clients / num_stacks
|
956
|
+
return if stack_length < 1
|
957
|
+
|
958
|
+
# apply the distribution
|
959
|
+
maintain_focus do
|
960
|
+
each_column do |a|
|
961
|
+
a.length = stack_length
|
962
|
+
a.layout = :stack
|
988
963
|
end
|
989
964
|
|
990
|
-
|
965
|
+
squeeze_columns num_stacks-1..-1
|
991
966
|
end
|
967
|
+
end
|
992
968
|
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
969
|
+
##
|
970
|
+
# Arranges the clients in this view, while
|
971
|
+
# maintaining their relative order, in a (at
|
972
|
+
# best) equilateral triangle. However, the
|
973
|
+
# resulting arrangement appears like a diamond
|
974
|
+
# because wmii does not waste screen space.
|
975
|
+
#
|
976
|
+
def arrange_in_diamond
|
977
|
+
num_clients = num_managed_clients
|
978
|
+
return unless num_clients > 1
|
979
|
+
|
980
|
+
# determine dimensions of the rising sub-triangle
|
981
|
+
rise = num_clients / 2
|
982
|
+
|
983
|
+
span = sum = 0
|
984
|
+
1.upto rise do |h|
|
985
|
+
if sum + h > rise
|
986
|
+
break
|
987
|
+
else
|
988
|
+
sum += h
|
989
|
+
span += 1
|
990
|
+
end
|
1002
991
|
end
|
1003
992
|
|
1004
|
-
|
1005
|
-
|
1006
|
-
#
|
1007
|
-
|
1008
|
-
|
993
|
+
peak = num_clients - (sum * 2)
|
994
|
+
|
995
|
+
# quantify overall triangle as a sequence of heights
|
996
|
+
rise_seq = (1..span).to_a
|
997
|
+
fall_seq = rise_seq.reverse
|
998
|
+
|
999
|
+
heights = rise_seq
|
1000
|
+
heights << peak if peak > 0
|
1001
|
+
heights.concat fall_seq
|
1002
|
+
|
1003
|
+
# apply the heights
|
1004
|
+
maintain_focus do
|
1005
|
+
each_column do |col|
|
1006
|
+
if h = heights.shift
|
1007
|
+
col.length = h
|
1008
|
+
col.layout = :default
|
1009
|
+
end
|
1010
|
+
end
|
1009
1011
|
end
|
1010
1012
|
end
|
1011
1013
|
|
1012
|
-
|
1013
|
-
# access to global WM state
|
1014
|
-
#---------------------------------------------------------------------------
|
1014
|
+
private
|
1015
1015
|
|
1016
1016
|
##
|
1017
|
-
#
|
1017
|
+
# Squeezes all columns in the given index range into a single one.
|
1018
1018
|
#
|
1019
|
-
def
|
1020
|
-
|
1019
|
+
def squeeze_columns range
|
1020
|
+
extra = columns[range]
|
1021
|
+
|
1022
|
+
if extra.length > 1
|
1023
|
+
extra.reverse.each_cons(2) do |src, dst|
|
1024
|
+
dst.concat src
|
1025
|
+
end
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
extra
|
1021
1029
|
end
|
1022
1030
|
|
1023
1031
|
##
|
1024
|
-
#
|
1032
|
+
# Executes the given block and restores
|
1033
|
+
# focus to the client that had focus
|
1034
|
+
# before the given block was executed.
|
1025
1035
|
#
|
1026
|
-
def
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1036
|
+
def maintain_focus
|
1037
|
+
c, v = Client.curr, View.curr
|
1038
|
+
yield
|
1039
|
+
c.focus v
|
1030
1040
|
end
|
1031
1041
|
|
1032
1042
|
##
|
1033
|
-
# Returns the
|
1043
|
+
# Returns the number of clients in the non-floating areas of this view.
|
1034
1044
|
#
|
1035
|
-
def
|
1036
|
-
|
1045
|
+
def num_managed_clients
|
1046
|
+
manifest.scan(/^\d+ 0x/).length
|
1037
1047
|
end
|
1048
|
+
end
|
1038
1049
|
|
1039
|
-
|
1050
|
+
##
|
1051
|
+
# Subdivision of the bar---the thing that spans the width of the
|
1052
|
+
# screen---useful for displaying information and system controls.
|
1053
|
+
#
|
1054
|
+
class Barlet < Node
|
1055
|
+
attr_reader :side
|
1040
1056
|
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1057
|
+
def initialize file_name, side
|
1058
|
+
prefix =
|
1059
|
+
case @side = side
|
1060
|
+
when :left then '/lbar'
|
1061
|
+
when :right then '/rbar'
|
1062
|
+
else raise ArgumentError, side
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
super "#{prefix}/#{file_name}"
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
COLORS_REGEXP = /^\S+ \S+ \S+/
|
1069
|
+
|
1070
|
+
def label
|
1071
|
+
case read
|
1072
|
+
when /^label (.*)$/ then $1
|
1073
|
+
when /#{COLORS_REGEXP} (.*)$/o then $1
|
1048
1074
|
end
|
1075
|
+
end
|
1049
1076
|
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1077
|
+
def colors
|
1078
|
+
case read
|
1079
|
+
when /^colors (.*)$/ then $1
|
1080
|
+
when COLORS_REGEXP then $&
|
1081
|
+
end
|
1082
|
+
end
|
1083
|
+
|
1084
|
+
# detect the new bar file format introduced in wmii-hg2743
|
1085
|
+
temp_barlet = IXP_FS_ROOT.rbar["temp_barlet_#{object_id}"]
|
1086
|
+
begin
|
1087
|
+
temp_barlet.create
|
1088
|
+
SPLIT_FILE_FORMAT = temp_barlet.read =~ /\Acolors/
|
1089
|
+
ensure
|
1090
|
+
temp_barlet.remove
|
1091
|
+
end
|
1092
|
+
|
1093
|
+
def label= label
|
1094
|
+
if SPLIT_FILE_FORMAT
|
1095
|
+
write "label #{label}"
|
1096
|
+
else
|
1097
|
+
write "#{colors} #{label}"
|
1098
|
+
end
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
def colors= colors
|
1102
|
+
if SPLIT_FILE_FORMAT
|
1103
|
+
write "colors #{colors}"
|
1104
|
+
else
|
1105
|
+
write "#{colors} #{label}"
|
1106
|
+
end
|
1060
1107
|
end
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
#---------------------------------------------------------------------------
|
1111
|
+
# access to global WM state
|
1112
|
+
#---------------------------------------------------------------------------
|
1113
|
+
|
1114
|
+
##
|
1115
|
+
# Returns the root of IXP file system hierarchy.
|
1116
|
+
#
|
1117
|
+
def fs
|
1118
|
+
IXP_FS_ROOT
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
##
|
1122
|
+
# Returns the current set of tags.
|
1123
|
+
#
|
1124
|
+
def tags
|
1125
|
+
ary = IXP_FS_ROOT.tag.entries.sort
|
1126
|
+
ary.delete FOCUSED_WIDGET_ID
|
1127
|
+
ary
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
##
|
1131
|
+
# Returns the current set of views.
|
1132
|
+
#
|
1133
|
+
def views
|
1134
|
+
tags.map! {|t| View.new t }
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
##
|
1138
|
+
# Returns a list of all grouped clients in
|
1139
|
+
# the currently focused view. If there are
|
1140
|
+
# no grouped clients, then the currently
|
1141
|
+
# focused client is returned in the list.
|
1142
|
+
#
|
1143
|
+
def grouping
|
1144
|
+
list = curr_view.clients.select {|c| c.group? }
|
1145
|
+
list << curr_client if list.empty? and curr_client.exist?
|
1146
|
+
list
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
#---------------------------------------------------------------------------
|
1150
|
+
include ClientContainer
|
1151
|
+
#---------------------------------------------------------------------------
|
1152
|
+
|
1153
|
+
##
|
1154
|
+
# Returns the IDs of the current set of clients.
|
1155
|
+
#
|
1156
|
+
def client_ids
|
1157
|
+
ary = IXP_FS_ROOT.client.entries
|
1158
|
+
ary.delete FOCUSED_WIDGET_ID
|
1159
|
+
ary
|
1160
|
+
end
|
1061
1161
|
|
1062
1162
|
#---------------------------------------------------------------------------
|
1063
1163
|
# shortcuts for interactive WM manipulation (via IRB)
|
1064
1164
|
#---------------------------------------------------------------------------
|
1065
1165
|
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1166
|
+
def curr_client ; Client.curr ; end
|
1167
|
+
def next_client ; curr_client.next ; end
|
1168
|
+
def prev_client ; curr_client.prev ; end
|
1069
1169
|
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1170
|
+
def curr_area ; Area.curr ; end
|
1171
|
+
def next_area ; curr_area.next ; end
|
1172
|
+
def prev_area ; curr_area.prev ; end
|
1073
1173
|
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1174
|
+
def curr_view ; View.curr ; end
|
1175
|
+
def next_view ; curr_view.next ; end
|
1176
|
+
def prev_view ; curr_view.prev ; end
|
1077
1177
|
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1178
|
+
def curr_tag ; curr_view.id ; end
|
1179
|
+
def next_tag ; next_view.id ; end
|
1180
|
+
def prev_tag ; prev_view.id ; end
|
1081
1181
|
|
1082
|
-
|
1083
|
-
|
1182
|
+
# provide easy access to container state information
|
1183
|
+
[Client, Area, View].each {|c| c.extend ExportInstanceMethods }
|
1084
1184
|
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1185
|
+
def focus_client id
|
1186
|
+
Client.focus id
|
1187
|
+
end
|
1088
1188
|
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1189
|
+
def focus_area id
|
1190
|
+
Area.focus id
|
1191
|
+
end
|
1092
1192
|
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1193
|
+
def focus_view id
|
1194
|
+
View.focus id
|
1195
|
+
end
|
1096
1196
|
|
1097
|
-
|
1098
|
-
|
1197
|
+
# provide easy access to this module's instance methods
|
1198
|
+
extend self
|
1099
1199
|
end
|