uh-wm 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|