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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ba8fdd593aed4b5a3c017c9dba5f2bf97e180b90
4
- data.tar.gz: 1bc9621e7454e1fd4aaf1370eaee472ec35281eb
3
+ metadata.gz: 40e271eacf6628e4196a0a442cda080fad7e920d
4
+ data.tar.gz: c75d3a2df941bc52cef89ffbcc6c9268637e871a
5
5
  SHA512:
6
- metadata.gz: b7a6b5b73f564fb63fcf89724307dd9a5934b9fd3210e90c6df722ed1159928638485706090e3c94d9cddb3db4578398f83efe3c997b86e4c126974b91c855ca
7
- data.tar.gz: 40cbe74253fa28aa76cf0eb5cf762bd14c1fe4ddced31a4e6143fd6751bb6eac65974bc77b45f993828e109714ce34b33c304bf8096a1c5de758a992c1a3fcfa
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 obeying a defined
10
- protocol.
14
+ `uh-layout` ruby gem. A layout is a simple ruby object responding to
15
+ specific methods.
11
16
 
12
- Features:
17
+ Main features:
13
18
 
14
19
  * Xinerama support;
15
20
  * Multiple event handling strategy: blocking or multiplexing
16
- (`select()`);
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 strategy;
21
- * Program execution via key binding.
22
-
23
- * No re-parenting (so no window decoration either);
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
 
@@ -8,5 +8,5 @@ Feature: layout client management
8
8
  Then the window must be mapped
9
9
 
10
10
  Scenario: focuses new client window
11
- When a window requests to be mapped
11
+ When a window is mapped
12
12
  Then the window must be focused
@@ -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 the window name
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+/
@@ -6,5 +6,5 @@ Feature: layout client unmanagement
6
6
  And a second window is mapped
7
7
 
8
8
  Scenario: maps another window
9
- When the second window requests to be unmapped
9
+ When the second window is unmapped
10
10
  Then the first window must be mapped
@@ -0,0 +1,7 @@
1
+ Feature: clients window properties updating
2
+
3
+ Scenario: logs when the window properties of a client change
4
+ Given uhwm is running
5
+ And a window is mapped
6
+ When the window name changes to "testing_new_name"
7
+ Then the output must match /updat.+testing_new_name/i
@@ -0,0 +1,5 @@
1
+ Feature: expose events handling
2
+
3
+ Scenario: logs when an expose event is handled
4
+ Given uhwm is running
5
+ Then the output must match /expos.+window.+\d+/i
@@ -2,10 +2,10 @@ Feature: manager client unmanagement
2
2
 
3
3
  Background:
4
4
  Given uhwm is running
5
- And a window is managed
5
+ And a window is mapped
6
6
 
7
7
  Scenario: logs when a new client is unmanaged
8
- When the window requests to be unmapped
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"
@@ -9,5 +9,4 @@ Feature: program termination
9
9
 
10
10
  Scenario: logs about termination
11
11
  When I tell uhwm to quit
12
- Then uhwm must terminate successfully
13
- And the output must match /terminat/i
12
+ Then the output must match /terminat/i
@@ -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
@@ -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
- x_key 'alt+shift+q'
27
+ uhwm_request_quit
28
28
  end
29
29
 
30
30
  When /^I quit uhwm$/ do
31
- x_key 'alt+shift+q'
31
+ uhwm_request_quit
32
32
  assert_exit_status 0
33
33
  end
34
34
 
@@ -1,51 +1,56 @@
1
- Given /^a (\w+) window is mapped$/ do |ident|
2
- x_window_map ident: ident
3
- end
4
-
5
- Given /^a window is managed$/ do
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 /^a window requests to be mapped$/ do
15
- x_window_map
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 /^the window requests to be unmapped$/ do
19
- x_window_unmap
16
+ When /^a window requests to be mapped$/ do
17
+ x_client.map.sync
20
18
  end
21
19
 
22
- When /^the (\w+) window requests to be unmapped$/ do |ident|
23
- x_window_unmap ident: ident
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 /^a window requests to be mapped (\d+) times$/ do |times|
27
- x_window_map times: times.to_i
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
- x_window_destroy
32
+ x_client.destroy.sync
32
33
  end
33
34
 
34
- Then /^it must connect to X display$/ do
35
- uhwm_wait_output 'Connected to'
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 /^the window must be mapped$/ do
40
- expect(x_window_map_state).to eq 'IsViewable'
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 (\w+) window must be mapped$/ do |ident|
44
- expect(x_window_map_state ident: ident).to eq 'IsViewable'
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
- expect(x_focused_window_id).to eq x_window_id
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
@@ -10,8 +10,12 @@ module Uh
10
10
  @env, @events = env, events
11
11
  end
12
12
 
13
- def evaluate code
14
- instance_eval &code
13
+ def evaluate code = nil, &block
14
+ if code
15
+ instance_exec &code
16
+ else
17
+ instance_exec &block
18
+ end
15
19
  end
16
20
 
17
21
  def quit
data/lib/uh/wm/client.rb CHANGED
@@ -31,6 +31,11 @@ module Uh
31
31
  @wclass ||= @window.wclass
32
32
  end
33
33
 
34
+ def update_window_properties
35
+ @wname = @window.name
36
+ @wclass = @window.wclass
37
+ end
38
+
34
39
  def configure
35
40
  @window.configure @geo
36
41
  self
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, :layout_class, :modifier,
25
- :worker
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
- @clients.delete client
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
- @clients.delete client
77
- @events.emit :unmanage, args: client
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
@@ -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 do |keysym, _|
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.on_read do
62
- @manager.handle_pending_events
63
- end
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