Merge branch 'workers'
This commit is contained in:
commit
c21600f500
@ -30,6 +30,7 @@ options:
|
||||
-f, --run-control PATH specify alternate run control file
|
||||
-r, --require PATH require ruby feature
|
||||
-l, --layout LAYOUT specify layout
|
||||
-w, --worker WORKER specify worker
|
||||
```
|
||||
|
||||
|
||||
|
9
features/cli/worker.feature
Normal file
9
features/cli/worker.feature
Normal file
@ -0,0 +1,9 @@
|
||||
Feature: worker CLI option
|
||||
|
||||
Scenario: uses the blocking worker when `block' is given
|
||||
When I run uhwm with option -v -w block
|
||||
Then the output must match /work.+event.+block/i
|
||||
|
||||
Scenario: uses the multiplexing worker when `mux' is given
|
||||
When I run uhwm with option -v -w mux
|
||||
Then the output must match /work.+event.+mux/i
|
9
features/run_control/worker.feature
Normal file
9
features/run_control/worker.feature
Normal file
@ -0,0 +1,9 @@
|
||||
Feature: `worker' run control keyword
|
||||
|
||||
Scenario: configures the modifier key
|
||||
Given a run control file with:
|
||||
"""
|
||||
worker :mux
|
||||
"""
|
||||
And I start uhwm
|
||||
Then the output must match /work.+event.+mux/i
|
@ -9,6 +9,7 @@ options:
|
||||
-f, --run-control PATH specify alternate run control file
|
||||
-r, --require PATH require ruby feature
|
||||
-l, --layout LAYOUT specify layout
|
||||
-w, --worker WORKER specify worker
|
||||
eoh
|
||||
end
|
||||
|
||||
|
@ -12,6 +12,10 @@ require 'uh/wm/logger_formatter'
|
||||
require 'uh/wm/manager'
|
||||
require 'uh/wm/run_control'
|
||||
require 'uh/wm/runner'
|
||||
require 'uh/wm/workers'
|
||||
require 'uh/wm/workers/base'
|
||||
require 'uh/wm/workers/blocking'
|
||||
require 'uh/wm/workers/mux'
|
||||
|
||||
module Uh
|
||||
module WM
|
||||
|
@ -77,6 +77,11 @@ module Uh
|
||||
opts.on '-l', '--layout LAYOUT', 'specify layout' do |layout|
|
||||
@env.layout_class = self.class.const_get layout.to_sym
|
||||
end
|
||||
|
||||
opts.on '-w', Workers.types, '--worker WORKER',
|
||||
'specify worker' do |worker|
|
||||
@env.worker = worker.to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3,10 +3,11 @@ module Uh
|
||||
class Env
|
||||
RC_PATH = '~/.uhwmrc.rb'.freeze
|
||||
|
||||
MODIFIER = :mod1
|
||||
KEYBINDS = {
|
||||
MODIFIER = :mod1
|
||||
KEYBINDS = {
|
||||
q: proc { quit }
|
||||
}.freeze
|
||||
WORKER = :block
|
||||
|
||||
LOGGER_LEVEL = Logger::WARN
|
||||
LOGGER_LEVEL_VERBOSE = Logger::INFO
|
||||
@ -20,13 +21,15 @@ module Uh
|
||||
def_delegator :@output, :print
|
||||
|
||||
attr_reader :output, :keybinds
|
||||
attr_accessor :verbose, :debug, :rc_path, :layout_class, :modifier
|
||||
attr_accessor :verbose, :debug, :rc_path, :layout_class, :modifier,
|
||||
:worker
|
||||
|
||||
def initialize output
|
||||
@output = output
|
||||
@rc_path = RC_PATH
|
||||
@modifier = MODIFIER
|
||||
@keybinds = KEYBINDS.dup
|
||||
@worker = :block
|
||||
end
|
||||
|
||||
def verbose?
|
||||
|
@ -16,6 +16,10 @@ module Uh
|
||||
@clients = []
|
||||
end
|
||||
|
||||
def to_io
|
||||
IO.new(@display.fileno)
|
||||
end
|
||||
|
||||
def connect
|
||||
@events.emit :connecting, args: @display
|
||||
@display.open
|
||||
@ -31,12 +35,20 @@ module Uh
|
||||
@events.emit :disconnected
|
||||
end
|
||||
|
||||
def flush
|
||||
@display.flush
|
||||
end
|
||||
|
||||
def grab_key keysym, mod = nil
|
||||
mod_mask = KEY_MODIFIERS[@modifier]
|
||||
mod_mask |= KEY_MODIFIERS[mod] if mod
|
||||
@display.grab_key keysym.to_s, mod_mask
|
||||
end
|
||||
|
||||
def handle_next_event
|
||||
handle @display.next_event
|
||||
end
|
||||
|
||||
def handle_pending_events
|
||||
handle @display.next_event while @display.pending?
|
||||
end
|
||||
|
@ -32,6 +32,10 @@ module Uh
|
||||
@env.keybinds[translate_keysym keysym] = block
|
||||
end
|
||||
|
||||
def worker type, **options
|
||||
@env.worker = [type, options]
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
@ -54,8 +54,28 @@ module Uh
|
||||
end
|
||||
end
|
||||
|
||||
def worker
|
||||
@worker ||= Workers.build(*(@env.worker)).tap do |w|
|
||||
w.on_read do
|
||||
@env.log_debug 'Processing pending events'
|
||||
@manager.handle_pending_events
|
||||
end
|
||||
w.on_read_next do
|
||||
@env.log_debug 'Processing next event'
|
||||
@manager.handle_next_event
|
||||
end
|
||||
w.on_timeout do |*args|
|
||||
@env.log_debug "Worker timeout: #{args.inspect}"
|
||||
@env.log_debug 'Flushing X output buffer'
|
||||
@manager.flush
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run_until &block
|
||||
manager.handle_pending_events until block.call
|
||||
worker.watch @manager
|
||||
@env.log "Working events with `#{worker.class}'"
|
||||
worker.work_events until block.call
|
||||
end
|
||||
|
||||
def terminate
|
||||
|
@ -11,7 +11,10 @@ module Uh
|
||||
end
|
||||
|
||||
def uhwm_ensure_stop
|
||||
@process and @process.terminate
|
||||
if @process
|
||||
x_key 'alt+q'
|
||||
@process.terminate
|
||||
end
|
||||
end
|
||||
|
||||
def uhwm_pid
|
||||
|
21
lib/uh/wm/workers.rb
Normal file
21
lib/uh/wm/workers.rb
Normal file
@ -0,0 +1,21 @@
|
||||
module Uh
|
||||
module WM
|
||||
module Workers
|
||||
FACTORIES = {
|
||||
block: ->(options) { Blocking.new(options) },
|
||||
mux: ->(options) { Mux.new(options) }
|
||||
}.freeze
|
||||
|
||||
class << self
|
||||
def types
|
||||
FACTORIES.keys
|
||||
end
|
||||
|
||||
def build type, **options
|
||||
(FACTORIES[type] or fail ArgumentError, "unknown worker: `#{type}'")
|
||||
.call options
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
31
lib/uh/wm/workers/base.rb
Normal file
31
lib/uh/wm/workers/base.rb
Normal file
@ -0,0 +1,31 @@
|
||||
module Uh
|
||||
module WM
|
||||
module Workers
|
||||
class Base
|
||||
def initialize **options
|
||||
@ios = []
|
||||
end
|
||||
|
||||
def watch io
|
||||
@ios << io
|
||||
end
|
||||
|
||||
def before_wait &block
|
||||
if block_given? then @before_wait = block else @before_wait end
|
||||
end
|
||||
|
||||
def on_timeout &block
|
||||
if block_given? then @on_timeout = block else @on_timeout end
|
||||
end
|
||||
|
||||
def on_read &block
|
||||
if block_given? then @on_read = block else @on_read end
|
||||
end
|
||||
|
||||
def on_read_next &block
|
||||
if block_given? then @on_read_next = block else @on_read_next end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
15
lib/uh/wm/workers/blocking.rb
Normal file
15
lib/uh/wm/workers/blocking.rb
Normal file
@ -0,0 +1,15 @@
|
||||
module Uh
|
||||
module WM
|
||||
module Workers
|
||||
class Blocking < Base
|
||||
def work_events
|
||||
#until yield
|
||||
# @on_events_read_bang.call
|
||||
#end
|
||||
#@on_events_read_bang.call until yield
|
||||
@on_read_next.call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
18
lib/uh/wm/workers/mux.rb
Normal file
18
lib/uh/wm/workers/mux.rb
Normal file
@ -0,0 +1,18 @@
|
||||
module Uh
|
||||
module WM
|
||||
module Workers
|
||||
class Mux < Base
|
||||
def initialize timeout: 1
|
||||
super
|
||||
@timeout = timeout
|
||||
end
|
||||
|
||||
def work_events
|
||||
@before_wait.call if @before_wait
|
||||
if res = select(@ios, [], [], @timeout) then @on_read.call res
|
||||
else @on_timeout.call if @on_timeout end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -176,6 +176,15 @@ module Uh
|
||||
end
|
||||
end
|
||||
|
||||
context 'with worker option' do
|
||||
let(:arguments) { %w[-w mux] }
|
||||
|
||||
it 'assigns the worker type in the env' do
|
||||
cli.parse_arguments!
|
||||
expect(cli.env.worker).to eq :mux
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid option' do
|
||||
let(:arguments) { %w[--unknown-option] }
|
||||
|
||||
|
@ -29,6 +29,10 @@ module Uh
|
||||
expect(env.keybinds.keys).to eq %i[q]
|
||||
end
|
||||
|
||||
it 'has the blocking worker by default' do
|
||||
expect(env.worker).to eq :block
|
||||
end
|
||||
|
||||
describe '#verbose?' do
|
||||
context 'when verbose mode is disabled' do
|
||||
before { env.verbose = false }
|
||||
|
@ -15,6 +15,18 @@ module Uh
|
||||
expect(manager.clients).to be_empty
|
||||
end
|
||||
|
||||
describe '#to_io', :xvfb do
|
||||
context 'when connected' do
|
||||
before { manager.connect }
|
||||
|
||||
it 'returns an IO object wrapping the display file descriptor' do
|
||||
expect(manager.to_io)
|
||||
.to be_an(IO)
|
||||
.and have_attributes(fileno: display.fileno)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#connect', :xvfb do
|
||||
it 'opens the display' do
|
||||
expect(manager.display).to receive(:open).and_call_original
|
||||
@ -70,6 +82,13 @@ module Uh
|
||||
end
|
||||
end
|
||||
|
||||
describe '#flush' do
|
||||
it 'flushes the display' do
|
||||
expect(display).to receive :flush
|
||||
manager.flush
|
||||
end
|
||||
end
|
||||
|
||||
describe '#grab_key' do
|
||||
it 'grabs given key on the display' do
|
||||
expect(manager.display)
|
||||
@ -87,6 +106,15 @@ module Uh
|
||||
end
|
||||
end
|
||||
|
||||
describe '#handle_next_event' do
|
||||
it 'handles the next available event on display' do
|
||||
event = double 'event'
|
||||
allow(display).to receive(:next_event) { event }
|
||||
expect(manager).to receive(:handle).with(event).once
|
||||
manager.handle_next_event
|
||||
end
|
||||
end
|
||||
|
||||
describe '#handle_pending_events' do
|
||||
let(:event) { double 'event' }
|
||||
|
||||
|
@ -80,6 +80,18 @@ module Uh
|
||||
expect(env.keybinds.keys).to include %i[f shift]
|
||||
end
|
||||
end
|
||||
|
||||
describe '#worker' do
|
||||
it 'sets the worker type in the env' do
|
||||
rc.worker :some_worker
|
||||
expect(env.worker[0]).to eq :some_worker
|
||||
end
|
||||
|
||||
it 'sets the worker options in the env' do
|
||||
rc.worker :some_worker, some: :option
|
||||
expect(env.worker[1]).to eq({ some: :option })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -122,11 +122,37 @@ module Uh
|
||||
end
|
||||
end
|
||||
|
||||
describe '#worker' do
|
||||
it 'returns a worker' do
|
||||
expect(runner.worker).to respond_to :work_events
|
||||
end
|
||||
|
||||
it 'setups the read callback to tell manager to handle pending events' do
|
||||
expect(runner.manager).to receive :handle_pending_events
|
||||
runner.worker.on_read.call
|
||||
end
|
||||
|
||||
it 'setups the read_next callback to tell manager to handle next event' do
|
||||
expect(runner.manager).to receive :handle_next_event
|
||||
runner.worker.on_read_next.call
|
||||
end
|
||||
|
||||
it 'setups the timeout callback to tell manager to flush the output' do
|
||||
expect(runner.manager).to receive :flush
|
||||
runner.worker.on_timeout.call
|
||||
end
|
||||
end
|
||||
|
||||
describe '#run_until' do
|
||||
it 'tells the manager to handle events until given block is true' do
|
||||
it 'tells the worker to watch the manager' do
|
||||
expect(runner.worker).to receive(:watch).with runner.manager
|
||||
runner.run_until { true }
|
||||
end
|
||||
|
||||
it 'tells the worker to work 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
|
||||
expect(runner.worker).to receive(:work_events).exactly(3).times
|
||||
runner.run_until &block
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user