uh 1.2.3 → 2.0.0.pre
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.
- checksums.yaml +4 -4
- data/ext/uh/display.c +6 -2
- data/ext/uh/uh.c +1 -5
- data/ext/uh/uh.h +1 -5
- data/ext/uh/window.c +0 -39
- data/lib/uh.rb +0 -1
- data/lib/uh/display.rb +0 -4
- data/lib/uh/version.rb +1 -1
- data/lib/uh/window.rb +0 -4
- data/uh.gemspec +0 -1
- metadata +6 -19
- data/lib/uh/wm.rb +0 -213
- data/lib/uh/wm/action_handler.rb +0 -77
- data/lib/uh/wm/client.rb +0 -83
- data/lib/uh/wm/manager.rb +0 -84
- data/lib/uh/wm/workers/base_worker.rb +0 -20
- data/lib/uh/wm/workers/blocking_worker.rb +0 -11
- data/lib/uh/wm/workers/multiplexing_worker.rb +0 -33
- data/test/uh/test_wm.rb +0 -36
- data/test/uh/wm/test_client.rb +0 -182
- data/test/uh/wm/test_manager.rb +0 -164
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fac46367eac28fe3f697da45b08ed7250a5f8ac
|
4
|
+
data.tar.gz: 6d68b1ac9b0627154a98715662a3dd686b4d91b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1009fe21fd3c74988921ae694ea8aff50c953d6777a5ba629dc5a256789aa12b097ec8879099032c4879470bb248dd70dbe9950cf81c146bac9beae2bc951387
|
7
|
+
data.tar.gz: 0ff9b73c6acc2475c794f25e05c01626a20859f74da948af929865062b28512bdd975d6de9b0c41ac59653170c21ee5fd92565d5b96572d7abe8377b5f565bc1
|
data/ext/uh/display.c
CHANGED
@@ -13,8 +13,12 @@ VALUE rdisplay_error_handler = Qnil;
|
|
13
13
|
int display_x_error_handler(Display *dpy, XErrorEvent *e);
|
14
14
|
|
15
15
|
|
16
|
-
VALUE display_s_on_error(VALUE klass
|
17
|
-
|
16
|
+
VALUE display_s_on_error(VALUE klass) {
|
17
|
+
if (!rb_block_given_p()) {
|
18
|
+
rb_raise(rb_eArgError, "no block given");
|
19
|
+
}
|
20
|
+
|
21
|
+
rdisplay_error_handler = rb_block_proc();
|
18
22
|
rb_global_variable(&rdisplay_error_handler);
|
19
23
|
|
20
24
|
return Qnil;
|
data/ext/uh/uh.c
CHANGED
@@ -33,7 +33,7 @@ void uh_color() {
|
|
33
33
|
|
34
34
|
void uh_display() {
|
35
35
|
cDisplay = rb_define_class_under(mUh, "Display", rb_cObject);
|
36
|
-
rb_define_singleton_method(cDisplay, "on_error", display_s_on_error,
|
36
|
+
rb_define_singleton_method(cDisplay, "on_error", display_s_on_error, 0);
|
37
37
|
rb_define_alloc_func(cDisplay, display_alloc);
|
38
38
|
rb_define_attr(cDisplay, "name", 1, 0);
|
39
39
|
rb_define_method(cDisplay, "close", display_close, 0);
|
@@ -120,14 +120,11 @@ void uh_screen() {
|
|
120
120
|
void uh_window() {
|
121
121
|
cWindow = rb_define_class_under(mUh, "Window", rb_cObject);
|
122
122
|
rb_define_attr(cWindow, "id", 1, 0);
|
123
|
-
rb_define_method(cWindow, "destroy", window_destroy, 0);
|
124
123
|
rb_define_method(cWindow, "focus", window_focus, 0);
|
125
124
|
rb_define_method(cWindow, "kill", window_kill, 0);
|
126
125
|
rb_define_method(cWindow, "map", window_map, 0);
|
127
|
-
rb_define_method(cWindow, "mask", window_mask, 0);
|
128
126
|
rb_define_method(cWindow, "mask=", window_mask_set, 1);
|
129
127
|
rb_define_method(cWindow, "name", window_name, 0);
|
130
|
-
rb_define_method(cWindow, "name=", window_name_set, 1);
|
131
128
|
rb_define_method(cWindow, "override_redirect?", window_override_redirect, 0);
|
132
129
|
rb_define_method(cWindow, "raise", window_raise, 0);
|
133
130
|
rb_define_method(cWindow, "unmap", window_unmap, 0);
|
@@ -137,7 +134,6 @@ void uh_window() {
|
|
137
134
|
rb_define_private_method(cWindow, "_configure", window__configure, 4);
|
138
135
|
rb_define_private_method(cWindow, "_configure_event",
|
139
136
|
window__configure_event, 4);
|
140
|
-
rb_define_private_method(cWindow, "_create", window__create, 4);
|
141
137
|
rb_define_private_method(cWindow, "_create_sub", window__create_sub, 4);
|
142
138
|
rb_define_private_method(cWindow, "_moveresize", window__moveresize, 4);
|
143
139
|
}
|
data/ext/uh/uh.h
CHANGED
@@ -47,7 +47,7 @@ VALUE mUh, mEvents,
|
|
47
47
|
|
48
48
|
VALUE color_make(unsigned long pixel);
|
49
49
|
|
50
|
-
VALUE display_s_on_error(VALUE klass
|
50
|
+
VALUE display_s_on_error(VALUE klass);
|
51
51
|
VALUE display_alloc(VALUE klass);
|
52
52
|
VALUE display_close(VALUE self);
|
53
53
|
VALUE display_color_by_name(VALUE self, VALUE rcolor);
|
@@ -80,23 +80,19 @@ VALUE pixmap_make(Display *display, Pixmap xpixmap, VALUE width, VALUE height);
|
|
80
80
|
|
81
81
|
VALUE screen_init(VALUE self, VALUE id, VALUE x, VALUE y, VALUE w, VALUE h);
|
82
82
|
|
83
|
-
VALUE window_destroy(VALUE self);
|
84
83
|
VALUE window_focus(VALUE self);
|
85
84
|
VALUE window_icccm_wm_delete(VALUE self);
|
86
85
|
VALUE window_icccm_wm_protocols(VALUE self);
|
87
86
|
VALUE window_kill(VALUE self);
|
88
87
|
VALUE window_map(VALUE self);
|
89
|
-
VALUE window_mask(VALUE self);
|
90
88
|
VALUE window_mask_set(VALUE self, VALUE mask);
|
91
89
|
VALUE window_name(VALUE self);
|
92
|
-
VALUE window_name_set(VALUE self, VALUE name);
|
93
90
|
VALUE window_override_redirect(VALUE self);
|
94
91
|
VALUE window_raise(VALUE self);
|
95
92
|
VALUE window_unmap(VALUE self);
|
96
93
|
VALUE window_wclass(VALUE self);
|
97
94
|
VALUE window__configure(VALUE self, VALUE rx, VALUE ry, VALUE rw, VALUE rh);
|
98
95
|
VALUE window__configure_event(VALUE self, VALUE rx, VALUE ry, VALUE rw, VALUE rh);
|
99
|
-
VALUE window__create(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h);
|
100
96
|
VALUE window__create_sub(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h);
|
101
97
|
VALUE window__moveresize(VALUE self, VALUE x, VALUE y, VALUE width, VALUE height);
|
102
98
|
int window_id(VALUE window);
|
data/ext/uh/window.c
CHANGED
@@ -9,14 +9,6 @@
|
|
9
9
|
#define WINDOW window->id
|
10
10
|
|
11
11
|
|
12
|
-
VALUE window_destroy(VALUE self) {
|
13
|
-
SET_WINDOW(self);
|
14
|
-
|
15
|
-
XDestroyWindow(DPY, WINDOW);
|
16
|
-
|
17
|
-
return Qnil;
|
18
|
-
}
|
19
|
-
|
20
12
|
VALUE window_focus(VALUE self) {
|
21
13
|
SET_WINDOW(self);
|
22
14
|
|
@@ -76,17 +68,6 @@ VALUE window_map(VALUE self) {
|
|
76
68
|
return Qnil;
|
77
69
|
}
|
78
70
|
|
79
|
-
VALUE window_mask(VALUE self) {
|
80
|
-
XWindowAttributes wa;
|
81
|
-
SET_WINDOW(self);
|
82
|
-
|
83
|
-
if (!XGetWindowAttributes(DPY, WINDOW, &wa)) {
|
84
|
-
rb_raise(rb_eArgError, "cannot get window attributes for `0x%08lx'", WINDOW);
|
85
|
-
}
|
86
|
-
|
87
|
-
return LONG2FIX(wa.your_event_mask);
|
88
|
-
}
|
89
|
-
|
90
71
|
VALUE window_mask_set(VALUE self, VALUE mask) {
|
91
72
|
XSetWindowAttributes attrs;
|
92
73
|
SET_WINDOW(self);
|
@@ -111,14 +92,6 @@ VALUE window_name(VALUE self) {
|
|
111
92
|
return wname;
|
112
93
|
}
|
113
94
|
|
114
|
-
VALUE window_name_set(VALUE self, VALUE name) {
|
115
|
-
SET_WINDOW(self);
|
116
|
-
|
117
|
-
XStoreName(DPY, WINDOW, RSTRING_PTR(name));
|
118
|
-
|
119
|
-
return Qnil;
|
120
|
-
}
|
121
|
-
|
122
95
|
VALUE window_override_redirect(VALUE self) {
|
123
96
|
XWindowAttributes wa;
|
124
97
|
SET_WINDOW(self);
|
@@ -198,18 +171,6 @@ VALUE window__configure_event(VALUE self, VALUE rx, VALUE ry, VALUE rw, VALUE rh
|
|
198
171
|
return Qnil;
|
199
172
|
}
|
200
173
|
|
201
|
-
VALUE window__create(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h) {
|
202
|
-
Window win;
|
203
|
-
SET_WINDOW(self);
|
204
|
-
|
205
|
-
win = XCreateSimpleWindow(DPY, WINDOW,
|
206
|
-
FIX2INT(x), FIX2INT(y), FIX2INT(w), FIX2INT(h),
|
207
|
-
0, BlackPixel(DPY, SCREEN_DEFAULT), BlackPixel(DPY, SCREEN_DEFAULT)
|
208
|
-
);
|
209
|
-
|
210
|
-
return window_make(DPY, win);
|
211
|
-
}
|
212
|
-
|
213
174
|
VALUE window__create_sub(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h) {
|
214
175
|
XSetWindowAttributes wa;
|
215
176
|
Window sub_win;
|
data/lib/uh.rb
CHANGED
data/lib/uh/display.rb
CHANGED
data/lib/uh/version.rb
CHANGED
data/lib/uh/window.rb
CHANGED
data/uh.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thibault Jouan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -101,22 +101,11 @@ files:
|
|
101
101
|
- lib/uh/screen.rb
|
102
102
|
- lib/uh/version.rb
|
103
103
|
- lib/uh/window.rb
|
104
|
-
- lib/uh/wm.rb
|
105
|
-
- lib/uh/wm/action_handler.rb
|
106
|
-
- lib/uh/wm/client.rb
|
107
|
-
- lib/uh/wm/manager.rb
|
108
|
-
- lib/uh/wm/workers/base_worker.rb
|
109
|
-
- lib/uh/wm/workers/blocking_worker.rb
|
110
|
-
- lib/uh/wm/workers/multiplexing_worker.rb
|
111
104
|
- test/test_helper.rb
|
112
105
|
- test/uh/test_geo.rb
|
113
|
-
- test/uh/test_wm.rb
|
114
|
-
- test/uh/wm/test_client.rb
|
115
|
-
- test/uh/wm/test_manager.rb
|
116
106
|
- uh.gemspec
|
117
107
|
homepage: https://rubygems.org/gems/uh
|
118
|
-
licenses:
|
119
|
-
- BSD-3-Clause
|
108
|
+
licenses: []
|
120
109
|
metadata: {}
|
121
110
|
post_install_message:
|
122
111
|
rdoc_options: []
|
@@ -129,9 +118,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
129
118
|
version: '0'
|
130
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
120
|
requirements:
|
132
|
-
- - "
|
121
|
+
- - ">"
|
133
122
|
- !ruby/object:Gem::Version
|
134
|
-
version:
|
123
|
+
version: 1.3.1
|
135
124
|
requirements: []
|
136
125
|
rubyforge_project:
|
137
126
|
rubygems_version: 2.4.5
|
@@ -141,6 +130,4 @@ summary: Xlib simplified toolkit
|
|
141
130
|
test_files:
|
142
131
|
- test/test_helper.rb
|
143
132
|
- test/uh/test_geo.rb
|
144
|
-
|
145
|
-
- test/uh/wm/test_client.rb
|
146
|
-
- test/uh/wm/test_manager.rb
|
133
|
+
has_rdoc:
|
data/lib/uh/wm.rb
DELETED
@@ -1,213 +0,0 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
require 'logger'
|
3
|
-
|
4
|
-
require 'uh/wm/action_handler'
|
5
|
-
require 'uh/wm/client'
|
6
|
-
require 'uh/wm/manager'
|
7
|
-
require 'uh/wm/workers/base_worker'
|
8
|
-
require 'uh/wm/workers/blocking_worker'
|
9
|
-
require 'uh/wm/workers/multiplexing_worker'
|
10
|
-
|
11
|
-
module Uh
|
12
|
-
class WM
|
13
|
-
include Events
|
14
|
-
|
15
|
-
LOGGER_FORMAT_STR = "%s.%03i %s: %s\n".freeze
|
16
|
-
LOGGER_FORMATER = proc do |severity, datetime, progname, message|
|
17
|
-
LOGGER_FORMAT_STR % [
|
18
|
-
datetime.strftime('%FT%T'),
|
19
|
-
datetime.usec / 1000,
|
20
|
-
severity[0..0],
|
21
|
-
message
|
22
|
-
]
|
23
|
-
end
|
24
|
-
LOGGER_LEVEL = Logger::INFO
|
25
|
-
LOGGER_DEBUG_ENV = 'UH_DEBUG'.freeze
|
26
|
-
|
27
|
-
WORKERS = {
|
28
|
-
blocking: Workers::BlockingWorker,
|
29
|
-
multiplexing: Workers::MultiplexingWorker
|
30
|
-
}.freeze
|
31
|
-
|
32
|
-
DEFAULT_MODIFIER = :mod1
|
33
|
-
INPUT_MASK = SUBSTRUCTURE_REDIRECT_MASK
|
34
|
-
ROOT_MASK = PROPERTY_CHANGE_MASK |
|
35
|
-
SUBSTRUCTURE_REDIRECT_MASK |
|
36
|
-
SUBSTRUCTURE_NOTIFY_MASK |
|
37
|
-
STRUCTURE_NOTIFY_MASK
|
38
|
-
|
39
|
-
extend Forwardable
|
40
|
-
def_delegators :@manager, :on_configure, :on_manage, :on_unmanage,
|
41
|
-
:on_change
|
42
|
-
def_delegator :@logger, :info, :log
|
43
|
-
def_delegator :@logger, :error, :log_error
|
44
|
-
|
45
|
-
attr_reader :actions, :keys, :rules
|
46
|
-
|
47
|
-
def initialize(layout)
|
48
|
-
@layout = layout
|
49
|
-
@display = Display.new
|
50
|
-
@logger = Logger.new($stdout).tap do |o|
|
51
|
-
o.level = ENV.key?(LOGGER_DEBUG_ENV) ? Logger::DEBUG : LOGGER_LEVEL
|
52
|
-
o.formatter = LOGGER_FORMATER
|
53
|
-
end
|
54
|
-
@manager = Manager.new
|
55
|
-
@actions = ActionHandler.new(self, @manager, @layout)
|
56
|
-
@keys = {}
|
57
|
-
@rules = {}
|
58
|
-
end
|
59
|
-
|
60
|
-
def modifier(mod = nil)
|
61
|
-
return (@modifier or DEFAULT_MODIFIER) unless mod
|
62
|
-
@modifier = mod
|
63
|
-
end
|
64
|
-
|
65
|
-
def key(key, mod = nil, &block)
|
66
|
-
mod_mask = KEY_MODIFIERS[modifier]
|
67
|
-
mod_mask |= KEY_MODIFIERS[mod] if mod
|
68
|
-
@keys[[key, mod_mask]] = block
|
69
|
-
end
|
70
|
-
|
71
|
-
def rule(selectors = '', &block)
|
72
|
-
[*selectors].each do |selector|
|
73
|
-
@rules[/\A#{selector}/i] = block
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def on_init(&block)
|
78
|
-
@on_init = block
|
79
|
-
end
|
80
|
-
|
81
|
-
def on_expose(&block)
|
82
|
-
@on_expose = block
|
83
|
-
end
|
84
|
-
|
85
|
-
def worker(*args, **options)
|
86
|
-
@worker = WORKERS[args.first].new(@display, @logger, options)
|
87
|
-
end
|
88
|
-
|
89
|
-
def request_quit!
|
90
|
-
@quit_requested = true
|
91
|
-
end
|
92
|
-
|
93
|
-
def connect
|
94
|
-
@display.open
|
95
|
-
Display.on_error proc { fail OtherWMRunningError }
|
96
|
-
@display.listen_events INPUT_MASK
|
97
|
-
@display.sync false
|
98
|
-
Display.on_error proc { |*args| handle_error(*args) }
|
99
|
-
@display.sync false
|
100
|
-
@display.root.mask = ROOT_MASK
|
101
|
-
@worker.setup
|
102
|
-
@on_init.call @display if @on_init
|
103
|
-
end
|
104
|
-
|
105
|
-
def disconnect
|
106
|
-
@display.close
|
107
|
-
end
|
108
|
-
|
109
|
-
def grab_keys
|
110
|
-
@keys.each do |k, v|
|
111
|
-
key, mod = *k
|
112
|
-
key = key.to_s.gsub /\AXK_/, ''
|
113
|
-
@display.grab_key key, mod
|
114
|
-
end
|
115
|
-
@display.sync false
|
116
|
-
end
|
117
|
-
|
118
|
-
def run_until(&block)
|
119
|
-
@worker.each_event do |e|
|
120
|
-
process_event e
|
121
|
-
break if block.call
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def run
|
126
|
-
run_until { quit_requested? }
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
private
|
131
|
-
|
132
|
-
def modifier_mask(mod)
|
133
|
-
KEY_MODIFIERS[mod]
|
134
|
-
end
|
135
|
-
|
136
|
-
def quit_requested?
|
137
|
-
!!@quit_requested
|
138
|
-
end
|
139
|
-
|
140
|
-
def process_event(event)
|
141
|
-
return unless respond_to? handler = event_handler_method(event), true
|
142
|
-
log_event event
|
143
|
-
send handler, event
|
144
|
-
end
|
145
|
-
|
146
|
-
def event_handler_method(event)
|
147
|
-
('handle_%s' % event.type).to_sym
|
148
|
-
end
|
149
|
-
|
150
|
-
def log_event(event)
|
151
|
-
complement = case event.type
|
152
|
-
when :destroy_notify, :expose, :map_request, :property_notify
|
153
|
-
"window: #{event.window}"
|
154
|
-
when :configure_request
|
155
|
-
'%s, above: #%d, detail: #%d, value_mask: #%d' % [
|
156
|
-
Geo.format_xgeometry(event.x, event.y, event.width, event.height),
|
157
|
-
event.above_window_id,
|
158
|
-
event.detail,
|
159
|
-
event.value_mask
|
160
|
-
]
|
161
|
-
when :key_press
|
162
|
-
"window: #{event.window}, key: #{event.key}, mask: #{event.modifier_mask}"
|
163
|
-
when :unmap_notify
|
164
|
-
"window: #{event.window}, event_window: #{event.event_window}"
|
165
|
-
end
|
166
|
-
|
167
|
-
log [
|
168
|
-
'XEvent', event.type,
|
169
|
-
event.send_event ? 'SENT' : nil,
|
170
|
-
complement
|
171
|
-
].compact.join(' ')
|
172
|
-
end
|
173
|
-
|
174
|
-
def handle_configure_request(event)
|
175
|
-
@manager.configure event.window
|
176
|
-
end
|
177
|
-
|
178
|
-
def handle_destroy_notify(event)
|
179
|
-
@manager.destroy event.window
|
180
|
-
end
|
181
|
-
|
182
|
-
def handle_expose(event)
|
183
|
-
@on_expose.call event.window if @on_expose
|
184
|
-
end
|
185
|
-
|
186
|
-
def handle_key_press(event)
|
187
|
-
actions.call @keys[["XK_#{event.key}".to_sym, event.modifier_mask]]
|
188
|
-
end
|
189
|
-
|
190
|
-
def handle_map_request(event)
|
191
|
-
if client = @manager.map(event.window)
|
192
|
-
@display.listen_events event.window, PROPERTY_CHANGE_MASK
|
193
|
-
@rules.each do |selector, action|
|
194
|
-
if client.wclass =~ selector
|
195
|
-
actions.call action
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def handle_property_notify(event)
|
202
|
-
@manager.update_properties event.window
|
203
|
-
end
|
204
|
-
|
205
|
-
def handle_unmap_notify(event)
|
206
|
-
@manager.unmap event.window
|
207
|
-
end
|
208
|
-
|
209
|
-
def handle_error(req, resource_id, msg)
|
210
|
-
@logger.error "XERROR: #{resource_id} #{req} #{msg}"
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
data/lib/uh/wm/action_handler.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
module Uh
|
2
|
-
class WM
|
3
|
-
class ActionHandler
|
4
|
-
extend Forwardable
|
5
|
-
def_delegators :@wm, :log, :log_error
|
6
|
-
|
7
|
-
attr_reader :layout
|
8
|
-
|
9
|
-
def initialize(wm, manager, layout)
|
10
|
-
@wm, @manager, @layout = wm, manager, layout
|
11
|
-
end
|
12
|
-
|
13
|
-
def call(action)
|
14
|
-
instance_exec &action
|
15
|
-
rescue LocalJumpError => e
|
16
|
-
log_error "Action: #{e}"
|
17
|
-
end
|
18
|
-
|
19
|
-
def quit
|
20
|
-
log 'Exiting...'
|
21
|
-
@wm.request_quit!
|
22
|
-
end
|
23
|
-
|
24
|
-
def execute(command)
|
25
|
-
log "Spawn `#{command}`"
|
26
|
-
pid = fork do
|
27
|
-
fork do
|
28
|
-
Process.setsid
|
29
|
-
begin
|
30
|
-
exec command
|
31
|
-
rescue Errno::ENOENT => e
|
32
|
-
log_error "Spawn: #{e}"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
Process.waitpid pid
|
37
|
-
end
|
38
|
-
|
39
|
-
def log_layout
|
40
|
-
log "Layout:\n#{@layout.to_s.lines.map { |e| " #{e}" }.join.chomp}"
|
41
|
-
end
|
42
|
-
|
43
|
-
def log_clients
|
44
|
-
log "Clients:\n#{@manager.to_s.lines.map { |e| " #{e}" }.join.chomp}"
|
45
|
-
end
|
46
|
-
|
47
|
-
def log_separator
|
48
|
-
log '- ' * 24
|
49
|
-
end
|
50
|
-
|
51
|
-
def method_missing(m, *args, &block)
|
52
|
-
if respond_to? m
|
53
|
-
meth = layout_method m
|
54
|
-
log "#{@layout.class.name}##{meth} #{args.inspect}"
|
55
|
-
begin
|
56
|
-
@layout.send(meth, *args)
|
57
|
-
rescue NoMethodError
|
58
|
-
log_error "Layout does not implement `#{meth}'"
|
59
|
-
end
|
60
|
-
else
|
61
|
-
super
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def respond_to_missing?(m, *)
|
66
|
-
m.to_s =~ /\Alayout_/ || super
|
67
|
-
end
|
68
|
-
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def layout_method(m)
|
73
|
-
m.to_s.gsub(/\Alayout_/, 'handle_').to_sym
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
data/lib/uh/wm/client.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'uh/geo_accessors'
|
2
|
-
|
3
|
-
module Uh
|
4
|
-
class WM
|
5
|
-
class Client
|
6
|
-
include GeoAccessors
|
7
|
-
|
8
|
-
attr_reader :window
|
9
|
-
attr_accessor :geo, :unmap_count
|
10
|
-
|
11
|
-
def initialize(window)
|
12
|
-
@window = window
|
13
|
-
@hide = true
|
14
|
-
@unmap_count = 0
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_s
|
18
|
-
'<%s> (%s) %s win: %s unmaps: %d' %
|
19
|
-
[name, wclass, @geo, @window, @unmap_count]
|
20
|
-
end
|
21
|
-
|
22
|
-
def name
|
23
|
-
@name ||= @window.name
|
24
|
-
end
|
25
|
-
|
26
|
-
def wclass
|
27
|
-
@wclass ||= @window.wclass
|
28
|
-
end
|
29
|
-
|
30
|
-
def hidden?
|
31
|
-
@hide
|
32
|
-
end
|
33
|
-
|
34
|
-
def update_window_properties
|
35
|
-
@name = @window.name
|
36
|
-
@wclass = @window.wclass
|
37
|
-
end
|
38
|
-
|
39
|
-
def configure
|
40
|
-
@window.configure @geo
|
41
|
-
self
|
42
|
-
end
|
43
|
-
|
44
|
-
def moveresize
|
45
|
-
@window.moveresize @geo
|
46
|
-
self
|
47
|
-
end
|
48
|
-
|
49
|
-
def show
|
50
|
-
@window.map
|
51
|
-
@hide = false
|
52
|
-
self
|
53
|
-
end
|
54
|
-
|
55
|
-
def hide
|
56
|
-
@window.unmap
|
57
|
-
@hide = true
|
58
|
-
@unmap_count += 1
|
59
|
-
self
|
60
|
-
end
|
61
|
-
|
62
|
-
def focus
|
63
|
-
@window.raise
|
64
|
-
@window.focus
|
65
|
-
self
|
66
|
-
end
|
67
|
-
|
68
|
-
def kill
|
69
|
-
if @window.icccm_wm_protocols.include? :WM_DELETE_WINDOW
|
70
|
-
@window.icccm_wm_delete
|
71
|
-
else
|
72
|
-
@window.kill
|
73
|
-
end
|
74
|
-
self
|
75
|
-
end
|
76
|
-
|
77
|
-
def kill!
|
78
|
-
@window.kill
|
79
|
-
self
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
data/lib/uh/wm/manager.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
module Uh
|
2
|
-
class WM
|
3
|
-
class Manager
|
4
|
-
DEFAULT_GEO = Geo.new(0, 0, 320, 240).freeze
|
5
|
-
|
6
|
-
attr_reader :clients
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
@clients = []
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_s
|
13
|
-
@clients.join $/
|
14
|
-
end
|
15
|
-
|
16
|
-
def on_configure(&block)
|
17
|
-
@on_configure = block
|
18
|
-
end
|
19
|
-
|
20
|
-
def on_manage(&block)
|
21
|
-
@on_manage = block
|
22
|
-
end
|
23
|
-
|
24
|
-
def on_unmanage(&block)
|
25
|
-
@on_unmanage = block
|
26
|
-
end
|
27
|
-
|
28
|
-
def on_change(&block)
|
29
|
-
@on_change = block
|
30
|
-
end
|
31
|
-
|
32
|
-
def configure(window)
|
33
|
-
if client = client_for(window)
|
34
|
-
client.configure
|
35
|
-
else
|
36
|
-
geo = @on_configure ? @on_configure.call(window) : DEFAULT_GEO
|
37
|
-
window.configure_event geo
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def map(window)
|
42
|
-
return if window.override_redirect? || client_for(window)
|
43
|
-
Client.new(window).tap { |o| manage o }
|
44
|
-
end
|
45
|
-
|
46
|
-
def unmap(window)
|
47
|
-
return unless client = client_for(window)
|
48
|
-
if client.unmap_count > 0
|
49
|
-
client.unmap_count -= 1
|
50
|
-
else
|
51
|
-
unmanage client
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def destroy(window)
|
56
|
-
return unless client = client_for(window)
|
57
|
-
unmanage client
|
58
|
-
end
|
59
|
-
|
60
|
-
def update_properties(window)
|
61
|
-
return unless client = client_for(window)
|
62
|
-
client.update_window_properties
|
63
|
-
@on_change.call client if @on_change
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def client_for(window)
|
70
|
-
@clients.find { |e| e.window == window }
|
71
|
-
end
|
72
|
-
|
73
|
-
def manage(client)
|
74
|
-
@clients << client
|
75
|
-
@on_manage.call client if @on_manage
|
76
|
-
end
|
77
|
-
|
78
|
-
def unmanage(client)
|
79
|
-
@clients.reject! { |e| e == client }
|
80
|
-
@on_unmanage.call client if @on_unmanage
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Uh
|
2
|
-
class WM
|
3
|
-
module Workers
|
4
|
-
class BaseWorker
|
5
|
-
def initialize(display, logger, **options)
|
6
|
-
@display = display
|
7
|
-
@logger = logger
|
8
|
-
configure **options
|
9
|
-
end
|
10
|
-
|
11
|
-
def configure(**options)
|
12
|
-
end
|
13
|
-
|
14
|
-
def setup
|
15
|
-
self
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module Uh
|
2
|
-
class WM
|
3
|
-
module Workers
|
4
|
-
class MultiplexingWorker < BaseWorker
|
5
|
-
DEFAULT_TIMEOUT = 4
|
6
|
-
|
7
|
-
def configure(timeout: DEFAULT_TIMEOUT, on_timeout: nil)
|
8
|
-
@timeout = timeout
|
9
|
-
@on_timeout = on_timeout
|
10
|
-
end
|
11
|
-
|
12
|
-
def setup
|
13
|
-
@display_io = IO.new(@display.fileno)
|
14
|
-
self
|
15
|
-
end
|
16
|
-
|
17
|
-
def each_event
|
18
|
-
loop do
|
19
|
-
@display.flush
|
20
|
-
@logger.debug "select [#{@display_io.fileno}], _, _, #{@timeout}"
|
21
|
-
rs, _ = IO.select [@display_io], [], [], @timeout
|
22
|
-
@logger.debug " => #{rs.inspect}"
|
23
|
-
if rs.nil? || rs.empty?
|
24
|
-
@on_timeout.call if @on_timeout
|
25
|
-
else
|
26
|
-
yield @display.next_event while @display.pending?
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/test/uh/test_wm.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'uh/wm'
|
3
|
-
|
4
|
-
module Uh
|
5
|
-
describe WM do
|
6
|
-
subject { WM.new(Object.new) }
|
7
|
-
|
8
|
-
it 'has no rules' do
|
9
|
-
assert_empty subject.rules
|
10
|
-
end
|
11
|
-
|
12
|
-
describe '#rule' do
|
13
|
-
let(:block) { proc { } }
|
14
|
-
|
15
|
-
it 'registers a new rule' do
|
16
|
-
subject.rule 'client', &block
|
17
|
-
assert_equal 1, subject.rules.size
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'transforms the given selector as a regexp' do
|
21
|
-
subject.rule 'client', &block
|
22
|
-
assert_equal /\Aclient/i, subject.rules.keys[0]
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'assigns the given block' do
|
26
|
-
subject.rule 'client', &block
|
27
|
-
assert_includes subject.rules.values, block
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'accepts an array of selectors' do
|
31
|
-
subject.rule %w[foo bar], &block
|
32
|
-
assert_equal [/\Afoo/i, /\Abar/i], subject.rules.keys
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/test/uh/wm/test_client.rb
DELETED
@@ -1,182 +0,0 @@
|
|
1
|
-
require 'ostruct'
|
2
|
-
require 'test_helper'
|
3
|
-
require 'uh/wm'
|
4
|
-
|
5
|
-
module Uh
|
6
|
-
class WM
|
7
|
-
describe Client do
|
8
|
-
let(:geo) { Geo.new(0, 0, 1024, 768) }
|
9
|
-
let(:window) { OpenStruct.new(name: 'win name', wclass: 'win class') }
|
10
|
-
subject { Client.new(window) }
|
11
|
-
|
12
|
-
before { subject.geo = geo }
|
13
|
-
|
14
|
-
it 'is hidden' do
|
15
|
-
assert subject.hidden?
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'has an unmap count of 0' do
|
19
|
-
assert_equal 0, subject.unmap_count
|
20
|
-
end
|
21
|
-
|
22
|
-
describe '#name' do
|
23
|
-
it 'returns the window name' do
|
24
|
-
assert_equal 'win name', subject.name
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe '#wclass' do
|
29
|
-
it 'returns the window class' do
|
30
|
-
assert_equal 'win class', subject.wclass
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
describe '#update_window_properties' do
|
35
|
-
it 'updates the window name' do
|
36
|
-
window.name = 'new name'
|
37
|
-
assert_equal 'new name', subject.name
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'updates the window class' do
|
41
|
-
window.wclass = 'new class'
|
42
|
-
assert_equal 'new class', subject.wclass
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
describe '#configure' do
|
47
|
-
let(:window) { Minitest::Mock.new }
|
48
|
-
|
49
|
-
before { window.expect :configure, window, [geo] }
|
50
|
-
|
51
|
-
it 'configures the window with client geo' do
|
52
|
-
subject.configure
|
53
|
-
window.verify
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'returns self' do
|
57
|
-
assert_same subject, subject.configure
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
describe '#moveresize' do
|
62
|
-
let(:window) { Minitest::Mock.new }
|
63
|
-
|
64
|
-
before { window.expect :moveresize, window, [geo] }
|
65
|
-
it 'moveresizes the window with client geo' do
|
66
|
-
subject.moveresize
|
67
|
-
window.verify
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'returns self' do
|
71
|
-
assert_same subject, subject.moveresize
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
describe '#show' do
|
76
|
-
let(:window) { Minitest::Mock.new }
|
77
|
-
|
78
|
-
before { window.expect :map, window }
|
79
|
-
|
80
|
-
it 'maps the window' do
|
81
|
-
subject.show
|
82
|
-
window.verify
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'is not hidden anymore' do
|
86
|
-
subject.show
|
87
|
-
refute subject.hidden?
|
88
|
-
end
|
89
|
-
|
90
|
-
it 'returns self' do
|
91
|
-
assert_same subject, subject.show
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
describe '#hide' do
|
96
|
-
let(:window) { Minitest::Mock.new }
|
97
|
-
|
98
|
-
before { window.expect :unmap, window }
|
99
|
-
|
100
|
-
it 'unmaps the window' do
|
101
|
-
subject.hide
|
102
|
-
window.verify
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'stays hidden' do
|
106
|
-
subject.hide
|
107
|
-
assert subject.hidden?
|
108
|
-
end
|
109
|
-
|
110
|
-
it 'increments the unmap count' do
|
111
|
-
subject.hide
|
112
|
-
assert_equal 1, subject.unmap_count
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'returns self' do
|
116
|
-
assert_same subject, subject.hide
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
describe '#focus' do
|
121
|
-
let(:window) { Minitest::Mock.new }
|
122
|
-
|
123
|
-
before do
|
124
|
-
window.expect :raise, window
|
125
|
-
window.expect :focus, window
|
126
|
-
end
|
127
|
-
|
128
|
-
it 'raises and focuses the window' do
|
129
|
-
subject.focus
|
130
|
-
window.verify
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'returns self' do
|
134
|
-
assert_same subject, subject.focus
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
describe '#kill' do
|
139
|
-
let(:window) { Minitest::Mock.new }
|
140
|
-
let(:protocols) { [] }
|
141
|
-
|
142
|
-
before { window.expect :icccm_wm_protocols, protocols }
|
143
|
-
|
144
|
-
it 'kills the window' do
|
145
|
-
window.expect :kill, window
|
146
|
-
subject.kill
|
147
|
-
window.verify
|
148
|
-
end
|
149
|
-
|
150
|
-
it 'returns self' do
|
151
|
-
window.expect :kill, window
|
152
|
-
assert_same subject, subject.kill
|
153
|
-
end
|
154
|
-
|
155
|
-
context 'when window supports icccm wm delete' do
|
156
|
-
let(:protocols) { [:WM_DELETE_WINDOW] }
|
157
|
-
|
158
|
-
it 'icccm deletes the window' do
|
159
|
-
window.expect :icccm_wm_delete, window
|
160
|
-
subject.kill
|
161
|
-
window.verify
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
describe '#kill!' do
|
167
|
-
let(:window) { Minitest::Mock.new }
|
168
|
-
|
169
|
-
before { window.expect :kill, window }
|
170
|
-
|
171
|
-
it 'kills the window' do
|
172
|
-
subject.kill!
|
173
|
-
window.verify
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'returns self' do
|
177
|
-
assert_same subject, subject.kill!
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
data/test/uh/wm/test_manager.rb
DELETED
@@ -1,164 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'uh/wm'
|
3
|
-
|
4
|
-
module Uh
|
5
|
-
class WM
|
6
|
-
describe Manager do
|
7
|
-
let(:output) { StringIO.new }
|
8
|
-
let(:window) { Minitest::Mock.new }
|
9
|
-
subject { Manager.new }
|
10
|
-
|
11
|
-
it 'has no clients' do
|
12
|
-
assert subject.clients.empty?
|
13
|
-
end
|
14
|
-
|
15
|
-
describe '#configure' do
|
16
|
-
context 'with new window' do
|
17
|
-
it 'sends a default configure event to the window' do
|
18
|
-
window.expect :configure_event, window, [Geo.new(0, 0, 320, 240)]
|
19
|
-
subject.configure window
|
20
|
-
window.verify
|
21
|
-
end
|
22
|
-
|
23
|
-
context 'with a registered callback' do
|
24
|
-
it 'sends configure event with geo returned by callback' do
|
25
|
-
subject.on_configure { Geo.new(0, 0, 42, 42) }
|
26
|
-
window.expect :configure_event, window, [Geo.new(0, 0, 42, 42)]
|
27
|
-
subject.configure window
|
28
|
-
window.verify
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context 'with known window' do
|
34
|
-
let(:client) { Minitest::Mock.new }
|
35
|
-
|
36
|
-
before do
|
37
|
-
subject.clients << client
|
38
|
-
client.expect :window, window
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'sends a configure message to the client for given window' do
|
42
|
-
window.expect :==, true, [Object]
|
43
|
-
client.expect :configure, client
|
44
|
-
subject.configure window
|
45
|
-
client.verify
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
describe '#map' do
|
51
|
-
before do
|
52
|
-
window.expect :override_redirect?, false
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'registers a new client' do
|
56
|
-
subject.map window
|
57
|
-
assert_equal 1, subject.clients.size
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'calls the manage callback' do
|
61
|
-
subject.on_manage do |client|
|
62
|
-
assert_equal subject.clients[0], client
|
63
|
-
throw :manage
|
64
|
-
end
|
65
|
-
assert_throws(:manage) { subject.map window }
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
describe '#unmap' do
|
70
|
-
let(:client) { Client.new(window) }
|
71
|
-
|
72
|
-
before do
|
73
|
-
subject.clients << client
|
74
|
-
window.expect :==, true, [Object]
|
75
|
-
end
|
76
|
-
|
77
|
-
context 'when client unmap count is 0 or less' do
|
78
|
-
it 'preserves the unmap count' do
|
79
|
-
subject.unmap window
|
80
|
-
assert_equal 0, client.unmap_count
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'unmanages the client' do
|
84
|
-
subject.unmap window
|
85
|
-
refute_includes subject.clients, client
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'calls the unmanage callback' do
|
89
|
-
subject.on_unmanage do |c|
|
90
|
-
assert_equal client, c
|
91
|
-
throw :unmanage
|
92
|
-
end
|
93
|
-
assert_throws(:unmanage) { subject.unmap window }
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
context 'when client unmap count is strictly positive' do
|
98
|
-
before { client.unmap_count += 1 }
|
99
|
-
|
100
|
-
it 'decrements the unmap count' do
|
101
|
-
subject.unmap window
|
102
|
-
assert_equal 0, client.unmap_count
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'does not unmanage the client' do
|
106
|
-
subject.unmap window
|
107
|
-
assert_includes subject.clients, client
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
describe '#destroy' do
|
113
|
-
let(:client) { Client.new(window) }
|
114
|
-
|
115
|
-
before do
|
116
|
-
subject.clients << client
|
117
|
-
window.expect :==, true, [Object]
|
118
|
-
end
|
119
|
-
|
120
|
-
it 'unmanages the client' do
|
121
|
-
subject.destroy window
|
122
|
-
refute_includes subject.clients, client
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'calls the unmanage callback' do
|
126
|
-
subject.on_unmanage do |c|
|
127
|
-
assert_equal client, c
|
128
|
-
throw :unmanage
|
129
|
-
end
|
130
|
-
assert_throws(:unmanage) { subject.destroy window }
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
describe '#update_properties' do
|
135
|
-
context 'with known window' do
|
136
|
-
before do
|
137
|
-
window.expect :==, true, [Object]
|
138
|
-
window.expect :name, 'window'
|
139
|
-
window.expect :wclass, 'window class'
|
140
|
-
end
|
141
|
-
|
142
|
-
it 'updates client window properties' do
|
143
|
-
client = Minitest::Mock.new
|
144
|
-
client.expect :window, window
|
145
|
-
subject.clients << client
|
146
|
-
client.expect :update_window_properties, client
|
147
|
-
subject.update_properties window
|
148
|
-
client.verify
|
149
|
-
end
|
150
|
-
|
151
|
-
it 'calls the change callback' do
|
152
|
-
client = Client.new(window)
|
153
|
-
subject.clients << client
|
154
|
-
subject.on_change do |c|
|
155
|
-
assert_same client, c
|
156
|
-
throw :change
|
157
|
-
end
|
158
|
-
assert_throws(:change) { subject.update_properties window }
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|