uh-wm 0.0.1 → 0.0.2.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7fae76224987cc1f74c7a5f18c7b8d06eaee509b
4
- data.tar.gz: 8f1aab69ba46466bc7e98200eaec588a9c14ca2f
3
+ metadata.gz: 74533b8c4aea78f1fd611ad9a66f9003c7a70c78
4
+ data.tar.gz: 31ab453643a6c06b22fc7182344564976c622a5a
5
5
  SHA512:
6
- metadata.gz: a018d975a3061f73d6412dd06d4d980b1259a9ddc02ba9c95a4a08e86fb8a89d07fdc21931b1eb213e28923964cc000e7de5853e7a501e8a5b4f805787763398
7
- data.tar.gz: 344f2278196204a869cdd2943d88b389d257550c297e85bb451d3cf42008a762c114ce11953339b09a693b8d40ab324441fe9585424556dc94b9ad9235d3b5b6
6
+ metadata.gz: 32e9cdad0aecb15955af5dcebba0cdcb0424cc4cb7263e659dc96936c845cfba38de6007a972325b3e0e2b8e3ab16ebe6a611391f74c05009dcdd680d97f5f56
7
+ data.tar.gz: e1d903145b302e5a6ec00c00fd3e4c4bde795565a3ce5d969a8875704ff700f197c86afdf184b775a882bfa95e5aea32c4aa4be51777b6cb3841dbb0567e5566
@@ -0,0 +1,17 @@
1
+ module Uh
2
+ module WM
3
+ class ActionsHandler
4
+ def initialize env, events
5
+ @env, @events = env, events
6
+ end
7
+
8
+ def evaluate code
9
+ instance_eval &code
10
+ end
11
+
12
+ def quit
13
+ @events.emit :quit
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/uh/wm/cli.rb ADDED
@@ -0,0 +1,84 @@
1
+ module Uh
2
+ module WM
3
+ class CLI
4
+ ArgumentError = Class.new(ArgumentError)
5
+
6
+ USAGE = "Usage: #{File.basename $0} [options]".freeze
7
+
8
+ EX_USAGE = 64
9
+ EX_SOFTWARE = 70
10
+
11
+ class << self
12
+ def run arguments, stdout: $stdout, stderr: $stderr
13
+ cli = new arguments, stdout: stdout
14
+ cli.parse_arguments!
15
+ cli.run
16
+ rescue ArgumentError => e
17
+ stderr.puts e
18
+ exit EX_USAGE
19
+ rescue RuntimeError => e
20
+ stderr.puts "#{e.class.name}: #{e.message}"
21
+ stderr.puts e.backtrace.map { |e| ' %s' % e } if cli.env.debug?
22
+ exit EX_SOFTWARE
23
+ end
24
+ end
25
+
26
+ attr_reader :env
27
+
28
+ def initialize args, stdout: $stdout
29
+ @arguments = args
30
+ @env = Env.new(stdout.tap { |o| o.sync = true })
31
+ end
32
+
33
+ def parse_arguments!
34
+ option_parser.parse! @arguments
35
+ rescue OptionParser::InvalidOption => e
36
+ fail ArgumentError, option_parser
37
+ end
38
+
39
+ def run
40
+ Runner.run env
41
+ end
42
+
43
+
44
+ private
45
+
46
+ def option_parser
47
+ OptionParser.new do |opts|
48
+ opts.banner = USAGE
49
+ opts.separator ''
50
+ opts.separator 'options:'
51
+
52
+ opts.on '-h', '--help', 'print this message' do
53
+ @env.print opts
54
+ exit
55
+ end
56
+
57
+ opts.on '-v', '--version', 'enable verbose mode' do
58
+ @env.verbose = true
59
+ @env.log_logger_level
60
+ end
61
+
62
+ opts.on '-d', '--debug', 'enable debug mode' do
63
+ @env.debug = true
64
+ @env.log_logger_level
65
+ end
66
+
67
+ opts.on '-f', '--run-control PATH',
68
+ 'specify alternate run control file' do |e|
69
+ @env.rc_path = e
70
+ end
71
+
72
+ opts.on '-r', '--require PATH', 'require ruby feature' do |feature|
73
+ require feature
74
+ @env.log "Loaded `#{feature}' ruby feature"
75
+ end
76
+
77
+ opts.on '-l', '--layout LAYOUT', 'specify layout' do |layout|
78
+ @env.layout_class = self.class.const_get layout.to_sym
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,30 @@
1
+ module Uh
2
+ module WM
3
+ class Dispatcher
4
+ attr_reader :hooks
5
+
6
+ def initialize
7
+ @hooks = Hash.new { |h, k| h[k] = [] }
8
+ end
9
+
10
+ def [] *key
11
+ @hooks[translate_key key]
12
+ end
13
+
14
+ def on *key, &block
15
+ @hooks[translate_key key] << block
16
+ end
17
+
18
+ def emit *key, args: []
19
+ @hooks[translate_key key].each { |e| e.call *args }
20
+ end
21
+
22
+
23
+ private
24
+
25
+ def translate_key key
26
+ key.one? ? key[0] : key
27
+ end
28
+ end
29
+ end
30
+ end
data/lib/uh/wm/env.rb ADDED
@@ -0,0 +1,60 @@
1
+ module Uh
2
+ module WM
3
+ class Env
4
+ RC_PATH = '~/.uhwmrc.rb'.freeze
5
+
6
+ MODIFIER = :mod1
7
+ KEYBINDS = {
8
+ q: proc { quit }
9
+ }.freeze
10
+
11
+ LOGGER_LEVEL = Logger::WARN
12
+ LOGGER_LEVEL_VERBOSE = Logger::INFO
13
+ LOGGER_LEVEL_DEBUG = Logger::DEBUG
14
+ LOGGER_LEVEL_STRINGS = %w[DEBUG INFO WARN ERROR FATAL UNKNOWN]
15
+
16
+ extend Forwardable
17
+ def_delegator :logger, :info, :log
18
+ def_delegator :logger, :debug, :log_debug
19
+ def_delegator :@output, :print
20
+
21
+ attr_reader :output, :keybinds
22
+ attr_accessor :verbose, :debug, :rc_path, :layout_class, :modifier
23
+
24
+ def initialize output
25
+ @output = output
26
+ @rc_path = RC_PATH
27
+ @modifier = MODIFIER
28
+ @keybinds = KEYBINDS.dup
29
+ end
30
+
31
+ def verbose?
32
+ !!@verbose
33
+ end
34
+
35
+ def debug?
36
+ !!@debug
37
+ end
38
+
39
+ def layout
40
+ @layout ||= if layout_class
41
+ layout_class.new
42
+ else
43
+ require 'uh/layout'
44
+ ::Uh::Layout.new
45
+ end
46
+ end
47
+
48
+ def logger
49
+ @logger ||= Logger.new(@output).tap do |o|
50
+ o.level = debug? ? LOGGER_LEVEL_DEBUG :
51
+ verbose? ? LOGGER_LEVEL_VERBOSE : LOGGER_LEVEL
52
+ end
53
+ end
54
+
55
+ def log_logger_level
56
+ log "Logging at #{LOGGER_LEVEL_STRINGS[logger.level]} level"
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,53 @@
1
+ module Uh
2
+ module WM
3
+ class Manager
4
+ INPUT_MASK = Events::SUBSTRUCTURE_REDIRECT_MASK
5
+
6
+ attr_reader :modifier, :display
7
+
8
+ def initialize events, modifier, display = Display.new
9
+ @events = events
10
+ @modifier = modifier
11
+ @display = display
12
+ end
13
+
14
+ def connect
15
+ @events.emit :connecting, args: @display
16
+ @display.open
17
+ Display.on_error { fail OtherWMRunningError }
18
+ @display.listen_events INPUT_MASK
19
+ @display.sync false
20
+ Display.on_error { |*args| handle_error *args }
21
+ @display.sync false
22
+ @events.emit :connected, args: @display
23
+ end
24
+
25
+ def grab_key keysym, mod = nil
26
+ mod_mask = KEY_MODIFIERS[@modifier]
27
+ mod_mask |= KEY_MODIFIERS[mod] if mod
28
+ @display.grab_key keysym.to_s, mod_mask
29
+ end
30
+
31
+ def handle_pending_events
32
+ handle @display.next_event while @display.pending?
33
+ end
34
+
35
+ def handle event
36
+ case event.type
37
+ when :key_press
38
+ key_selector = event.modifier_mask & KEY_MODIFIERS[:shift] == 1 ?
39
+ [event.key.to_sym, :shift] :
40
+ event.key.to_sym
41
+ @events.emit :key, *key_selector
42
+ end
43
+ end
44
+
45
+
46
+ private
47
+
48
+ def handle_error *args
49
+ @dispatcher.emit :error, args: args
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,47 @@
1
+ module Uh
2
+ module WM
3
+ class RunControl
4
+ KEYSYM_TRANSLATIONS = {
5
+ backspace: :BackSpace,
6
+ enter: :Return,
7
+ return: :Return,
8
+ tab: :Tab
9
+ }.freeze
10
+
11
+ class << self
12
+ def evaluate env
13
+ rc_path = File.expand_path(env.rc_path)
14
+ rc = new env
15
+ rc.evaluate File.read(rc_path), rc_path if File.exist?(rc_path)
16
+ end
17
+ end
18
+
19
+ def initialize env
20
+ @env = env
21
+ end
22
+
23
+ def evaluate code, path
24
+ instance_eval code, path
25
+ end
26
+
27
+ def modifier mod
28
+ @env.modifier = mod
29
+ end
30
+
31
+ def key keysym, &block
32
+ @env.keybinds[translate_keysym keysym] = block
33
+ end
34
+
35
+
36
+ private
37
+
38
+ def translate_keysym keysym
39
+ translate_key = keysym.to_s.downcase.to_sym
40
+ translated_keysym = KEYSYM_TRANSLATIONS.key?(translate_key) ?
41
+ KEYSYM_TRANSLATIONS[translate_key] :
42
+ translate_key
43
+ keysym =~ /[A-Z]/ ? [translated_keysym, :shift] : translated_keysym
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,92 @@
1
+ module Uh
2
+ module WM
3
+ class Runner
4
+ class << self
5
+ def run env, **options
6
+ runner = new env, **options
7
+ runner.evaluate_run_control
8
+ runner.register_event_hooks
9
+ runner.connect_manager
10
+ runner.run_until { runner.stopped? }
11
+ end
12
+ end
13
+
14
+ extend Forwardable
15
+ def_delegator :@env, :layout
16
+
17
+ attr_reader :env, :events, :actions
18
+
19
+ def initialize env, manager: nil, stopped: false
20
+ @env = env
21
+ @events = Dispatcher.new
22
+ @manager = manager
23
+ @actions = ActionsHandler.new(@env, @events)
24
+ @stopped = stopped
25
+ end
26
+
27
+ def stopped?
28
+ !!@stopped
29
+ end
30
+
31
+ def stop!
32
+ @stopped = true
33
+ end
34
+
35
+ def manager
36
+ @manager ||= Manager.new(@events, @env.modifier)
37
+ end
38
+
39
+ def evaluate_run_control
40
+ RunControl.evaluate(env)
41
+ end
42
+
43
+ def register_event_hooks
44
+ register_runner_hooks
45
+ register_manager_hooks
46
+ register_layout_event_hooks
47
+ register_key_bindings_hooks
48
+ end
49
+
50
+ def connect_manager
51
+ manager.connect
52
+ @env.keybinds.each do |keysym, _|
53
+ manager.grab_key *keysym
54
+ end
55
+ end
56
+
57
+ def run_until &block
58
+ manager.handle_pending_events until block.call
59
+ end
60
+
61
+
62
+ private
63
+
64
+ def register_runner_hooks
65
+ @events.on(:quit) { stop! }
66
+ end
67
+
68
+ def register_manager_hooks
69
+ @events.on(:connecting) do |display|
70
+ @env.log_debug "Connecting to X server on `#{display}'"
71
+ end
72
+ @events.on(:connected) do |display|
73
+ @env.log "Connected to X server on `#{display}'"
74
+ end
75
+ end
76
+
77
+ def register_layout_event_hooks
78
+ @events.on(:connected) do |display|
79
+ layout.register display
80
+ end
81
+ end
82
+
83
+ def register_key_bindings_hooks
84
+ @env.keybinds.each do |keysym, code|
85
+ @events.on :key, *keysym do
86
+ @actions.evaluate code
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,72 @@
1
+ module Uh
2
+ module WM
3
+ module Testing
4
+ module AcceptanceHelpers
5
+ def uhwm_run options = '-v'
6
+ command = %w[uhwm]
7
+ command << options if options
8
+ @interactive = @process = run command.join ' '
9
+ end
10
+
11
+ def uhwm_ensure_stop
12
+ @process and @process.terminate
13
+ end
14
+
15
+ def uhwm_pid
16
+ @process.pid
17
+ end
18
+
19
+ def uhwm_output
20
+ @process.stdout
21
+ end
22
+
23
+ def uhwm_wait_output message, timeout: 1
24
+ Timeout.timeout(timeout) do
25
+ loop do
26
+ break if case message
27
+ when Regexp then @process.stdout + @process.stderr =~ message
28
+ when String then assert_partial_output_interactive message
29
+ end
30
+ sleep 0.1
31
+ end
32
+ end
33
+ rescue Timeout::Error
34
+ output = (@process.stdout + @process.stderr).lines
35
+ .map { |e| " #{e}" }
36
+ .join
37
+ fail [
38
+ "expected `#{message}' not seen after #{timeout} seconds in:",
39
+ " ```\n#{output} ```"
40
+ ].join "\n"
41
+ end
42
+
43
+ def uhwm_run_wait_ready
44
+ uhwm_run
45
+ uhwm_wait_output 'Connected to'
46
+ end
47
+
48
+ def with_other_wm
49
+ @other_wm = ChildProcess.build('twm').tap { |o| o.start }
50
+ @other_wm.stop
51
+ end
52
+
53
+ def other_wm
54
+ @other_wm
55
+ end
56
+
57
+ def x_key key
58
+ fail "cannot simulate X key `#{key}'" unless system "xdotool key #{key}"
59
+ end
60
+
61
+ def x_socket_check pid
62
+ case RbConfig::CONFIG['host_os']
63
+ when /linux/
64
+ `netstat -xp 2> /dev/null`.lines.grep /\s+#{pid}\/ruby/
65
+ else
66
+ `sockstat -u`.lines.grep /\s+ruby.+\s+#{pid}/
67
+ end.any?
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
data/lib/uh/wm/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Uh
2
2
  module WM
