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 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