From cd76c4e270195e1b08dea4a5ef4a7f33c6bcce19 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 17:34:36 +0000 Subject: [PATCH 01/18] Implement basic Manager --- lib/uh/wm.rb | 1 + lib/uh/wm/manager.rb | 15 +++++++++++++++ spec/uh/wm/manager_spec.rb | 20 ++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 lib/uh/wm/manager.rb create mode 100644 spec/uh/wm/manager_spec.rb diff --git a/lib/uh/wm.rb b/lib/uh/wm.rb index 553cec2..fb7e515 100644 --- a/lib/uh/wm.rb +++ b/lib/uh/wm.rb @@ -2,6 +2,7 @@ require 'uh' require 'uh/wm/cli' require 'uh/wm/env' +require 'uh/wm/manager' module Uh module WM diff --git a/lib/uh/wm/manager.rb b/lib/uh/wm/manager.rb new file mode 100644 index 0000000..aa9aedb --- /dev/null +++ b/lib/uh/wm/manager.rb @@ -0,0 +1,15 @@ +module Uh + module WM + class Manager + attr_reader :display + + def initialize + @display = Display.new + end + + def connect + @display.open + end + end + end +end diff --git a/spec/uh/wm/manager_spec.rb b/spec/uh/wm/manager_spec.rb new file mode 100644 index 0000000..312eaaa --- /dev/null +++ b/spec/uh/wm/manager_spec.rb @@ -0,0 +1,20 @@ +module Uh + module WM + RSpec.describe Manager do + subject(:manager) { described_class.new } + + describe '#initialize' do + it 'assigns a new display' do + expect(manager.display).to be_a Display + end + end + + describe '#connect' do + it 'opens the display' do + expect(manager.display).to receive :open + manager.connect + end + end + end + end +end From ea0034fd7e748e3a996e4ad56a800bbddcca2214 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 17:35:27 +0000 Subject: [PATCH 02/18] Implement basic Runner --- lib/uh/wm.rb | 1 + lib/uh/wm/runner.rb | 24 ++++++++++++++++++++ spec/uh/wm/runner_spec.rb | 46 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 lib/uh/wm/runner.rb create mode 100644 spec/uh/wm/runner_spec.rb diff --git a/lib/uh/wm.rb b/lib/uh/wm.rb index fb7e515..244715a 100644 --- a/lib/uh/wm.rb +++ b/lib/uh/wm.rb @@ -3,6 +3,7 @@ require 'uh' require 'uh/wm/cli' require 'uh/wm/env' require 'uh/wm/manager' +require 'uh/wm/runner' module Uh module WM diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb new file mode 100644 index 0000000..7407470 --- /dev/null +++ b/lib/uh/wm/runner.rb @@ -0,0 +1,24 @@ +module Uh + module WM + class Runner + class << self + def run env + runner = new env + runner.connect_manager + end + end + + attr_reader :env, :manager + + def initialize env + @env = env + @manager = Manager.new + end + + def connect_manager + @manager.connect + @env.log "Connected to X server" + end + end + end +end diff --git a/spec/uh/wm/runner_spec.rb b/spec/uh/wm/runner_spec.rb new file mode 100644 index 0000000..d160cec --- /dev/null +++ b/spec/uh/wm/runner_spec.rb @@ -0,0 +1,46 @@ +module Uh + module WM + RSpec.describe Runner do + let(:env) { Env.new(StringIO.new) } + subject(:runner) { described_class.new env } + + describe '.run' do + subject(:run) { described_class.run env } + + it 'builds a new Runner with given env' do + expect(described_class).to receive(:new).with(env).and_call_original + run + end + + it 'connects the manager' do + runner + allow(described_class).to receive(:new) { runner } + expect(runner).to receive(:connect_manager) + run + end + end + + describe '#initialize' do + it 'assigns the env' do + expect(runner.env).to be env + end + + it 'assigns a new Manager' do + expect(runner.manager).to be_a Manager + end + end + + describe '#connect_manager' do + it 'connects the manager' do + expect(runner.manager).to receive :connect + runner.connect_manager + end + + it 'logs a message when connected' do + expect(env).to receive(:log).with /connected/i + runner.connect_manager + end + end + end + end +end From 49fe77ddb10bf96d0cd341645aa8ffd8bbb23b70 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 17:36:11 +0000 Subject: [PATCH 03/18] Integrate our new Runner into CLI --- lib/uh/wm/cli.rb | 4 +--- spec/uh/wm/cli_spec.rb | 13 ++----------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/lib/uh/wm/cli.rb b/lib/uh/wm/cli.rb index 5ea3e54..bf478db 100644 --- a/lib/uh/wm/cli.rb +++ b/lib/uh/wm/cli.rb @@ -32,9 +32,7 @@ module Uh end def run - @display = Display.new - @display.open - @env.log "Connected to X server on `#{@display}'" + Runner.run env end diff --git a/spec/uh/wm/cli_spec.rb b/spec/uh/wm/cli_spec.rb index 5b6b5de..193ed83 100644 --- a/spec/uh/wm/cli_spec.rb +++ b/spec/uh/wm/cli_spec.rb @@ -63,19 +63,10 @@ module Uh end describe '#run' do - let(:display) { instance_spy Display } - - before { allow(Display).to receive(:new) { display } } - - it 'opens a new X display' do - expect(display).to receive :open + it 'runs a runner with the env' do + expect(Runner).to receive(:run).with(cli.env) cli.run end - - it 'prints a message on standard output when connected' do - cli.run - expect(stdout.string).to match /connected/i - end end describe '#parse_arguments!' do From 84ad217d5bd78ceacf328429733bc7c42857e880 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 20:17:51 +0000 Subject: [PATCH 04/18] Implement a basic event dispatcher --- lib/uh/wm.rb | 1 + lib/uh/wm/dispatcher.rb | 27 +++++++++++++++++++++ spec/uh/wm/dispatcher_spec.rb | 44 +++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 lib/uh/wm/dispatcher.rb create mode 100644 spec/uh/wm/dispatcher_spec.rb diff --git a/lib/uh/wm.rb b/lib/uh/wm.rb index 244715a..4034c03 100644 --- a/lib/uh/wm.rb +++ b/lib/uh/wm.rb @@ -1,6 +1,7 @@ require 'uh' require 'uh/wm/cli' +require 'uh/wm/dispatcher' require 'uh/wm/env' require 'uh/wm/manager' require 'uh/wm/runner' diff --git a/lib/uh/wm/dispatcher.rb b/lib/uh/wm/dispatcher.rb new file mode 100644 index 0000000..a7b0298 --- /dev/null +++ b/lib/uh/wm/dispatcher.rb @@ -0,0 +1,27 @@ +module Uh + module WM + class Dispatcher + attr_reader :hooks + + def initialize hooks = Hash.new + @hooks = hooks + end + + def [] *key + @hooks[translate_key key] or [] + end + + def on *key, &block + @hooks[translate_key key] ||= [] + @hooks[translate_key key] << block + end + + + private + + def translate_key key + key.one? ? key[0] : key + end + end + end +end diff --git a/spec/uh/wm/dispatcher_spec.rb b/spec/uh/wm/dispatcher_spec.rb new file mode 100644 index 0000000..277a02a --- /dev/null +++ b/spec/uh/wm/dispatcher_spec.rb @@ -0,0 +1,44 @@ +module Uh + module WM + RSpec.describe Dispatcher do + let(:hooks) { {} } + subject(:dispatcher) { described_class.new hooks } + + describe '#[]' do + context 'when given key for existing hook' do + let(:hooks) { { hook_key: [:hook] } } + + it 'returns registered hooks for this key' do + expect(dispatcher[:hook_key]).to eq [:hook] + end + end + + context 'when given multiple keys for existing hook' do + let(:hooks) { { %i[hook key] => [:hook] } } + + it 'returns registered hooks for this key' do + expect(dispatcher[:hook, :key]).to eq [:hook] + end + end + + context 'when given key for unknown hook' do + it 'returns an empty array' do + expect(dispatcher[:unknown_hook]).to eq [] + end + end + end + + describe '#on' do + it 'registers given hook for given key' do + dispatcher.on(:hook_key) { :hook } + expect(dispatcher.hooks[:hook_key]).to be + end + + it 'registers given hook for given multiple keys' do + dispatcher.on(:hook, :key) { :hook } + expect(dispatcher.hooks[%i[hook key]]).to be + end + end + end + end +end From b4b4f086d4e4f563e81e5bddfbf33b41321aacd8 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 20:42:30 +0000 Subject: [PATCH 05/18] Implement Manager#grab_key --- lib/uh/wm/manager.rb | 4 ++++ spec/uh/wm/manager_spec.rb | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/uh/wm/manager.rb b/lib/uh/wm/manager.rb index aa9aedb..99e0ac0 100644 --- a/lib/uh/wm/manager.rb +++ b/lib/uh/wm/manager.rb @@ -10,6 +10,10 @@ module Uh def connect @display.open end + + def grab_key keysym + @display.grab_key keysym.to_s, KEY_MODIFIERS[:mod1] + end end end end diff --git a/spec/uh/wm/manager_spec.rb b/spec/uh/wm/manager_spec.rb index 312eaaa..75e11b1 100644 --- a/spec/uh/wm/manager_spec.rb +++ b/spec/uh/wm/manager_spec.rb @@ -15,6 +15,14 @@ module Uh manager.connect end end + + describe '#grab_key' do + it 'grabs given key on the display' do + expect(manager.display) + .to receive(:grab_key).with('q', KEY_MODIFIERS[:mod1]) + manager.grab_key :q + end + end end end end From 44a69b75c6df923037e55498e5ec9cdb992d627e Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 21:29:53 +0000 Subject: [PATCH 06/18] Accept a Manager instance in Runner constructor --- lib/uh/wm/runner.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index 7407470..96548db 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -10,9 +10,9 @@ module Uh attr_reader :env, :manager - def initialize env + def initialize env, manager: Manager.new @env = env - @manager = Manager.new + @manager = manager end def connect_manager From b354ffcd62d5d59749efced05c1e8015b9a7cfc4 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 21:44:04 +0000 Subject: [PATCH 07/18] Add stopped status notion in Runner --- lib/uh/wm/runner.rb | 8 ++++++++ spec/uh/wm/runner_spec.rb | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index 96548db..5456b8d 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -15,6 +15,14 @@ module Uh @manager = manager end + def stopped? + !!@stopped + end + + def stop! + @stopped = true + end + def connect_manager @manager.connect @env.log "Connected to X server" diff --git a/spec/uh/wm/runner_spec.rb b/spec/uh/wm/runner_spec.rb index d160cec..bff1e85 100644 --- a/spec/uh/wm/runner_spec.rb +++ b/spec/uh/wm/runner_spec.rb @@ -28,6 +28,34 @@ module Uh it 'assigns a new Manager' do expect(runner.manager).to be_a Manager end + + it 'is not stopped' do + expect(runner).not_to be_stopped + end + end + + describe '#stopped?' do + context 'when not stopped' do + it 'returns false' do + expect(runner.stopped?).to be false + end + end + + context 'when stopped' do + before { runner.stop! } + + it 'returns true' do + expect(runner.stopped?).to be true + end + end + end + + describe '#stop!' do + it 'sets the runner as stopped' do + expect { runner.stop! } + .to change { runner.stopped? } + .from(false).to(true) + end end describe '#connect_manager' do From d3007201ccf71f2975d1b509200cf223c7e866a4 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 22:23:42 +0000 Subject: [PATCH 08/18] Accept Display instance in Manager constructor --- lib/uh/wm/manager.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/uh/wm/manager.rb b/lib/uh/wm/manager.rb index 99e0ac0..8a93167 100644 --- a/lib/uh/wm/manager.rb +++ b/lib/uh/wm/manager.rb @@ -3,8 +3,8 @@ module Uh class Manager attr_reader :display - def initialize - @display = Display.new + def initialize display = Display.new + @display = display end def connect From 585903240b788a47ee32d03c3330cb59c9c33ff5 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 22:26:30 +0000 Subject: [PATCH 09/18] Implement Manager#handle_pending_events --- lib/uh/wm/manager.rb | 7 +++++++ spec/uh/wm/manager_spec.rb | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/lib/uh/wm/manager.rb b/lib/uh/wm/manager.rb index 8a93167..7dd3b38 100644 --- a/lib/uh/wm/manager.rb +++ b/lib/uh/wm/manager.rb @@ -14,6 +14,13 @@ module Uh def grab_key keysym @display.grab_key keysym.to_s, KEY_MODIFIERS[:mod1] end + + def handle_pending_events + handle @display.next_event while @display.pending? + end + + def handle event + end end end end diff --git a/spec/uh/wm/manager_spec.rb b/spec/uh/wm/manager_spec.rb index 75e11b1..95b4544 100644 --- a/spec/uh/wm/manager_spec.rb +++ b/spec/uh/wm/manager_spec.rb @@ -1,7 +1,8 @@ module Uh module WM RSpec.describe Manager do - subject(:manager) { described_class.new } + let(:display) { Display.new } + subject(:manager) { described_class.new display } describe '#initialize' do it 'assigns a new display' do @@ -23,6 +24,38 @@ module Uh manager.grab_key :q end end + + describe '#handle_pending_events' do + let(:event) { double 'event' } + + context 'when an event is pending on display' do + before do + allow(display).to receive(:pending?).and_return true, false + allow(display).to receive(:next_event) { event } + end + + it 'handles the event' do + expect(manager).to receive(:handle).with(event).once + manager.handle_pending_events + end + end + + context 'when multiple events are pending on display' do + before do + allow(display).to receive(:pending?).and_return true, true, false + allow(display).to receive(:next_event) { event } + end + + it 'handles all pending events' do + expect(manager).to receive(:handle).with(event).twice + manager.handle_pending_events + end + end + end + + describe '#handle' do + it 'handles an event' + end end end end From fd13accaf65ee3863d2a11275f9b9b74d11cceeb Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 22:27:36 +0000 Subject: [PATCH 10/18] Assign a Dispatcher in new Runner instances --- lib/uh/wm/runner.rb | 3 ++- spec/uh/wm/runner_spec.rb | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index 5456b8d..a39c70d 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -8,10 +8,11 @@ module Uh end end - attr_reader :env, :manager + attr_reader :env, :events, :manager def initialize env, manager: Manager.new @env = env + @events = Dispatcher.new @manager = manager end diff --git a/spec/uh/wm/runner_spec.rb b/spec/uh/wm/runner_spec.rb index bff1e85..6b40cd4 100644 --- a/spec/uh/wm/runner_spec.rb +++ b/spec/uh/wm/runner_spec.rb @@ -25,6 +25,10 @@ module Uh expect(runner.env).to be env end + it 'assigns a new Dispatcher' do + expect(runner.events).to be_a Dispatcher + end + it 'assigns a new Manager' do expect(runner.manager).to be_a Manager end From 7c8b3120842ce4bebab5967e50b60bb97548ba87 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 22:28:28 +0000 Subject: [PATCH 11/18] Accept stopped status param in Runner constructor --- lib/uh/wm/runner.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index a39c70d..f876a9e 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -10,10 +10,11 @@ module Uh attr_reader :env, :events, :manager - def initialize env, manager: Manager.new + def initialize env, manager: Manager.new, stopped: false @env = env @events = Dispatcher.new @manager = manager + @stopped = stopped end def stopped? From 6b0676e5474044f24616e995c6d94b32418980b3 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 22:29:29 +0000 Subject: [PATCH 12/18] Accept constructor options in Runner.run factory --- lib/uh/wm/runner.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index f876a9e..f7421e8 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -2,8 +2,8 @@ module Uh module WM class Runner class << self - def run env - runner = new env + def run env, **options + runner = new env, **options runner.connect_manager end end From ca8f60365f2a4d162ba82eee2e70cd77bc855ddf Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 22:42:48 +0000 Subject: [PATCH 13/18] Ignore /tmp/ from version control --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e398d24..0fcf412 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /Gemfile-custom.rb /Gemfile.lock +/tmp/ From 7becda9f31cac399172058e0ed4daddcb25c768e Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 23:37:02 +0000 Subject: [PATCH 14/18] Implement Dispatcher#emit --- lib/uh/wm/dispatcher.rb | 4 ++++ spec/uh/wm/dispatcher_spec.rb | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/uh/wm/dispatcher.rb b/lib/uh/wm/dispatcher.rb index a7b0298..697e5af 100644 --- a/lib/uh/wm/dispatcher.rb +++ b/lib/uh/wm/dispatcher.rb @@ -16,6 +16,10 @@ module Uh @hooks[translate_key key] << block end + def emit *key + @hooks[translate_key key].tap { |o| o.each { |e| e.call } if o } + end + private diff --git a/spec/uh/wm/dispatcher_spec.rb b/spec/uh/wm/dispatcher_spec.rb index 277a02a..bd06d11 100644 --- a/spec/uh/wm/dispatcher_spec.rb +++ b/spec/uh/wm/dispatcher_spec.rb @@ -39,6 +39,26 @@ module Uh expect(dispatcher.hooks[%i[hook key]]).to be end end + + describe '#emit' do + it 'calls hooks registered for given key' do + dispatcher.on(:hook_key) { throw :hook_code } + expect { dispatcher.emit :hook_key }.to throw_symbol :hook_code + end + + context 'when no hooks are registered for given key' do + it 'does not call another hook' do + dispatcher.on(:hook_key) { throw :hook_code } + expect { dispatcher.emit :other_hook_key }.not_to throw_symbol + end + end + + context 'when no hooks are registered at all' do + it 'does not raise any error' do + expect { dispatcher.emit :hook_key }.not_to raise_error + end + end + end end end end From 498feb809e2894a1774be2f89cde21bea8be9ea0 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 23:38:32 +0000 Subject: [PATCH 15/18] Instanciate Manager with a mandatory Dispatcher --- lib/uh/wm/manager.rb | 5 +++-- lib/uh/wm/runner.rb | 4 ++-- spec/uh/wm/manager_spec.rb | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/uh/wm/manager.rb b/lib/uh/wm/manager.rb index 7dd3b38..1845365 100644 --- a/lib/uh/wm/manager.rb +++ b/lib/uh/wm/manager.rb @@ -3,8 +3,9 @@ module Uh class Manager attr_reader :display - def initialize display = Display.new - @display = display + def initialize events, display = Display.new + @events = events + @display = display end def connect diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index f7421e8..a4dd118 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -10,10 +10,10 @@ module Uh attr_reader :env, :events, :manager - def initialize env, manager: Manager.new, stopped: false + def initialize env, manager: nil, stopped: false @env = env @events = Dispatcher.new - @manager = manager + @manager = manager || Manager.new(@events) @stopped = stopped end diff --git a/spec/uh/wm/manager_spec.rb b/spec/uh/wm/manager_spec.rb index 95b4544..f145a2f 100644 --- a/spec/uh/wm/manager_spec.rb +++ b/spec/uh/wm/manager_spec.rb @@ -1,8 +1,9 @@ module Uh module WM RSpec.describe Manager do + let(:events) { Dispatcher.new } let(:display) { Display.new } - subject(:manager) { described_class.new display } + subject(:manager) { described_class.new events, display } describe '#initialize' do it 'assigns a new display' do From c8f12af987636d19f0a91751ab1b965f517c982a Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 23:40:05 +0000 Subject: [PATCH 16/18] Implement Manager#handle --- lib/uh/wm/manager.rb | 3 +++ spec/uh/wm/manager_spec.rb | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/uh/wm/manager.rb b/lib/uh/wm/manager.rb index 1845365..0148d8a 100644 --- a/lib/uh/wm/manager.rb +++ b/lib/uh/wm/manager.rb @@ -21,6 +21,9 @@ module Uh end def handle event + case event.type + when :key_press then @events.emit :key, event.key.to_sym + end end end end diff --git a/spec/uh/wm/manager_spec.rb b/spec/uh/wm/manager_spec.rb index f145a2f..032a40b 100644 --- a/spec/uh/wm/manager_spec.rb +++ b/spec/uh/wm/manager_spec.rb @@ -55,7 +55,14 @@ module Uh end describe '#handle' do - it 'handles an event' + context 'when key_release event is given' do + let(:event) { double 'event', type: :key_press, key: 'q' } + + it 'emits :key event with the corresponding key' do + events.on(:key, :q) { throw :key_press_code } + expect { manager.handle event }.to throw_symbol :key_press_code + end + end end end end From 224ae6be5fc0b5d546425a54050db0189d9ec1b1 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Thu, 9 Apr 2015 00:11:23 +0000 Subject: [PATCH 17/18] Implement Runner#run_until --- lib/uh/wm/runner.rb | 4 ++++ spec/uh/wm/runner_spec.rb | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index a4dd118..f279c9f 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -29,6 +29,10 @@ module Uh @manager.connect @env.log "Connected to X server" end + + def run_until &block + @manager.handle_pending_events until block.call + end end end end diff --git a/spec/uh/wm/runner_spec.rb b/spec/uh/wm/runner_spec.rb index 6b40cd4..014c795 100644 --- a/spec/uh/wm/runner_spec.rb +++ b/spec/uh/wm/runner_spec.rb @@ -73,6 +73,15 @@ module Uh runner.connect_manager end end + + describe '#run_until' do + it 'tells the manager to handle events until given block is true' do + block = proc { } + allow(block).to receive(:call).and_return(false, false, false, true) + expect(runner.manager).to receive(:handle_pending_events).exactly(3).times + runner.run_until &block + end + end end end end From ceac19b346bae349cb61115b6d36fc9f5f56a1e9 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 8 Apr 2015 02:56:10 +0000 Subject: [PATCH 18/18] Quit on `mod1+q' key binding * Loop our runner until it is "stopped"; * Use the event dispatcher to stop the runner on `mod1+q' key press; * Tell the manager to grab the `q' key. --- bin/uhwm | 1 - features/actions/quit.feature | 6 ++++++ features/steps/run_steps.rb | 13 +++++++++++++ features/steps/x_steps.rb | 8 ++++++++ lib/uh/wm/runner.rb | 14 ++++++++++++++ spec/uh/wm/cli_spec.rb | 4 ++++ spec/uh/wm/runner_spec.rb | 31 ++++++++++++++++++++++++++++--- 7 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 features/actions/quit.feature diff --git a/bin/uhwm b/bin/uhwm index e03193c..562a83f 100755 --- a/bin/uhwm +++ b/bin/uhwm @@ -3,4 +3,3 @@ require 'uh/wm' Uh::WM::CLI.run(ARGV) -sleep 8 diff --git a/features/actions/quit.feature b/features/actions/quit.feature new file mode 100644 index 0000000..40c0839 --- /dev/null +++ b/features/actions/quit.feature @@ -0,0 +1,6 @@ +Feature: quit action + + Scenario: quits on keybing press + Given uhwm is running + When I press the default quit key binding + Then uhwm should terminate successfully diff --git a/features/steps/run_steps.rb b/features/steps/run_steps.rb index e617e27..70e5a56 100644 --- a/features/steps/run_steps.rb +++ b/features/steps/run_steps.rb @@ -4,6 +4,15 @@ def uhwm_run options = nil @interactive = @process = run command.join ' ' end +def uhwm_run_wait_ready + uhwm_run + uhwm_wait_output 'Connected to' +end + +Given /^uhwm is running$/ do + uhwm_run_wait_ready +end + When /^I start uhwm$/ do uhwm_run end @@ -15,3 +24,7 @@ end Then /^the exit status must be (\d+)$/ do |exit_status| assert_exit_status exit_status.to_i end + +Then /^uhwm should terminate successfully$/ do + assert_exit_status 0 +end diff --git a/features/steps/x_steps.rb b/features/steps/x_steps.rb index d7bcd9e..a900916 100644 --- a/features/steps/x_steps.rb +++ b/features/steps/x_steps.rb @@ -1,3 +1,11 @@ +def x_key key + fail "cannot simulate X key `#{key}'" unless system "xdotool key #{key}" +end + +When /^I press the default quit key binding$/ do + x_key 'alt+q' +end + Then /^it must connect to X display$/ do uhwm_wait_output 'Connected to' expect(`sockstat -u`.lines.grep /\s+ruby.+\s+#{@process.pid}/) diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index f279c9f..849acac 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -4,7 +4,9 @@ module Uh class << self def run env, **options runner = new env, **options + runner.register_event_hooks runner.connect_manager + runner.run_until { runner.stopped? } end end @@ -25,14 +27,26 @@ module Uh @stopped = true end + def register_event_hooks + register_key_bindings_hooks + end + def connect_manager @manager.connect @env.log "Connected to X server" + @manager.grab_key :q end def run_until &block @manager.handle_pending_events until block.call end + + + private + + def register_key_bindings_hooks + @events.on(:key, :q) { stop! } + end end end end diff --git a/spec/uh/wm/cli_spec.rb b/spec/uh/wm/cli_spec.rb index 193ed83..7bf4482 100644 --- a/spec/uh/wm/cli_spec.rb +++ b/spec/uh/wm/cli_spec.rb @@ -15,6 +15,10 @@ module Uh described_class.run arguments, stdout: stdout, stderr: stderr end + # FIXME: remove this hack we currently need to prevent the Runner from + # blocking. + before { allow(Runner).to receive :run } + it 'builds a new CLI with given arguments' do expect(described_class) .to receive(:new).with(arguments, stdout: stdout).and_call_original diff --git a/spec/uh/wm/runner_spec.rb b/spec/uh/wm/runner_spec.rb index 014c795..7f4a65a 100644 --- a/spec/uh/wm/runner_spec.rb +++ b/spec/uh/wm/runner_spec.rb @@ -5,15 +5,23 @@ module Uh subject(:runner) { described_class.new env } describe '.run' do - subject(:run) { described_class.run env } + subject(:run) { described_class.run env, stopped: true } it 'builds a new Runner with given env' do - expect(described_class).to receive(:new).with(env).and_call_original + expect(described_class) + .to receive(:new).with(env, anything).and_call_original + run + end + + it 'registers event hooks' do + runner.stop! + allow(described_class).to receive(:new) { runner } + expect(runner).to receive(:register_event_hooks) run end it 'connects the manager' do - runner + runner.stop! allow(described_class).to receive(:new) { runner } expect(runner).to receive(:connect_manager) run @@ -62,7 +70,19 @@ module Uh end end + describe '#register_event_hooks' do + context 'key bindings' do + it 'registers key bindings event hooks' do + runner.register_event_hooks + expect(runner.events[:key, :q]).not_to be_empty + end + end + end + describe '#connect_manager' do + let(:manager) { instance_spy Manager } + subject(:runner) { described_class.new env, manager: manager } + it 'connects the manager' do expect(runner.manager).to receive :connect runner.connect_manager @@ -72,6 +92,11 @@ module Uh expect(env).to receive(:log).with /connected/i runner.connect_manager end + + it 'tells the manager to grab keys' do + expect(runner.manager).to receive(:grab_key).with :q + runner.connect_manager + end end describe '#run_until' do