uh-wm 0.0.1 → 0.0.2.pre

Sign up to get free protection for your applications and to get access to all the features.
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