3
- VERSION = '0.0.1'
3
+ VERSION = '0.0.2.pre'
4
4
  end
5
5
  end
data/lib/uh/wm.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'forwardable'
2
+ require 'logger'
3
+ require 'optparse'
4
+ require 'uh'
5
+
6
+ require 'uh/wm/actions_handler'
7
+ require 'uh/wm/cli'
8
+ require 'uh/wm/dispatcher'
9
+ require 'uh/wm/env'
10
+ require 'uh/wm/manager'
11
+ require 'uh/wm/run_control'
12
+ require 'uh/wm/runner'
13
+
14
+ module Uh
15
+ module WM
16
+ Error = Class.new(StandardError)
17
+ RuntimeError = Class.new(RuntimeError)
18
+ ArgumentError = Class.new(Error)
19
+
20
+ class OtherWMRunningError < RuntimeError
21
+ def message
22
+ 'another window manager is already running'
23
+ end
24
+ end
25
+ end
26
+ end
metadata CHANGED
@@ -1,25 +1,129 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uh-wm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thibault Jouan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-06 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2015-04-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: uh
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.0.pre
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.0.pre
27
+ - !ruby/object:Gem::Dependency
28
+ name: uh-layout
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.0.pre
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.0.pre
41
+ - !ruby/object:Gem::Dependency
42
+ name: aruba
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: cucumber
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: headless
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.4'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.2'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.2'
13
111
  description: uh-wm
