diff --git a/features/layout/protocol.feature b/features/layout/protocol.feature index 5df4e09..14d1296 100644 --- a/features/layout/protocol.feature +++ b/features/layout/protocol.feature @@ -16,6 +16,10 @@ Feature: layout protocol def remove client puts "testing_#remove_#{client.name}" end + + def update client + puts "testing_#update_#{client.name}" + end end """ @@ -33,3 +37,9 @@ Feature: layout protocol And a window is mapped When the window is unmapped Then the output must contain "testing_#remove_XClient/default" + + Scenario: tells the layout to update a changed client with #update message + Given uhwm is running with options -v -r./layout -l Layout + And a window is mapped + When the window name changes to "testing_new_name" + Then the output must contain "testing_#update_testing_new_name" diff --git a/features/manager/change.feature b/features/manager/change.feature new file mode 100644 index 0000000..0d44d10 --- /dev/null +++ b/features/manager/change.feature @@ -0,0 +1,7 @@ +Feature: clients window properties updating + + Scenario: logs when the window properties of a client change + Given uhwm is running + And a window is mapped + When the window name changes to "testing_new_name" + Then the output must match /updat.+testing_new_name/i diff --git a/features/steps/x_steps.rb b/features/steps/x_steps.rb index 13fe3a6..fcdc8a8 100644 --- a/features/steps/x_steps.rb +++ b/features/steps/x_steps.rb @@ -28,6 +28,10 @@ When /^the window is destroyed$/ do x_client.destroy.sync end +When /^the window name changes to "([^"]+)"$/ do |name| + x_client.window_name = name +end + Then /^it must connect to X display$/ do uhwm_wait_ready expect(x_socket_check uhwm.pid).to be true diff --git a/lib/uh/wm/client.rb b/lib/uh/wm/client.rb index 1eea9b9..464d637 100644 --- a/lib/uh/wm/client.rb +++ b/lib/uh/wm/client.rb @@ -31,6 +31,11 @@ module Uh @wclass ||= @window.wclass end + def update_window_properties + @wname = @window.name + @wclass = @window.wclass + end + def configure @window.configure @geo self diff --git a/lib/uh/wm/manager.rb b/lib/uh/wm/manager.rb index ab830cd..a3fc312 100644 --- a/lib/uh/wm/manager.rb +++ b/lib/uh/wm/manager.rb @@ -59,6 +59,7 @@ module Uh return if window.override_redirect? || client_for(window) @clients << client = Client.new(window) @events.emit :manage, args: client + @display.listen_events window, Events::PROPERTY_CHANGE_MASK end def unmap window @@ -77,6 +78,12 @@ module Uh @events.emit :unmanage, args: client end + def update_properties window + return unless client = client_for(window) + client.update_window_properties + @events.emit :change, args: client + end + def handle_next_event handle @display.next_event end @@ -117,6 +124,10 @@ module Uh map event.window end + def handle_property_notify event + update_properties event.window + end + def handle_unmap_notify event unmap event.window end diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index 6e6aab3..beb6ffc 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -119,6 +119,10 @@ module Uh log "Unmanaging client #{client}" layout.remove client end + @events.on :change do |client| + log "Updating client #{client}" + layout.update client + end end def register_keybinds_hooks diff --git a/lib/uh/wm/testing/acceptance_helpers.rb b/lib/uh/wm/testing/acceptance_helpers.rb index ec7d153..7558ca0 100644 --- a/lib/uh/wm/testing/acceptance_helpers.rb +++ b/lib/uh/wm/testing/acceptance_helpers.rb @@ -159,6 +159,11 @@ module Uh @name end + def window_name= name + @name = @window.name = name + window.name + end + def map times: 1 times.times { window.map } window.map diff --git a/spec/uh/wm/client_spec.rb b/spec/uh/wm/client_spec.rb index d246842..d074646 100644 --- a/spec/uh/wm/client_spec.rb +++ b/spec/uh/wm/client_spec.rb @@ -47,6 +47,24 @@ module Uh end end + describe '#update_window_properties' do + it 'updates the cached window name' do + client.name + allow(window).to receive(:name) { 'new name' } + expect { client.update_window_properties } + .to change { client.name } + .from('wname').to 'new name' + end + + it 'updates the cached window class' do + client.wclass + allow(window).to receive(:wclass) { 'new class' } + expect { client.update_window_properties } + .to change { client.wclass } + .from('wclass').to 'new class' + end + end + describe '#configure' do it 'configures the window with client geo' do expect(window).to receive(:configure).with geo diff --git a/spec/uh/wm/manager_spec.rb b/spec/uh/wm/manager_spec.rb index 2b4db09..036c4f6 100644 --- a/spec/uh/wm/manager_spec.rb +++ b/spec/uh/wm/manager_spec.rb @@ -133,6 +133,8 @@ module Uh end describe '#map' do + let(:display) { instance_spy Display } + it 'registers a new client wrapping the given window' do manager.map window expect(manager.clients[0]) @@ -159,6 +161,13 @@ module Uh end manager.map window end + + it 'listens for property notify events on given window' do + expect(display) + .to receive(:listen_events) + .with window, Events::PROPERTY_CHANGE_MASK + manager.map window + end end describe '#unmap' do @@ -239,6 +248,30 @@ module Uh end end + describe '#update_properties' do + context 'with known window' do + before { manager.clients << client } + + it 'tells the client to update its window properties' do + expect(client).to receive :update_window_properties + manager.update_properties window + end + + it 'emits :change event with the client' do + events.on :change, &block + expect(block).to receive(:call).with client + manager.update_properties window + end + end + + context 'with unknown window' do + it 'does not emit any event' do + expect(events).not_to receive :emit + manager.update_properties window + end + end + end + describe '#handle_next_event' do it 'handles the next available event on display' do event = double 'event' @@ -338,6 +371,15 @@ module Uh manager.handle event end end + + context 'when property_notify event is given' do + let(:event) { mock_event :property_notify, window: :window } + + it 'updates event window properties' do + expect(manager).to receive(:update_properties).with :window + manager.handle event + end + end end end end diff --git a/spec/uh/wm/runner_spec.rb b/spec/uh/wm/runner_spec.rb index fd6eff4..3c974c0 100644 --- a/spec/uh/wm/runner_spec.rb +++ b/spec/uh/wm/runner_spec.rb @@ -5,6 +5,7 @@ SomeLayout = Class.new do define_method(:suggest_geo) { build_geo 0, 0, 42, 42 } define_method(:<<) { |*_| } define_method(:remove) { |*_| } + define_method(:update) { |*_| } end module Uh @@ -98,6 +99,12 @@ module Uh expect(env.layout).to receive(:remove).with :client runner.events.emit :unmanage, args: :client end + + it 'registers for :change event' do + runner.register_event_hooks + expect(env.layout).to receive(:update).with :client + runner.events.emit :change, args: :client + end end context 'keys hooks' do diff --git a/uh-wm.gemspec b/uh-wm.gemspec index 19f795b..8fcfb9b 100644 --- a/uh-wm.gemspec +++ b/uh-wm.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |s| s.executables = s.files.grep(/\Abin\//) { |f| File.basename(f) } s.add_dependency 'uh', '2.0.0.pre2' - s.add_dependency 'uh-layout', '0.2.0.pre' + s.add_dependency 'uh-layout', '~> 0.2.2' s.add_development_dependency 'aruba', '~> 0.6' s.add_development_dependency 'cucumber', '~> 2.0'