uh 1.2.3 → 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d15f9c10043e73d9891e0e63ee0242b979ce6aac
4
- data.tar.gz: bf8dd289b1c4b88f6ea8f9749c14e0b5d6ff7ae2
3
+ metadata.gz: 1fac46367eac28fe3f697da45b08ed7250a5f8ac
4
+ data.tar.gz: 6d68b1ac9b0627154a98715662a3dd686b4d91b7
5
5
  SHA512:
6
- metadata.gz: 3f2d7a2e3f5c157d33d40c69cd8bdec77ab1052241676479606014391925cbcc72c29c5510af874f936bf5769f15b215ca597170761cec2d4b2a59a764fdedb0
7
- data.tar.gz: f13f6fd116766445cb26531b5b5523c0a76f10f122af011a11163d7a83559b21151cfafd90fca81f30aa1aed086241174d7256e1d8c9107ce183dd0a8cda8005
6
+ metadata.gz: 1009fe21fd3c74988921ae694ea8aff50c953d6777a5ba629dc5a256789aa12b097ec8879099032c4879470bb248dd70dbe9950cf81c146bac9beae2bc951387
7
+ data.tar.gz: 0ff9b73c6acc2475c794f25e05c01626a20859f74da948af929865062b28512bdd975d6de9b0c41ac59653170c21ee5fd92565d5b96572d7abe8377b5f565bc1
@@ -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, VALUE handler) {
17
- rdisplay_error_handler = handler;
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;
@@ -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, 1);
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
  }
@@ -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, VALUE handler);
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);
@@ -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
@@ -15,7 +15,6 @@ module Uh
15
15
  Error = Class.new(StandardError)
16
16
  RuntimeError = Class.new(RuntimeError)
17
17
  ArgumentError = Class.new(Error)
18
- OtherWMRunningError = Class.new(RuntimeError)
19
18
 
20
19
  KEY_MODIFIERS = {
21
20
  shift: 1 << 0,
@@ -4,10 +4,6 @@ module Uh
4
4
  ENV['DISPLAY']
5
5
  end
6
6
 
7
- def create_window(geo)
8
- root.create geo
9
- end
10
-
11
7
  def create_subwindow(geo)
12
8
  root.create_sub geo
13
9
  end
@@ -1,3 +1,3 @@
1
1
  module Uh
2
- VERSION = '1.2.3'.freeze
2
+ VERSION = '2.0.0.pre'.freeze
3
3
  end
@@ -18,10 +18,6 @@ module Uh
18
18
  self
19
19
  end
20
20
 
21
- def create(geo)
22
- _create geo.x, geo.y, geo.width, geo.height
23
- end
24
-
25
21
  def create_sub(geo)
26
22
  _create_sub geo.x, geo.y, geo.width, geo.height
27
23
  end
data/uh.gemspec CHANGED
@@ -5,7 +5,6 @@ Gem::Specification.new do |s|
5
5
  s.version = Uh::VERSION.dup
6
6
  s.summary = 'Xlib simplified toolkit'
7
7
  s.description = s.name
8
- s.license = 'BSD-3-Clause'
9
8
  s.homepage = 'https://rubygems.org/gems/uh'
10
9
 
11
10
  s.authors = 'Thibault Jouan'
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: 1.2.3
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-24 00:00:00.000000000 Z
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: '0'
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
- - test/uh/test_wm.rb
145
- - test/uh/wm/test_client.rb
146
- - test/uh/wm/test_manager.rb
133
+ has_rdoc:
@@ -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
@@ -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
@@ -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
@@ -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,11 +0,0 @@
1
- module Uh
2
- class WM
3
- module Workers
4
- class BlockingWorker < BaseWorker
5
- def each_event
6
- @display.each_event { |e| yield e }
7
- end
8
- end
9
- end
10
- end
11
- 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
@@ -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
@@ -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
@@ -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