14
112
  email: tj@a13.fr
15
113
  executables: []
16
114
  extensions: []
17
115
  extra_rdoc_files: []
18
116
  files:
19
- - ".gitignore"
20
- - LICENSE
117
+ - lib/uh/wm.rb
118
+ - lib/uh/wm/actions_handler.rb
119
+ - lib/uh/wm/cli.rb
120
+ - lib/uh/wm/dispatcher.rb
121
+ - lib/uh/wm/env.rb
122
+ - lib/uh/wm/manager.rb
123
+ - lib/uh/wm/run_control.rb
124
+ - lib/uh/wm/runner.rb
125
+ - lib/uh/wm/testing/acceptance_helpers.rb
21
126
  - lib/uh/wm/version.rb
22
- - uh-wm.gemspec
23
127
  homepage: https://rubygems.org/gems/uh-wm
24
128
  licenses: []
25
129
  metadata: {}
@@ -34,9 +138,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
34
138
  version: '0'
35
139
  required_rubygems_version: !ruby/object:Gem::Requirement
36
140
  requirements:
37
- - - ">="
141
+ - - ">"
38
142
  - !ruby/object:Gem::Version
39
- version: '0'
143
+ version: 1.3.1
40
144
  requirements: []
41
145
  rubyforge_project:
42
146
  rubygems_version: 2.4.5
