From f26e16fe6e7ccd286212450b7dc20705541945ac Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Tue, 28 Apr 2015 11:52:15 +0000 Subject: [PATCH 1/5] Implement Client#kill and Client#kill! --- lib/uh/wm/client.rb | 14 ++++++++++++++ spec/support/factories.rb | 5 +++-- spec/uh/wm/client_spec.rb | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/lib/uh/wm/client.rb b/lib/uh/wm/client.rb index 328ccfa..c24b040 100644 --- a/lib/uh/wm/client.rb +++ b/lib/uh/wm/client.rb @@ -66,6 +66,20 @@ module Uh @window.focus self end + + def kill + if @window.icccm_wm_protocols.include? :WM_DELETE_WINDOW + @window.icccm_wm_delete + else + @window.kill + end + self + end + + def kill! + window.kill + self + end end end end diff --git a/spec/support/factories.rb b/spec/support/factories.rb index 73c32ab..3c7381a 100644 --- a/spec/support/factories.rb +++ b/spec/support/factories.rb @@ -17,11 +17,12 @@ module Factories modifier_mask: modifier_mask end - def mock_window override_redirect: false + def mock_window override_redirect: false, icccm_wm_protocols: [] instance_spy Uh::Window, 'window', to_s: 'wid', name: 'wname', wclass: 'wclass', - override_redirect?: override_redirect + override_redirect?: override_redirect, + icccm_wm_protocols: icccm_wm_protocols end end diff --git a/spec/uh/wm/client_spec.rb b/spec/uh/wm/client_spec.rb index d074646..807743c 100644 --- a/spec/uh/wm/client_spec.rb +++ b/spec/uh/wm/client_spec.rb @@ -1,7 +1,8 @@ module Uh module WM RSpec.describe Client do - let(:window) { mock_window } + let(:protocols) { [] } + let(:window) { mock_window icccm_wm_protocols: protocols } let(:geo) { build_geo } subject(:client) { described_class.new window, geo } @@ -143,6 +144,37 @@ module Uh expect(client.focus).to be client end end + + describe '#kill' do + it 'kills the window' do + expect(window).to receive :kill + client.kill + end + + it 'returns self' do + expect(client.kill).to be client + end + + context 'when window supports icccm wm delete' do + let(:protocols) { [:WM_DELETE_WINDOW] } + + it 'icccm deletes the window' do + expect(window).to receive :icccm_wm_delete + client.kill + end + end + end + + describe '#kill!' do + it 'kills the window' do + expect(window).to receive :kill + client.kill! + end + + it 'returns self' do + expect(client.kill!).to be client + end + end end end end From 97abd402b1a39b69d1679e318d59e91691861d6f Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 29 Apr 2015 02:36:36 +0000 Subject: [PATCH 2/5] Accept window names in x_window_map_state test helper --- lib/uh/wm/testing/acceptance_helpers.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/uh/wm/testing/acceptance_helpers.rb b/lib/uh/wm/testing/acceptance_helpers.rb index 4ef50f7..bf86f5e 100644 --- a/lib/uh/wm/testing/acceptance_helpers.rb +++ b/lib/uh/wm/testing/acceptance_helpers.rb @@ -89,8 +89,14 @@ expected `#{message}' (#{times}) not seen after #{e.timeout} seconds in: fail "cannot simulate X key `#{k}'" unless system "xdotool key #{k}" end - def x_window_map_state window_id - `xwininfo -id #{window_id}`[/Map State: (\w+)/, 1] + def x_window_map_state window_selector + select_args = case window_selector + when Integer then "-id #{window_selector}" + when String then "-name #{window_selector}" + else fail ArgumentError, + "not an Integer nor a String: `#{window_selector.inspect}'" + end + `xwininfo #{select_args}`[/Map State: (\w+)/, 1] end From eed9cdf0c091fa51da9e216edca0de6abda3a269 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 29 Apr 2015 02:37:31 +0000 Subject: [PATCH 3/5] Support usage of ICCCM compliant window in UAT --- features/support/env.rb | 4 ++++ lib/uh/wm/testing/acceptance_helpers.rb | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/features/support/env.rb b/features/support/env.rb index 3a7fcfc..b5333d3 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -28,6 +28,10 @@ Around '@other_wm_running' do |_, block| with_other_wm { block.call } end +After '@icccm_window' do + icccm_window_ensure_stop +end + if ENV.key? 'TRAVIS' ENV['UHWMTEST_TIMEOUT'] = 8.to_s end diff --git a/lib/uh/wm/testing/acceptance_helpers.rb b/lib/uh/wm/testing/acceptance_helpers.rb index bf86f5e..5bee5e6 100644 --- a/lib/uh/wm/testing/acceptance_helpers.rb +++ b/lib/uh/wm/testing/acceptance_helpers.rb @@ -8,6 +8,19 @@ module Uh QUIT_KEYBINDING = 'alt+shift+q'.freeze LOG_READY = 'Working events'.freeze + def icccm_window_start + @icccm_window = ChildProcess.build(*%w[xmessage window]) + @icccm_window.start + end + + def icccm_window_ensure_stop + @icccm_window.stop + end + + def icccm_window_name + 'xmessage' + end + def uhwm_run options = '-v' command = %w[uhwm] command << options if options From 10ad5d9a7610aa568cbf70d5416814c011ea973f Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 29 Apr 2015 02:43:57 +0000 Subject: [PATCH 4/5] Fix x_window_map_state UAT helper to hide output --- lib/uh/wm/testing/acceptance_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/uh/wm/testing/acceptance_helpers.rb b/lib/uh/wm/testing/acceptance_helpers.rb index 5bee5e6..061a5b5 100644 --- a/lib/uh/wm/testing/acceptance_helpers.rb +++ b/lib/uh/wm/testing/acceptance_helpers.rb @@ -109,7 +109,7 @@ expected `#{message}' (#{times}) not seen after #{e.timeout} seconds in: else fail ArgumentError, "not an Integer nor a String: `#{window_selector.inspect}'" end - `xwininfo #{select_args}`[/Map State: (\w+)/, 1] + `xwininfo #{select_args} 2> /dev/null`[/Map State: (\w+)/, 1] end From 1cc1f98ad2afc14c7b346df36285bbf00f52e483 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 29 Apr 2015 02:38:30 +0000 Subject: [PATCH 5/5] Implement `kill' action keyword When invoked, will kill the client returned by `layout.current_client`. ICCCM WM_DELETE_WINDOW is used instead if the window reports to support this protocol. --- features/actions/kill.feature | 11 +++++++++++ features/steps/x_steps.rb | 11 +++++++++++ lib/uh/wm/actions_handler.rb | 4 ++++ spec/uh/wm/actions_handler_spec.rb | 15 +++++++++++++++ 4 files changed, 41 insertions(+) create mode 100644 features/actions/kill.feature diff --git a/features/actions/kill.feature b/features/actions/kill.feature new file mode 100644 index 0000000..e9031a0 --- /dev/null +++ b/features/actions/kill.feature @@ -0,0 +1,11 @@ +Feature: `kill' action keyword + + @icccm_window + Scenario: kills current client + Given uhwm is running with this run control file: + """ + key(:f) { kill_current } + """ + And an ICCCM compliant window is mapped + When I press the alt+f keys + Then the ICCCM window must be unmapped by the manager diff --git a/features/steps/x_steps.rb b/features/steps/x_steps.rb index d145146..3ac42aa 100644 --- a/features/steps/x_steps.rb +++ b/features/steps/x_steps.rb @@ -1,3 +1,10 @@ +Given /^an ICCCM compliant window is mapped$/ do + icccm_window_start + timeout_until 'window not mapped after %d seconds' do + x_window_map_state(icccm_window_name) == 'IsViewable' + end +end + Given /^a(?:\s(\w+))? window is mapped$/ do |ident| x_client(ident).map.sync timeout_until 'window not mapped after %d seconds' do @@ -42,6 +49,10 @@ Then /^the(?:\s(\w+))? window must be mapped$/ do |ident| end end +Then /^the ICCCM window must be unmapped by the manager$/ do + uhwm_wait_output /unmanag.+#{icccm_window_name}/i +end + Then /^the window must be focused$/ do timeout_until 'window not focused after %d seconds' do x_focused_window_id == x_client.window_id diff --git a/lib/uh/wm/actions_handler.rb b/lib/uh/wm/actions_handler.rb index 01b7ab2..dc5cf2a 100644 --- a/lib/uh/wm/actions_handler.rb +++ b/lib/uh/wm/actions_handler.rb @@ -38,6 +38,10 @@ module Uh Process.waitpid pid end + def kill_current + layout.current_client.kill + end + def log_separator log '- ' * 24 end diff --git a/spec/uh/wm/actions_handler_spec.rb b/spec/uh/wm/actions_handler_spec.rb index dcaa238..ce15031 100644 --- a/spec/uh/wm/actions_handler_spec.rb +++ b/spec/uh/wm/actions_handler_spec.rb @@ -24,6 +24,21 @@ module Uh end end + describe '#kill_current' do + let(:client) { instance_spy Client } + + context 'when layout has a client' do + before do + allow(actions.layout).to receive(:current_client) { client } + end + + it 'kills layout current client' do + expect(client).to receive :kill + actions.kill_current + end + end + end + describe '#log_separator' do it 'logs a separator' do expect(env).to receive(:log).with /(?:- ){20,}/