uh-wm 0.0.2 → 0.0.3
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/README.md +14 -15
- data/features/layout/manage.feature +1 -1
- data/features/layout/protocol.feature +34 -2
- data/features/layout/unmanage.feature +1 -1
- data/features/manager/change.feature +7 -0
- data/features/manager/expose.feature +5 -0
- data/features/manager/unmanage.feature +2 -2
- data/features/run_control/layout.feature +39 -0
- data/features/session/termination.feature +1 -2
- data/features/steps/output_steps.rb +11 -0
- data/features/steps/run_steps.rb +2 -2
- data/features/steps/x_steps.rb +29 -24
- data/features/workers/block.feature +15 -0
- data/features/workers/mux.feature +15 -0
- data/lib/uh/wm/actions_handler.rb +6 -2
- data/lib/uh/wm/client.rb +5 -0
- data/lib/uh/wm/env.rb +2 -2
- data/lib/uh/wm/manager.rb +22 -4
- data/lib/uh/wm/run_control.rb +12 -0
- data/lib/uh/wm/runner.rb +12 -9
- data/lib/uh/wm/testing/acceptance_helpers.rb +47 -56
- data/lib/uh/wm/version.rb +1 -1
- data/lib/uh/wm/workers/base.rb +1 -1
- data/lib/uh/wm/workers/mux.rb +1 -1
- data/spec/spec_helper.rb +4 -0
- data/spec/support/factories.rb +27 -0
- data/spec/uh/wm/actions_handler_spec.rb +6 -1
- data/spec/uh/wm/client_spec.rb +21 -6
- data/spec/uh/wm/dispatcher_spec.rb +1 -1
- data/spec/uh/wm/env_spec.rb +18 -9
- data/spec/uh/wm/manager_spec.rb +70 -39
- data/spec/uh/wm/run_control_spec.rb +25 -1
- data/spec/uh/wm/runner_spec.rb +23 -13
- data/uh-wm.gemspec +2 -1
- metadata +20 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40e271eacf6628e4196a0a442cda080fad7e920d
|
4
|
+
data.tar.gz: c75d3a2df941bc52cef89ffbcc6c9268637e871a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07f4ee1ff8da6285d2e8d63b357feb0916c3dd3964b8552b11912b2fa6d54e383c900e1b094a39da17461bc2c2bf65b44dc5d0331021a0aac51dcb531e0ecd83
|
7
|
+
data.tar.gz: 38a41438342a2660ce49536008c7789402596bbd9dcbeb24335d6337f3dd7c9fe6aa3a9d2269be7bdb4714c88e9b252260489474160a485d0dd22ed69a80a963
|
data/README.md
CHANGED
@@ -1,36 +1,35 @@
|
|
1
1
|
uh-wm
|
2
2
|
=====
|
3
3
|
|
4
|
+
[![Version ][badge-version-img]][badge-version-uri]
|
5
|
+
[![Build status ][badge-build-img]][badge-build-uri]
|
6
|
+
[![Code Climate ][badge-cclimate-img]][badge-cclimate-uri]
|
7
|
+
|
8
|
+
|
4
9
|
uh-wm is a minimalistic tiling and stacking window manager for X. It
|
5
10
|
shares some similarities with dwm and wmii, but is written in ruby so
|
6
11
|
you can configure and extend features with ruby code.
|
7
12
|
|
8
13
|
The layout strategy is interchangeable, the default one being the
|
9
|
-
`uh-layout` ruby gem. A layout is a simple object
|
10
|
-
|
14
|
+
`uh-layout` ruby gem. A layout is a simple ruby object responding to
|
15
|
+
specific methods.
|
11
16
|
|
12
|
-
|
17
|
+
Main features:
|
13
18
|
|
14
19
|
* Xinerama support;
|
15
20
|
* Multiple event handling strategy: blocking or multiplexing
|
16
|
-
|
17
|
-
* Configuration with a run control file;
|
21
|
+
with `select()`;
|
22
|
+
* Configuration with a run control file (ruby DSL);
|
18
23
|
* Key bindings with user defined code as callback;
|
19
24
|
* Configurable modifier key;
|
20
|
-
* Support user-defined layout
|
21
|
-
* Program execution
|
22
|
-
|
23
|
-
* No
|
24
|
-
* No grabbing of the modifier key;
|
25
|
+
* Support user-defined layout strategies;
|
26
|
+
* Program execution;
|
27
|
+
* No re-parenting (therefore, no window decoration either);
|
28
|
+
* No grabbing of the modifier key alone;
|
25
29
|
* No mouse handling;
|
26
30
|
* Very limited ICCCM support.
|
27
31
|
|
28
32
|
|
29
|
-
[![Version ][badge-version-img]][badge-version-uri]
|
30
|
-
[![Build status ][badge-build-img]][badge-build-uri]
|
31
|
-
[![Code Climate ][badge-cclimate-img]][badge-cclimate-uri]
|
32
|
-
|
33
|
-
|
34
33
|
Getting started
|
35
34
|
---------------
|
36
35
|
|
@@ -6,10 +6,26 @@ Feature: layout protocol
|
|
6
6
|
class Layout
|
7
7
|
def register display
|
8
8
|
puts display
|
9
|
+
display.create_subwindow(Uh::Geo.new(0, 0, 640, 16)).tap do |o|
|
10
|
+
o.show
|
11
|
+
end
|
9
12
|
end
|
10
13
|
|
11
14
|
def << client
|
12
|
-
puts client
|
15
|
+
puts "testing_#<<_#{client.name}"
|
16
|
+
client.show
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove client
|
20
|
+
puts "testing_#remove_#{client.name}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def update client
|
24
|
+
puts "testing_#update_#{client.name}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def expose window
|
28
|
+
puts "testing_#expose_#{window.id}"
|
13
29
|
end
|
14
30
|
end
|
15
31
|
"""
|
@@ -21,4 +37,20 @@ Feature: layout protocol
|
|
21
37
|
Scenario: tells the layout to manage a client with #<< message
|
22
38
|
Given uhwm is running with options -v -r./layout -l Layout
|
23
39
|
When a window requests to be mapped
|
24
|
-
Then the output must contain
|
40
|
+
Then the output must contain "testing_#<<_XClient/default"
|
41
|
+
|
42
|
+
Scenario: tells the layout to unmanage a client with #remove message
|
43
|
+
Given uhwm is running with options -v -r./layout -l Layout
|
44
|
+
And a window is mapped
|
45
|
+
When the window is unmapped
|
46
|
+
Then the output must contain "testing_#remove_XClient/default"
|
47
|
+
|
48
|
+
Scenario: tells the layout to update a changed client with #update message
|
49
|
+
Given uhwm is running with options -v -r./layout -l Layout
|
50
|
+
And a window is mapped
|
51
|
+
When the window name changes to "testing_new_name"
|
52
|
+
Then the output must contain "testing_#update_testing_new_name"
|
53
|
+
|
54
|
+
Scenario: tells the layout about an exposed window with #expose message
|
55
|
+
Given I run uhwm with options -r./layout -l Layout
|
56
|
+
Then the output must match /testing_#expose_\d+/
|
@@ -2,10 +2,10 @@ Feature: manager client unmanagement
|
|
2
2
|
|
3
3
|
Background:
|
4
4
|
Given uhwm is running
|
5
|
-
And a window is
|
5
|
+
And a window is mapped
|
6
6
|
|
7
7
|
Scenario: logs when a new client is unmanaged
|
8
|
-
When the window
|
8
|
+
When the window is unmapped
|
9
9
|
Then the output must match /unmanag.+xclient/i
|
10
10
|
|
11
11
|
Scenario: unmanages client on destroy notify X events
|
@@ -0,0 +1,39 @@
|
|
1
|
+
Feature: `layout' run control keyword
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given a file named my_layout.rb with:
|
5
|
+
"""
|
6
|
+
class MyLayout
|
7
|
+
def initialize **options
|
8
|
+
puts "testing_rc_layout_#{options.inspect}" if options.any?
|
9
|
+
end
|
10
|
+
|
11
|
+
def register *_, **options
|
12
|
+
puts "testing_rc_layout_register"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
"""
|
16
|
+
|
17
|
+
Scenario: configures a layout class
|
18
|
+
Given a run control file with:
|
19
|
+
"""
|
20
|
+
layout MyLayout
|
21
|
+
"""
|
22
|
+
When I run uhwm with options -r./my_layout
|
23
|
+
Then the output must contain "testing_rc_layout_register"
|
24
|
+
|
25
|
+
Scenario: configures a layout class with options
|
26
|
+
Given a run control file with:
|
27
|
+
"""
|
28
|
+
layout MyLayout, foo: :bar
|
29
|
+
"""
|
30
|
+
When I run uhwm with options -r./my_layout
|
31
|
+
Then the output must contain "testing_rc_layout_{:foo=>:bar}"
|
32
|
+
|
33
|
+
Scenario: configures a layout instance
|
34
|
+
Given a run control file with:
|
35
|
+
"""
|
36
|
+
layout MyLayout.new
|
37
|
+
"""
|
38
|
+
When I run uhwm with options -r./my_layout
|
39
|
+
Then the output must contain "testing_rc_layout_register"
|
@@ -27,6 +27,17 @@ Then /^the output must not match \/([^\/]+)\/([a-z]*)$/ do |pattern, options|
|
|
27
27
|
expect(all_output).not_to match Regexp.new(pattern, options)
|
28
28
|
end
|
29
29
|
|
30
|
+
Then /^the output must match \/([^\/]+)\/([a-z]*) at least (\d+) times$/ do
|
31
|
+
|pattern, options, times|
|
32
|
+
uhwm_wait_output Regexp.new(pattern, options), times.to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
Then /^the output must match \/([^\/]+)\/([a-z]*) exactly (\d+) times$/ do
|
36
|
+
|pattern, options, times|
|
37
|
+
scans = uhwm_wait_output Regexp.new(pattern, options)
|
38
|
+
expect(scans.size).to eq times.to_i
|
39
|
+
end
|
40
|
+
|
30
41
|
Then /^the output must contain:$/ do |content|
|
31
42
|
uhwm_wait_output content.to_s
|
32
43
|
end
|
data/features/steps/run_steps.rb
CHANGED
@@ -24,11 +24,11 @@ When /^I run uhwm with options? (-.+)$/ do |options|
|
|
24
24
|
end
|
25
25
|
|
26
26
|
When /^I tell uhwm to quit$/ do
|
27
|
-
|
27
|
+
uhwm_request_quit
|
28
28
|
end
|
29
29
|
|
30
30
|
When /^I quit uhwm$/ do
|
31
|
-
|
31
|
+
uhwm_request_quit
|
32
32
|
assert_exit_status 0
|
33
33
|
end
|
34
34
|
|
data/features/steps/x_steps.rb
CHANGED
@@ -1,51 +1,56 @@
|
|
1
|
-
Given /^a
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
x_window_map
|
7
|
-
uhwm_wait_output /manag.+#{x_window_name}/i
|
1
|
+
Given /^a(?:\s(\w+))? window is mapped$/ do |ident|
|
2
|
+
x_client(ident).map.sync
|
3
|
+
timeout_until 'window not mapped after %d seconds' do
|
4
|
+
x_window_map_state(x_client(ident).window_id) == 'IsViewable'
|
5
|
+
end
|
8
6
|
end
|
9
7
|
|
10
8
|
When /^I press the ([^ ]+) keys?$/ do |keys|
|
11
9
|
x_key keys
|
12
10
|
end
|
13
11
|
|
14
|
-
When /^
|
15
|
-
|
12
|
+
When /^I press the ([^ ]+) keys? (\d+) times$/ do |keys, times|
|
13
|
+
times.to_i.times { x_key keys }
|
16
14
|
end
|
17
15
|
|
18
|
-
When /^
|
19
|
-
|
16
|
+
When /^a window requests to be mapped$/ do
|
17
|
+
x_client.map.sync
|
20
18
|
end
|
21
19
|
|
22
|
-
When /^
|
23
|
-
|
20
|
+
When /^a window requests to be mapped (\d+) times$/ do |times|
|
21
|
+
x_client.map times: times.to_i
|
24
22
|
end
|
25
23
|
|
26
|
-
When /^
|
27
|
-
|
24
|
+
When /^the(?:\s(\w+))? window is unmapped$/ do |ident|
|
25
|
+
x_client(ident).unmap.sync
|
26
|
+
timeout_until 'window not unmapped after %d seconds' do
|
27
|
+
x_window_map_state(x_client(ident).window_id) == 'IsUnMapped'
|
28
|
+
end
|
28
29
|
end
|
29
30
|
|
30
31
|
When /^the window is destroyed$/ do
|
31
|
-
|
32
|
+
x_client.destroy.sync
|
32
33
|
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
expect(x_socket_check uhwm_pid).to be true
|
35
|
+
When /^the window name changes to "([^"]+)"$/ do |name|
|
36
|
+
x_client.window_name = name
|
37
37
|
end
|
38
38
|
|
39
|
-
Then /^
|
40
|
-
|
39
|
+
Then /^it must connect to X display$/ do
|
40
|
+
uhwm_wait_ready
|
41
|
+
expect(x_socket_check uhwm.pid).to be true
|
41
42
|
end
|
42
43
|
|
43
|
-
Then /^the
|
44
|
-
|
44
|
+
Then /^the(?:\s(\w+))? window must be mapped$/ do |ident|
|
45
|
+
timeout_until 'window not mapped after %d seconds' do
|
46
|
+
x_window_map_state(x_client(ident).window_id) == 'IsViewable'
|
47
|
+
end
|
45
48
|
end
|
46
49
|
|
47
50
|
Then /^the window must be focused$/ do
|
48
|
-
|
51
|
+
timeout_until 'window not focused after %d seconds' do
|
52
|
+
x_focused_window_id == x_client.window_id
|
53
|
+
end
|
49
54
|
end
|
50
55
|
|
51
56
|
Then /^the input event mask must include (.+)$/ do |mask|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Feature: blocking worker
|
2
|
+
|
3
|
+
Scenario: processes initial events
|
4
|
+
Given uhwm is running with options -d -w block
|
5
|
+
Then the output must match /xevent/i at least 2 times
|
6
|
+
|
7
|
+
Scenario: processes generated events
|
8
|
+
Given a run control file with:
|
9
|
+
"""
|
10
|
+
key(:f) { puts 'testing_worker_read' }
|
11
|
+
"""
|
12
|
+
And uhwm is running with options -d -w block
|
13
|
+
When I press the alt+f key 3 times
|
14
|
+
And I quit uhwm
|
15
|
+
Then the output must match /(testing_worker_read)/ exactly 3 times
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Feature: multiplexing worker
|
2
|
+
|
3
|
+
Scenario: processes initial events
|
4
|
+
Given uhwm is running with options -d -w mux
|
5
|
+
Then the output must match /xevent/i at least 2 times
|
6
|
+
|
7
|
+
Scenario: processes generated events
|
8
|
+
Given a run control file with:
|
9
|
+
"""
|
10
|
+
key(:f) { puts 'testing_worker_read' }
|
11
|
+
"""
|
12
|
+
And uhwm is running with options -d -w mux
|
13
|
+
When I press the alt+f key 3 times
|
14
|
+
And I quit uhwm
|
15
|
+
Then the output must match /(testing_worker_read)/ exactly 3 times
|
data/lib/uh/wm/client.rb
CHANGED
data/lib/uh/wm/env.rb
CHANGED
@@ -21,8 +21,8 @@ module Uh
|
|
21
21
|
def_delegators :@output, :print, :puts
|
22
22
|
|
23
23
|
attr_reader :output, :keybinds
|
24
|
-
attr_accessor :verbose, :debug, :rc_path, :
|
25
|
-
:
|
24
|
+
attr_accessor :verbose, :debug, :rc_path, :modifier, :worker,
|
25
|
+
:layout, :layout_class
|
26
26
|
|
27
27
|
def initialize output
|
28
28
|
@output = output
|
data/lib/uh/wm/manager.rb
CHANGED
@@ -59,6 +59,7 @@ module Uh
|
|
59
59
|
return if window.override_redirect? || client_for(window)
|
60
60
|
@clients << client = Client.new(window)
|
61
61
|
@events.emit :manage, args: client
|
62
|
+
@display.listen_events window, Events::PROPERTY_CHANGE_MASK
|
62
63
|
end
|
63
64
|
|
64
65
|
def unmap window
|
@@ -66,15 +67,19 @@ module Uh
|
|
66
67
|
if client.unmap_count > 0
|
67
68
|
client.unmap_count -= 1
|
68
69
|
else
|
69
|
-
|
70
|
-
@events.emit :unmanage, args: client
|
70
|
+
unmanage client
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
74
|
def destroy window
|
75
75
|
return unless client = client_for(window)
|
76
|
-
|
77
|
-
|
76
|
+
unmanage client
|
77
|
+
end
|
78
|
+
|
79
|
+
def update_properties window
|
80
|
+
return unless client = client_for(window)
|
81
|
+
client.update_window_properties
|
82
|
+
@events.emit :change, args: client
|
78
83
|
end
|
79
84
|
|
80
85
|
def handle_next_event
|
@@ -113,10 +118,18 @@ module Uh
|
|
113
118
|
destroy event.window
|
114
119
|
end
|
115
120
|
|
121
|
+
def handle_expose event
|
122
|
+
@events.emit :expose, args: event.window
|
123
|
+
end
|
124
|
+
|
116
125
|
def handle_map_request event
|
117
126
|
map event.window
|
118
127
|
end
|
119
128
|
|
129
|
+
def handle_property_notify event
|
130
|
+
update_properties event.window
|
131
|
+
end
|
132
|
+
|
120
133
|
def handle_unmap_notify event
|
121
134
|
unmap event.window
|
122
135
|
end
|
@@ -125,6 +138,11 @@ module Uh
|
|
125
138
|
@clients.find { |e| e.window == window }
|
126
139
|
end
|
127
140
|
|
141
|
+
def unmanage client
|
142
|
+
@clients.delete client
|
143
|
+
@events.emit :unmanage, args: client
|
144
|
+
end
|
145
|
+
|
128
146
|
def check_other_wm!
|
129
147
|
Display.on_error { fail OtherWMRunningError }
|
130
148
|
@display.listen_events INPUT_MASK
|
data/lib/uh/wm/run_control.rb
CHANGED
@@ -32,6 +32,18 @@ module Uh
|
|
32
32
|
@env.keybinds[translate_keysym *keysyms] = block
|
33
33
|
end
|
34
34
|
|
35
|
+
def layout arg, **options
|
36
|
+
if arg.is_a? Class
|
37
|
+
if options.any?
|
38
|
+
@env.layout = arg.new options
|
39
|
+
else
|
40
|
+
@env.layout_class = arg
|
41
|
+
end
|
42
|
+
else
|
43
|
+
@env.layout = arg
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
35
47
|
def worker type, **options
|
36
48
|
@env.worker = [type, options]
|
37
49
|
end
|
data/lib/uh/wm/runner.rb
CHANGED
@@ -51,19 +51,14 @@ module Uh
|
|
51
51
|
|
52
52
|
def connect_manager
|
53
53
|
manager.connect
|
54
|
-
@env.keybinds.each
|
55
|
-
manager.grab_key *keysym
|
56
|
-
end
|
54
|
+
@env.keybinds.each { |keysym, _| manager.grab_key *keysym }
|
57
55
|
end
|
58
56
|
|
59
57
|
def worker
|
60
58
|
@worker ||= Workers.build(*(@env.worker)).tap do |w|
|
61
|
-
w.
|
62
|
-
|
63
|
-
|
64
|
-
w.on_read_next do
|
65
|
-
@manager.handle_next_event
|
66
|
-
end
|
59
|
+
w.before_watch { @manager.handle_pending_events }
|
60
|
+
w.on_read { @manager.handle_pending_events }
|
61
|
+
w.on_read_next { @manager.handle_next_event }
|
67
62
|
w.on_timeout do |*args|
|
68
63
|
log_debug "Worker timeout: #{args.inspect}"
|
69
64
|
log_debug 'Flushing X output buffer'
|
@@ -119,6 +114,14 @@ module Uh
|
|
119
114
|
log "Unmanaging client #{client}"
|
120
115
|
layout.remove client
|
121
116
|
end
|
117
|
+
@events.on :change do |client|
|
118
|
+
log "Updating client #{client}"
|
119
|
+
layout.update client
|
120
|
+
end
|
121
|
+
@events.on :expose do |window|
|
122
|
+
log "Exposing window: #{window}"
|
123
|
+
layout.expose window
|
124
|
+
end
|
122
125
|
end
|
123
126
|
|
124
127
|
def register_keybinds_hooks
|