data/.gitignore DELETED
File without changes
data/LICENSE DELETED
@@ -1,30 +0,0 @@
1
- Copyright 2015 Thibault Jouan. All rights reserved.
2
-
3
- Redistribution and use in source and binary forms, with or without
4
- modification, are permitted provided that the following conditions are
5
- met:
6
-
7
- * Redistributions of source code must retain the above copyright
8
- notice, this list of conditions and the following disclaimer.
9
-
10
- * Redistributions in binary form must reproduce the above copyright
11
- notice, this list of conditions and the following disclaimer in
12
- the documentation and/or other materials provided with the
13
- distribution.
14
-
15
- * Neither the name of the software nor the names of its contributors
16
- may be used to endorse or promote products derived from this
17
- software without specific prior written permission.
18
-
19
-
20
- THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS "AS IS" AND
21
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23
- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
24
- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27
- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29
- OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30
- IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/uh-wm.gemspec DELETED
@@ -1,16 +0,0 @@
1
- require File.expand_path('../lib/uh/wm/version', __FILE__)
2
-
3
- Gem::Specification.new do |s|
4
- s.name = 'uh-wm'
5
- s.version = Uh::WM::VERSION.dup
6
- s.summary = 'uh window manager'
7
- s.description = s.name
8
- s.homepage = 'https://rubygems.org/gems/uh-wm'
9
-
10
- s.authors = 'Thibault Jouan'
11
- s.email = 'tj@a13.fr'
12
-
13
- s.files = `git ls-files`.split $/
14
- s.test_files = s.files.grep /\A(spec|features)\//
15
- s.executables = s.files.grep(/\Abin\//) { |f| File.basename(f) }
16
- end