From 3f39b9026990eb91fd17a2074bd059de24563d51 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Thu, 16 Apr 2015 09:30:32 +0000 Subject: [PATCH 1/7] Listen events for window management in Manager --- lib/uh/wm/manager.rb | 7 ++++++- spec/uh/wm/manager_spec.rb | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/uh/wm/manager.rb b/lib/uh/wm/manager.rb index 6f8c232..3b30cca 100644 --- a/lib/uh/wm/manager.rb +++ b/lib/uh/wm/manager.rb @@ -1,7 +1,11 @@ module Uh module WM class Manager - INPUT_MASK = Events::SUBSTRUCTURE_REDIRECT_MASK + INPUT_MASK = Events::SUBSTRUCTURE_REDIRECT_MASK + ROOT_MASK = Events::PROPERTY_CHANGE_MASK | + Events::SUBSTRUCTURE_REDIRECT_MASK | + Events::SUBSTRUCTURE_NOTIFY_MASK | + Events::STRUCTURE_NOTIFY_MASK attr_reader :modifier, :display @@ -20,6 +24,7 @@ module Uh Display.on_error { |*args| handle_error *args } @display.sync false @events.emit :connected, args: @display + @display.root.mask = ROOT_MASK end def disconnect diff --git a/spec/uh/wm/manager_spec.rb b/spec/uh/wm/manager_spec.rb index 1ece020..46a5d58 100644 --- a/spec/uh/wm/manager_spec.rb +++ b/spec/uh/wm/manager_spec.rb @@ -33,6 +33,14 @@ module Uh manager.connect end + it 'updates the root window mask in order to manage windows' do + manager.connect + expect(display.root.mask).to eq Events::PROPERTY_CHANGE_MASK | + Events::SUBSTRUCTURE_REDIRECT_MASK | + Events::SUBSTRUCTURE_NOTIFY_MASK | + Events::STRUCTURE_NOTIFY_MASK + end + context 'when connection fails' do before { allow(display).to receive(:open) { fail } } From 4e65d46730e78fc5f4cbf1c2008a3bbfb87a9d3a Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Thu, 16 Apr 2015 09:33:39 +0000 Subject: [PATCH 2/7] Handle map_request events in the Manager --- lib/uh/wm/manager.rb | 2 ++ spec/uh/wm/manager_spec.rb | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/uh/wm/manager.rb b/lib/uh/wm/manager.rb index 3b30cca..fde8bb2 100644 --- a/lib/uh/wm/manager.rb +++ b/lib/uh/wm/manager.rb @@ -49,6 +49,8 @@ module Uh [event.key.to_sym, :shift] : event.key.to_sym @events.emit :key, *key_selector + when :map_request + @events.emit :manage, args: event.window end end diff --git a/spec/uh/wm/manager_spec.rb b/spec/uh/wm/manager_spec.rb index 46a5d58..0557b31 100644 --- a/spec/uh/wm/manager_spec.rb +++ b/spec/uh/wm/manager_spec.rb @@ -135,6 +135,17 @@ module Uh end end end + + context 'when map_request event is given' do + let(:event) { double 'event', type: :map_request, window: :window } + + it 'emits :manage event' do + events.on(:manage) { throw :manage_code } + expect { manager.handle event }.to throw_symbol :manage_code + end + + it 'emits :manage event with the client' + end end end end From 8bcb31ddc21af53137724fd0f5b32e4833cb59ae Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Thu, 16 Apr 2015 09:33:56 +0000 Subject: [PATCH 3/7] Forward :manage events to the Layout in Runner --- lib/uh/wm/runner.rb | 3 +++ spec/uh/wm/runner_spec.rb | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index 1afd7a0..181ecd4 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -84,6 +84,9 @@ module Uh @events.on :connected do |display| layout.register display end + @events.on :manage do |client| + layout << client + end end def register_keybinds_hooks diff --git a/spec/uh/wm/runner_spec.rb b/spec/uh/wm/runner_spec.rb index fe65c11..978d31f 100644 --- a/spec/uh/wm/runner_spec.rb +++ b/spec/uh/wm/runner_spec.rb @@ -1,5 +1,6 @@ SomeLayout = Class.new do - define_method(:register) { |*args| } + define_method(:register) { |*args| } + define_method(:<<) { |*args| } end module Uh @@ -85,6 +86,12 @@ module Uh runner.events.emit :connected, args: :display end + it 'registers layout hook for :manage event' do + runner.register_event_hooks + expect(env.layout).to receive(:<<).with :window + runner.events.emit :manage, args: :window + end + it 'registers key bindings event hooks' do env.keybinds[:f] = -> { } runner.register_event_hooks From fe47e27d98e1bd7ddb14583fbd8567bac6718f4f Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Wed, 15 Apr 2015 17:56:17 +0000 Subject: [PATCH 4/7] Prototype clients management with windows --- features/layout/manage.feature | 18 ++++++++++++++++++ features/steps/output_steps.rb | 4 ++++ features/steps/run_steps.rb | 4 ++++ features/steps/x_steps.rb | 4 ++++ lib/uh/wm/testing/acceptance_helpers.rb | 8 ++++++++ 5 files changed, 38 insertions(+) create mode 100644 features/layout/manage.feature diff --git a/features/layout/manage.feature b/features/layout/manage.feature new file mode 100644 index 0000000..cca14f8 --- /dev/null +++ b/features/layout/manage.feature @@ -0,0 +1,18 @@ +Feature: layout client management + + Scenario: sends the #<< message when telling the layout to manage a client + Given a file named layout.rb with: + """ + class Layout + def register *_; end + + def << client + # FIXME: need the Manager to manage state with clients, not windows + #puts client.wname + puts client.name + end + end + """ + And uhwm is running with options -v -r./layout -l Layout + When a window requests to be mapped + Then the output must contain the window name diff --git a/features/steps/output_steps.rb b/features/steps/output_steps.rb index e55109e..73cd67f 100644 --- a/features/steps/output_steps.rb +++ b/features/steps/output_steps.rb @@ -27,3 +27,7 @@ end Then /^the output must contain current display$/ do uhwm_wait_output ENV['DISPLAY'] end + +Then /^the output must contain the window name$/ do + uhwm_wait_output x_window_name +end diff --git a/features/steps/run_steps.rb b/features/steps/run_steps.rb index d72b716..790e57d 100644 --- a/features/steps/run_steps.rb +++ b/features/steps/run_steps.rb @@ -6,6 +6,10 @@ Given /^uhwm is running$/ do uhwm_run_wait_ready end +Given /^uhwm is running with options? (-.+)$/ do |options| + uhwm_run_wait_ready options +end + Given /^uhwm is running with this run control file:$/ do |rc| write_file '.uhwmrc.rb', rc uhwm_run_wait_ready diff --git a/features/steps/x_steps.rb b/features/steps/x_steps.rb index c2950e7..e7a1544 100644 --- a/features/steps/x_steps.rb +++ b/features/steps/x_steps.rb @@ -2,6 +2,10 @@ When /^I press the ([^ ]+) keys?$/ do |keys| x_key keys end +When /^a window requests to be mapped$/ do + x_window_map +end + Then /^it must connect to X display$/ do uhwm_wait_output 'Connected to' expect(x_socket_check uhwm_pid).to be true diff --git a/lib/uh/wm/testing/acceptance_helpers.rb b/lib/uh/wm/testing/acceptance_helpers.rb index d28f6fc..27a0bfb 100644 --- a/lib/uh/wm/testing/acceptance_helpers.rb +++ b/lib/uh/wm/testing/acceptance_helpers.rb @@ -66,6 +66,14 @@ module Uh `sockstat -u`.lines.grep /\s+ruby.+\s+#{pid}/ end.any? end + + def x_window_name + 'Event Tester' + end + + def x_window_map + spawn 'xev -event owner_grab_button' + end end end end From 6e90225c9d74bd576d25ad00f9d5ee9ef5896851 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Thu, 16 Apr 2015 11:57:48 +0000 Subject: [PATCH 5/7] Add basic Client class --- lib/uh/wm.rb | 1 + lib/uh/wm/client.rb | 24 ++++++++++++++++++++++++ spec/uh/wm/client_spec.rb | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 lib/uh/wm/client.rb create mode 100644 spec/uh/wm/client_spec.rb diff --git a/lib/uh/wm.rb b/lib/uh/wm.rb index 2bd157a..d259520 100644 --- a/lib/uh/wm.rb +++ b/lib/uh/wm.rb @@ -5,6 +5,7 @@ require 'uh' require 'uh/wm/actions_handler' require 'uh/wm/cli' +require 'uh/wm/client' require 'uh/wm/dispatcher' require 'uh/wm/env' require 'uh/wm/manager' diff --git a/lib/uh/wm/client.rb b/lib/uh/wm/client.rb new file mode 100644 index 0000000..546288d --- /dev/null +++ b/lib/uh/wm/client.rb @@ -0,0 +1,24 @@ +module Uh + module WM + class Client + attr_reader :window + + def initialize window, geo = nil + @window = window + @geo = geo + end + + def to_s + "<#{wname}> (#{wclass}) #{@geo} win: #{@window}" + end + + def wname + @wname ||= @window.name + end + + def wclass + @wclass ||= @window.wclass + end + end + end +end diff --git a/spec/uh/wm/client_spec.rb b/spec/uh/wm/client_spec.rb new file mode 100644 index 0000000..62cf8ef --- /dev/null +++ b/spec/uh/wm/client_spec.rb @@ -0,0 +1,39 @@ +module Uh + module WM + RSpec.describe Client do + let(:geo) { Geo.new(0, 0, 640, 480) } + let(:window) { double 'window', to_s: 'wid', name: 'wname', wclass: 'wclass' } + subject(:client) { described_class.new window, geo } + + describe '#to_s' do + it 'includes window name' do + expect(client.to_s).to include 'wname' + end + + it 'includes window class' do + expect(client.to_s).to include 'wclass' + end + + it 'includes geo' do + expect(client.to_s).to include geo.to_s + end + + it 'includes window id' do + expect(client.to_s).to include 'wid' + end + end + + describe '#wname' do + it 'returns the window name' do + expect(client.wname).to eq window.name + end + end + + describe '#wclass' do + it 'returns the window class' do + expect(client.wclass).to eq window.wclass + end + end + end + end +end From a0dcca07f97a6f022b85c2fbd8ec3d77fef31f9c Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Thu, 16 Apr 2015 11:59:13 +0000 Subject: [PATCH 6/7] Register clients in manager on map requests --- lib/uh/wm/manager.rb | 6 ++++-- spec/uh/wm/manager_spec.rb | 22 ++++++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/uh/wm/manager.rb b/lib/uh/wm/manager.rb index fde8bb2..ce163b6 100644 --- a/lib/uh/wm/manager.rb +++ b/lib/uh/wm/manager.rb @@ -7,12 +7,13 @@ module Uh Events::SUBSTRUCTURE_NOTIFY_MASK | Events::STRUCTURE_NOTIFY_MASK - attr_reader :modifier, :display + attr_reader :modifier, :display, :clients def initialize events, modifier, display = Display.new @events = events @modifier = modifier @display = display + @clients = [] end def connect @@ -50,7 +51,8 @@ module Uh event.key.to_sym @events.emit :key, *key_selector when :map_request - @events.emit :manage, args: event.window + @clients << client = Client.new(event.window) + @events.emit :manage, args: client end end diff --git a/spec/uh/wm/manager_spec.rb b/spec/uh/wm/manager_spec.rb index 0557b31..6fe3a61 100644 --- a/spec/uh/wm/manager_spec.rb +++ b/spec/uh/wm/manager_spec.rb @@ -11,6 +11,10 @@ module Uh expect(manager.display).to be_a Display end + it 'has no clients' do + expect(manager.clients).to be_empty + end + describe '#connect', :xvfb do it 'opens the display' do expect(manager.display).to receive(:open).and_call_original @@ -139,12 +143,22 @@ module Uh context 'when map_request event is given' do let(:event) { double 'event', type: :map_request, window: :window } - it 'emits :manage event' do - events.on(:manage) { throw :manage_code } - expect { manager.handle event }.to throw_symbol :manage_code + it 'registers a new client wrapping the event window' do + manager.handle event + expect(manager.clients[0]) + .to be_a(Client) + .and have_attributes(window: :window) end - it 'emits :manage event with the client' + it 'emits :manage event with the registered client' do + events.on :manage, &block + expect(block).to receive :call do |client| + expect(client) + .to be_a(Client) + .and have_attributes(window: :window) + end + manager.handle event + end end end end From c718ac4020221a411996f2de9c9430353a7388d3 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Thu, 16 Apr 2015 09:25:16 +0000 Subject: [PATCH 7/7] Manage clients with the Layout --- features/layout/manage.feature | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/features/layout/manage.feature b/features/layout/manage.feature index cca14f8..d485e57 100644 --- a/features/layout/manage.feature +++ b/features/layout/manage.feature @@ -7,9 +7,7 @@ Feature: layout client management def register *_; end def << client - # FIXME: need the Manager to manage state with clients, not windows - #puts client.wname - puts client.name + puts client end end """