uh 0.1.1

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.
@@ -0,0 +1,76 @@
1
+ module Uh
2
+ class WM
3
+ class Client
4
+ attr_reader :window
5
+ attr_accessor :geo
6
+
7
+ def initialize(window)
8
+ @window = window
9
+ @hide = true
10
+ end
11
+
12
+ def to_s
13
+ '<%s> (%s) window: %s, geo: %s' % [name, wclass, window, geo]
14
+ end
15
+
16
+ def name
17
+ @name ||= window.name
18
+ end
19
+
20
+ def wclass
21
+ @wclass ||= window.wclass
22
+ end
23
+
24
+ def hidden?
25
+ @hide
26
+ end
27
+
28
+ def update_window_properties
29
+ @name = @window.name
30
+ @wclass = @window.wclass
31
+ end
32
+
33
+ def configure
34
+ window.configure geo
35
+ self
36
+ end
37
+
38
+ def moveresize
39
+ window.moveresize geo
40
+ self
41
+ end
42
+
43
+ def show
44
+ window.map
45
+ @hide = false
46
+ self
47
+ end
48
+
49
+ def hide
50
+ window.unmap
51
+ @hide = true
52
+ self
53
+ end
54
+
55
+ def focus
56
+ window.raise
57
+ window.focus
58
+ self
59
+ end
60
+
61
+ def kill
62
+ if window.icccm_wm_protocols.include? :WM_DELETE_WINDOW
63
+ window.icccm_wm_delete
64
+ else
65
+ window.kill!
66
+ end
67
+ self
68
+ end
69
+
70
+ def kill!
71
+ window.kill
72
+ self
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,99 @@
1
+ module Uh
2
+ class WM
3
+ class Manager
4
+ DEFAULT_GEO = Geo.new(0, 0, 320, 240).freeze
5
+
6
+ extend Forwardable
7
+ def_delegator :@logger, :info, :log
8
+
9
+ def initialize(logger)
10
+ @logger = logger
11
+ @clients = []
12
+ @on_manage = []
13
+ end
14
+
15
+ def to_s
16
+ @clients.join $/
17
+ end
18
+
19
+ def on_configure(&block)
20
+ @on_configure = block
21
+ end
22
+
23
+ def on_manage(&block)
24
+ @on_manage << block
25
+ end
26
+
27
+ def on_unmanage(&block)
28
+ @on_unmanage = block
29
+ end
30
+
31
+ def on_change(&block)
32
+ @on_change = block
33
+ end
34
+
35
+ def configure(window)
36
+ if client = client_for(window)
37
+ log "#{self.class.name}#configure #{client} already managed"
38
+ client.configure
39
+ else
40
+ geo = @on_configure ? @on_configure.call(window) : DEFAULT_GEO
41
+ log "#{self.class.name}#configure window: #{window}, not managed"
42
+ log "#{window.class.name}#configure #{geo}"
43
+ window.configure_event geo
44
+ end
45
+ end
46
+
47
+ def map(window)
48
+ if window.override_redirect?
49
+ log "#{self.class.name}#map window.override_redirect, skipping"
50
+ return
51
+ end
52
+
53
+ if client = client_for(window)
54
+ log "#{self.class.name}#map #{client}, already managed"
55
+ else
56
+ manage Client.new(window)
57
+ end
58
+ end
59
+
60
+ def unmap(window)
61
+ remove_client_for window
62
+ end
63
+
64
+ def destroy(window)
65
+ remove_client_for window, destroy: true
66
+ end
67
+
68
+ def update_properties(window)
69
+ return unless client = client_for(window)
70
+ client.update_window_properties
71
+ @on_change.call client if @on_change
72
+ end
73
+
74
+
75
+ private
76
+
77
+ def client_for(window)
78
+ @clients.find { |e| e.window == window }
79
+ end
80
+
81
+ def remove_client_for(window, destroy: false)
82
+ return unless client = client_for(window)
83
+ unmanage client unless client.hidden? && !destroy
84
+ end
85
+
86
+ def manage(client)
87
+ log "#{self.class.name}#manage #{client}"
88
+ @clients << client
89
+ @on_manage.each { |e| e.call client }
90
+ end
91
+
92
+ def unmanage(client)
93
+ log "#{self.class.name}#unmanage #{client}"
94
+ @clients.reject! { |e| e == client }
95
+ @on_unmanage.call client if @on_unmanage
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,20 @@
1
+ module Uh
2
+ class WM
3
+ module Workers
4
+ class BaseWorker
5
+ def initialize(display, logger, **options)
6
+ @display = display
7
+ @logger = logger
8
+ configure **options
9
+ end
10
+
11
+ def configure(**options)
12
+ end
13
+
14
+ def setup
15
+ self
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module Uh
2
+ class WM
3
+ module Workers
4
+ class BlockingWorker < BaseWorker
5
+ def each_event
6
+ @display.each_event { |e| yield e }
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ module Uh
2
+ class WM
3
+ module Workers
4
+ class MultiplexingWorker < BaseWorker
5
+ def configure(timeout: 4)
6
+ @timeout = timeout
7
+ end
8
+
9
+ def setup
10
+ @display_io = IO.new(@display.fileno)
11
+ @display.flush
12
+ self
13
+ end
14
+
15
+ def each_event
16
+ loop do
17
+ @logger.debug "select [#{@display_io.fileno}], _, _, #{@timeout}"
18
+ rs, _ = IO.select [@display_io], [], [], @timeout
19
+ @logger.debug " => #{rs.inspect}"
20
+ next if rs.nil? || rs.empty?
21
+ yield @display.next_event while @display.pending?
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ #require 'minitest/parallel'
2
+ require 'minitest/spec'
3
+ require 'minitest/autorun'
4
+ require 'minitest/reporters'
5
+ require 'uh'
6
+
7
+ class Minitest::Test
8
+ # FIXME: SpecReporter output is incorrect with pretty diffs or parallel tests
9
+ #make_my_diffs_pretty!
10
+ #parallelize_me!
11
+ end
12
+
13
+ Minitest::Reporters.use!(Minitest::Reporters::SpecReporter.new)
@@ -0,0 +1,48 @@
1
+ require 'test_helper'
2
+
3
+ describe Uh::Geo do
4
+ subject { Uh::Geo.new(0, 0, 640, 480) }
5
+
6
+ describe '.new' do
7
+ it 'raises error when invalid width is given' do
8
+ assert_raises(Uh::ArgumentError) { Uh::Geo.new(0, 0, 0, 480) }
9
+ end
10
+
11
+ it 'raises error when invalid height is given' do
12
+ assert_raises(Uh::ArgumentError) { Uh::Geo.new(0, 0, 640, 0) }
13
+ end
14
+ end
15
+
16
+ describe '.format_xgeometry' do
17
+ it 'formats coordinates and dimensions as X geometry' do
18
+ assert_equal '640x480+0+0', Uh::Geo.format_xgeometry(0, 0, 640, 480)
19
+ end
20
+
21
+ it 'formats missing values as ?' do
22
+ assert_equal '?x?+?+?', Uh::Geo.format_xgeometry(*[nil] * 4)
23
+ end
24
+ end
25
+
26
+ describe '#to_s' do
27
+ it 'returns .format_xgeometry results' do
28
+ assert_equal Uh::Geo.format_xgeometry(*subject.values), subject.to_s
29
+ end
30
+ end
31
+
32
+ %w[width height].each do |dimension|
33
+ describe "##{dimension}=" do
34
+ it 'assigns given value' do
35
+ subject.send "#{dimension}=", 42
36
+ assert_equal 42, subject.send(dimension)
37
+ end
38
+
39
+ it 'raises error when 0 is given' do
40
+ assert_raises(Uh::ArgumentError) { subject.send "#{dimension}=", 0 }
41
+ end
42
+
43
+ it 'raises error when negative value is given' do
44
+ assert_raises(Uh::ArgumentError) { subject.send "#{dimension}=", -42 }
45
+ end
46
+ end
47
+ end
48
+ end
data/uh.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ require File.expand_path('../lib/uh/version', __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'uh'
5
+ s.version = Uh::VERSION.dup
6
+ s.summary = 'Xlib simplified toolkit'
7
+ s.description = s.name
8
+ s.homepage = 'https://rubygems.org/gems/uh'
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 /\Atest\//
15
+
16
+
17
+ s.add_development_dependency 'rake'
18
+ s.add_development_dependency 'rake-compiler'
19
+ s.add_development_dependency 'minitest', '~> 5.5'
20
+ s.add_development_dependency 'minitest-reporters', '~> 1.0'
21
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: uh
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Thibault Jouan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake-compiler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-reporters
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ description: uh
70
+ email: tj@a13.fr
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - ".gitignore"
76
+ - Gemfile
77
+ - Guardfile
78
+ - Rakefile
79
+ - TODO
80
+ - ext/uh/color.c
81
+ - ext/uh/display.c
82
+ - ext/uh/event.c
83
+ - ext/uh/extconf.rb
84
+ - ext/uh/font.c
85
+ - ext/uh/pixmap.c
86
+ - ext/uh/screen.c
87
+ - ext/uh/uh.c
88
+ - ext/uh/uh.h
89
+ - ext/uh/window.c
90
+ - lib/uh.rb
91
+ - lib/uh/display.rb
92
+ - lib/uh/drawable.rb
93
+ - lib/uh/events.rb
94
+ - lib/uh/font.rb
95
+ - lib/uh/geo.rb
96
+ - lib/uh/pixmap.rb
97
+ - lib/uh/screen.rb
98
+ - lib/uh/version.rb
99
+ - lib/uh/window.rb
100
+ - lib/uh/wm.rb
101
+ - lib/uh/wm/action_handler.rb
102
+ - lib/uh/wm/client.rb
103
+ - lib/uh/wm/manager.rb
104
+ - lib/uh/wm/workers/base_worker.rb
105
+ - lib/uh/wm/workers/blocking_worker.rb
106
+ - lib/uh/wm/workers/multiplexing_worker.rb
107
+ - test/test_helper.rb
108
+ - test/uh/test_geo.rb
109
+ - uh.gemspec
110
+ homepage: https://rubygems.org/gems/uh
111
+ licenses: []
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 2.4.5
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: Xlib simplified toolkit
133
+ test_files:
134
+ - test/test_helper.rb
135
+ - test/uh/test_geo.rb
136
+ has_rdoc: