vigilem-x11 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/vigilem/x11.rb +69 -0
- data/lib/vigilem/x11/constants.rb +5 -0
- data/lib/vigilem/x11/display.rb +53 -0
- data/lib/vigilem/x11/event_queue.rb +152 -0
- data/lib/vigilem/x11/input_system_handler.rb +75 -0
- data/lib/vigilem/x11/system.rb +37 -0
- data/lib/vigilem/x11/terminal_window_utils.rb +33 -0
- data/lib/vigilem/x11/version.rb +5 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/vigilem/x11/display_spec.rb +72 -0
- data/spec/vigilem/x11/event_queue_spec.rb +152 -0
- data/spec/vigilem/x11/input_system_handler_spec.rb +74 -0
- data/spec/vigilem/x11/system_spec.rb +49 -0
- data/spec/vigilem/x11/terminal_window_utils_spec.rb +29 -0
- data/spec/vigilem/x11_spec.rb +44 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 162ca2f1112eea4acea8fefef0cc1e0bb228d114
|
4
|
+
data.tar.gz: f6082f66f84e01897b736694b311a1e9e47b2e81
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 37d103aab9dafff1e6e9340249521504047fc37895ac5393ae5f46cc859a35f5f45a7b9f24fc3396591dcb18e935363945a6897cf155c851732f9e2d82e1e6a5
|
7
|
+
data.tar.gz: 6e1a02234056c12c0ed2e521d903d054360b902c7556a0c2fe65ab4b08594727bf09aa517e199930c82a81e8003d679705791630b651da7a363ba6011064ebca
|
data/lib/vigilem/x11.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'xlib'
|
2
|
+
|
3
|
+
require 'vigilem/x11/display'
|
4
|
+
|
5
|
+
module Vigilem
|
6
|
+
module X11
|
7
|
+
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# XQueryTree(Display *display, Window w, Window *root_return,
|
11
|
+
# Window *parent_return, Window **children_return,
|
12
|
+
# unsigned int *nchildren_return);
|
13
|
+
# @see man xquerytree
|
14
|
+
# @param [#to_ptr] display
|
15
|
+
# @param [Integer] w
|
16
|
+
# @param [Hash]
|
17
|
+
# @option :root_return [::FFI::Pointer<:ulong>]
|
18
|
+
# @option :parent_return [::FFI::Pointer<:ulong>]
|
19
|
+
# @option :children_return [::FFI::Pointer]
|
20
|
+
# @option :nchildren_return [::FFI::Pointer<:uint> || Integer]
|
21
|
+
# @return [Fixnum] status
|
22
|
+
def query_tree(display, w, opts={})
|
23
|
+
opts[:root_return] ||= ::FFI::MemoryPointer.new(:ulong, 1)
|
24
|
+
opts[:parent_return] ||= ::FFI::MemoryPointer.new(:ulong, 1)
|
25
|
+
opts[:children_return] ||= ::FFI::MemoryPointer.new(:ulong)
|
26
|
+
opts[:nchildren_return] ||= ::FFI::MemoryPointer.new(:uint, 1)
|
27
|
+
|
28
|
+
raise_nil_arg_error('display', display)
|
29
|
+
raise_nil_arg_error('w', w)
|
30
|
+
|
31
|
+
Xlib::XQueryTree(display, w, opts[:root_return], opts[:parent_return],
|
32
|
+
opts[:children_return], opts[:nchildren_return])
|
33
|
+
opts[:nchildren_return] = opts[:nchildren_return].read_uint
|
34
|
+
opts.each do |k,v|
|
35
|
+
opts[k] = v.read_ulong if opts[k].respond_to? :read_ulong
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# @param [#to_ptr] display
|
41
|
+
# @param [Integer || ::FFI::Pointer] focus_return
|
42
|
+
# @param [Integer || ::FFI::Pointer] revert_to_return
|
43
|
+
# @return [Array<Fixnum, Integer, Fixnum>] exit_code, xwindow id, revert_to_return
|
44
|
+
def get_input_focus(display, focus_return, revert_to_return=nil)
|
45
|
+
display = Vigilem::X11::Display.wrap(display)
|
46
|
+
if not focus_return.is_a? ::FFI::MemoryPointer
|
47
|
+
fr = focus_return
|
48
|
+
focus_return = ::FFI::MemoryPointer.new(:int)
|
49
|
+
focus_return.write_int(fr)
|
50
|
+
end
|
51
|
+
if not revert_to_return.is_a? ::FFI::MemoryPointer
|
52
|
+
rtr = revert_to_return
|
53
|
+
revert_to_return = ::FFI::MemoryPointer.new(:int)
|
54
|
+
revert_to_return.write_int(rtr || 0)
|
55
|
+
end
|
56
|
+
raise_nil_arg_error('display', display)
|
57
|
+
raise_nil_arg_error('focus_return', focus_return)
|
58
|
+
[Xlib.XGetInputFocus(display, focus_return, revert_to_return),
|
59
|
+
focus_return.read_int, revert_to_return.read_int]
|
60
|
+
end
|
61
|
+
|
62
|
+
def raise_nil_arg_error(name, val)
|
63
|
+
raise ArgumentError, "#{name} is #{val.inspect}" if val.nil?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
require 'vigilem/x11/input_system_handler'
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'xlib'
|
2
|
+
|
3
|
+
module Vigilem
|
4
|
+
module X11
|
5
|
+
#
|
6
|
+
#
|
7
|
+
class Display < Xlib::Display
|
8
|
+
|
9
|
+
@layout = superclass.layout
|
10
|
+
|
11
|
+
#
|
12
|
+
# @param [Display || FFI::Pointer || String]
|
13
|
+
# display_pointer_or_name
|
14
|
+
def initialize(display_pointer_or_name)
|
15
|
+
if display_pointer_or_name.is_a? ::FFI::Pointer
|
16
|
+
super(display_pointer_or_name)
|
17
|
+
else
|
18
|
+
super(Xlib.XOpenDisplay(display_pointer_or_name))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# @return [Fixnum]
|
24
|
+
def fileno
|
25
|
+
@fileno ||= self[:fd]
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# @return [UNIXSocket]
|
30
|
+
def to_io
|
31
|
+
@io ||= UNIXSocket.for_fd(fileno)
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
alias_method :open, :new
|
36
|
+
|
37
|
+
#
|
38
|
+
# @param [Display || FFI::Pointer || String]
|
39
|
+
# display_obj_pointer_or_name
|
40
|
+
# @return [Display]
|
41
|
+
def wrap(display_obj_pointer_or_name)
|
42
|
+
if display_obj_pointer_or_name.is_a? self
|
43
|
+
display_obj_pointer_or_name
|
44
|
+
else
|
45
|
+
Display.open(display_obj_pointer_or_name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'xlib'
|
2
|
+
|
3
|
+
require 'vigilem/support/obj_space'
|
4
|
+
|
5
|
+
require 'vigilem/core/buffer'
|
6
|
+
|
7
|
+
require 'vigilem/core/eventable'
|
8
|
+
|
9
|
+
require 'vigilem/x11/display'
|
10
|
+
|
11
|
+
module Vigilem
|
12
|
+
module X11
|
13
|
+
#
|
14
|
+
#
|
15
|
+
class EventQueue
|
16
|
+
|
17
|
+
include Core::Buffer
|
18
|
+
|
19
|
+
attr_reader :display
|
20
|
+
|
21
|
+
extend Support::ObjSpace
|
22
|
+
|
23
|
+
class << self
|
24
|
+
#
|
25
|
+
# @param [String || Display || ::FFI::Pointer]
|
26
|
+
# display_pointer_or_name
|
27
|
+
def new(display_obj_pointer_or_name)
|
28
|
+
ret = obj_register(super(display_obj_pointer_or_name))
|
29
|
+
same_display_check!
|
30
|
+
ret
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# finds an existing EventQueue with the given display or
|
35
|
+
# returns a new one based on the items passed in
|
36
|
+
# @param [Display || FFI::Pointer || String]
|
37
|
+
# display_obj_pointer_or_name
|
38
|
+
# @return [EventQueue]
|
39
|
+
def acquire(display_obj_pointer_or_name)
|
40
|
+
dip = Display.wrap(display_obj_pointer_or_name)
|
41
|
+
eventq = all.find {|evq| evq.fileno == dip.fileno }
|
42
|
+
|
43
|
+
eventq || new(dip)
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# @return [Array]
|
48
|
+
def same_display_check
|
49
|
+
all.group_by {|ev| ev.display.fileno }.select {|k, v| v.size > 1 }
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# @param [StandardError] err_type, defaults to ArgumentError
|
54
|
+
# @raise "EventQueues should not have the same display `#{array of event queues with same display}'"
|
55
|
+
# @return [NilClass]
|
56
|
+
def same_display_check!(err_type=ArgumentError)
|
57
|
+
unless (dups = same_display_check).empty?
|
58
|
+
raise err_type, "EventQueues should not have the same display `#{dups}'"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# @param [String || Display || ::FFI::Pointer]
|
66
|
+
# display_pointer_or_name
|
67
|
+
def initialize(display_obj_pointer_or_name)
|
68
|
+
@display = Display.wrap(display_obj_pointer_or_name)
|
69
|
+
end
|
70
|
+
|
71
|
+
# the XPending and items pulled from the queue that
|
72
|
+
# haven't propagated
|
73
|
+
# @return [Fixnum]
|
74
|
+
def pending
|
75
|
+
pending! + _internal_buffer.size
|
76
|
+
end
|
77
|
+
|
78
|
+
# only the number of events returned by XPending
|
79
|
+
# @return [Fixnum]
|
80
|
+
def pending!
|
81
|
+
Xlib.XPending(display!)
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# @return [Xlib::XEvent]
|
86
|
+
def next_event
|
87
|
+
x_event = Xlib::XEvent.new
|
88
|
+
Xlib.XNextEvent(display!, x_event)
|
89
|
+
x_event
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# @return [Fixnum]
|
94
|
+
def fileno
|
95
|
+
@fileno ||= display.fileno
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# @raise [ArgumentError]
|
100
|
+
# @return
|
101
|
+
def display!
|
102
|
+
# a way to validate the pointer to prevent segfault?
|
103
|
+
if display.is_a?(::FFI::Pointer) or display.respond_to?(:to_ptr)
|
104
|
+
display
|
105
|
+
else
|
106
|
+
raise ArgumentError, "Display is a `#{display.inspect}'" +
|
107
|
+
"and doesn't respond to :to_ptr"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# @param [Integer || Range] start_idx_range
|
113
|
+
# @param [Integer] len
|
114
|
+
# @return [Array]
|
115
|
+
def slice!(start_idx_range, len=nil)
|
116
|
+
# this isn;t the most efficient way, but is the
|
117
|
+
# most straight forward
|
118
|
+
pending!.times.map do
|
119
|
+
next_event
|
120
|
+
end.compact.slice!(start_idx_range, *len)
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# @raise [NotImplemented]
|
125
|
+
def concat(*args)
|
126
|
+
raise NotImplementedError
|
127
|
+
end
|
128
|
+
|
129
|
+
#
|
130
|
+
# @raise [NotImplemented]
|
131
|
+
def peek
|
132
|
+
raise NotImplementedError
|
133
|
+
# @todo
|
134
|
+
#if _internal_buffer.size > 0
|
135
|
+
# _internal_buffer[0]
|
136
|
+
#else
|
137
|
+
# if pending! > 0
|
138
|
+
# next_event
|
139
|
+
# end
|
140
|
+
#end
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
#
|
145
|
+
# @return [Array]
|
146
|
+
def _internal_buffer
|
147
|
+
@internal_buffer ||= []
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'vigilem/x11'
|
2
|
+
|
3
|
+
require 'vigilem/core/input_system_handler'
|
4
|
+
|
5
|
+
require 'vigilem/x11/constants'
|
6
|
+
|
7
|
+
require 'vigilem/x11/display'
|
8
|
+
|
9
|
+
require 'vigilem/x11/event_queue'
|
10
|
+
|
11
|
+
module Vigilem
|
12
|
+
module X11
|
13
|
+
#
|
14
|
+
#
|
15
|
+
class InputSystemHandler
|
16
|
+
include Core::InputSystemHandler
|
17
|
+
|
18
|
+
attr_reader :window_xid, :demultiplexer
|
19
|
+
|
20
|
+
#
|
21
|
+
# @param [Integer] win_xid
|
22
|
+
# @param [String || Display || ::FFI::Pointer] display_pointer_or_name
|
23
|
+
# @param [Integer] event_mask
|
24
|
+
def initialize(win_xid, display_obj_pointer_or_name, event_mask=nil)
|
25
|
+
|
26
|
+
initialize_input_system_handler
|
27
|
+
|
28
|
+
display = Display.open(display_obj_pointer_or_name)
|
29
|
+
|
30
|
+
@demultiplexer = Core::Demultiplexer.acquire(EventQueue.new(display), [[self.buffer, {:func => :concat}]]) do |dem|
|
31
|
+
dem.input.respond.fileno == display.fileno
|
32
|
+
end
|
33
|
+
|
34
|
+
@window_xid = win_xid
|
35
|
+
|
36
|
+
self.select_input(event_mask) if event_mask
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
include Core::Eventable
|
41
|
+
|
42
|
+
#
|
43
|
+
# @param [Fixnum] num
|
44
|
+
# @return [Array]
|
45
|
+
def read_many_nonblock(num=1)
|
46
|
+
synchronize {
|
47
|
+
demultiplexer.demux(num)
|
48
|
+
buffer.slice!(0, num)
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
# @todo handle `X Error of failed request: BadWindow (invalid Window parameter)'
|
53
|
+
# @param [Fixnum]
|
54
|
+
# @return [Fixnum]
|
55
|
+
def select_input(event_mask)
|
56
|
+
Xlib.XSelectInput(demultiplexer.input.display, window_xid, event_mask)
|
57
|
+
end
|
58
|
+
|
59
|
+
def_delegators :'demultiplexer.input', :pending, :display
|
60
|
+
|
61
|
+
# @see http://www.unix.com/man-page/All/3x/XGetInputFocus/
|
62
|
+
# @return [Array<Integer, Fixnum>] [xwindow_id, revert_to_return]
|
63
|
+
def get_input_focus
|
64
|
+
X11.get_input_focus(display, window_xid, 0)[1..-1]
|
65
|
+
end
|
66
|
+
|
67
|
+
# @see ::query_tree
|
68
|
+
# @return [Hash]
|
69
|
+
def query_tree(opts={})
|
70
|
+
X11.query_tree(display, window_xid, opts)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Vigilem
|
2
|
+
module X11
|
3
|
+
module System
|
4
|
+
# gets the
|
5
|
+
# @param [Integer] pid
|
6
|
+
# @return [Integer || NilClass]
|
7
|
+
def ppid_of(pid)
|
8
|
+
to_i!(`ps -p #{pid} -o ppid= 2>&1`.strip)
|
9
|
+
end
|
10
|
+
|
11
|
+
#
|
12
|
+
# @param [Intger] pid
|
13
|
+
# @return [File]
|
14
|
+
def environ_file(pid='self')
|
15
|
+
file_path = "#{File::SEPARATOR}#{File.join('proc', pid.to_s, 'environ')}"
|
16
|
+
if test ?e, file_path
|
17
|
+
@environ = File.open(file_path)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# like #to_i but returns nil if not convertable
|
22
|
+
# @todo move to support/core_ext
|
23
|
+
# @param [String] str
|
24
|
+
# @return [Integer || NilClass]
|
25
|
+
def to_i!(str)
|
26
|
+
if str =~ /^\s*(0+|(0*\.0+))\s*$/
|
27
|
+
0
|
28
|
+
else
|
29
|
+
[str.to_i].find {|i| i != 0 }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
extend self
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'vigilem/x11/system'
|
2
|
+
|
3
|
+
module Vigilem
|
4
|
+
module X11
|
5
|
+
#
|
6
|
+
#
|
7
|
+
module TerminalWindowUtils
|
8
|
+
|
9
|
+
extend System
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
# gets the id of the window that spawned this
|
14
|
+
# ruby process
|
15
|
+
# @return [Integer]
|
16
|
+
def window_id
|
17
|
+
return (env = to_i!(ENV['WINDOWID'])) if env
|
18
|
+
|
19
|
+
curr_pid = Process.pid
|
20
|
+
until curr_pid.to_i < 2
|
21
|
+
file = environ_file(curr_pid)
|
22
|
+
if file and (xid = to_i!(file.read.scan(/(?<=WINDOWID=)\d+/)[0]))
|
23
|
+
return xid
|
24
|
+
else
|
25
|
+
curr_pid = ppid_of(curr_pid)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'vigilem/x11/display'
|
4
|
+
|
5
|
+
describe Vigilem::X11::Display do
|
6
|
+
|
7
|
+
after(:each) do
|
8
|
+
[described_class].each do |klass|
|
9
|
+
(klass.instance_variables - [:@layout]).each do |ivar|
|
10
|
+
klass.send(:remove_instance_variable, ivar)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'is a subclass of Xlib::Display' do
|
16
|
+
expect(described_class).to be < Xlib::Display
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'has the same structure as Xlib::Display' do
|
20
|
+
expect(described_class.layout).to eql(Xlib::Display.layout)
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#initialize' do
|
24
|
+
it 'takes a pointer and creates a display from it' do
|
25
|
+
expect do
|
26
|
+
described_class.new(Xlib.XOpenDisplay(ENV['DISPLAY']))
|
27
|
+
end.not_to raise_error and be_a described_class
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'takes a display name and creates a Display' do
|
31
|
+
expect do
|
32
|
+
described_class.new(ENV['DISPLAY'])
|
33
|
+
end.not_to raise_error and be_a described_class
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'post_init' do
|
38
|
+
subject { described_class.new(ENV['DISPLAY']) }
|
39
|
+
|
40
|
+
describe '#fileno' do
|
41
|
+
it 'returns the fileno of the associated IO' do
|
42
|
+
expect(subject.fileno).to be_an Integer
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#to_io' do
|
47
|
+
it 'returns the display as IO' do
|
48
|
+
expect(subject.to_io).to be_a IO
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '::wrap' do
|
54
|
+
it 'returns a new display object' do
|
55
|
+
expect { described_class.wrap(ENV['DISPLAY']) }.not_to raise_error and be_a Display
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'takes a pointer and creates a display from it' do
|
59
|
+
expect { described_class.wrap(Xlib.XOpenDisplay(ENV['DISPLAY'])) }.not_to raise_error and be_a Display
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'takes a Display object and returns the same Display object' do
|
63
|
+
dpy = described_class.wrap(ENV['DISPLAY'])
|
64
|
+
expect { described_class.wrap(dpy) }.not_to raise_error and eql(dpy)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
#describe '::open' do
|
69
|
+
#
|
70
|
+
#end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'vigilem/x11/event_queue'
|
4
|
+
|
5
|
+
describe Vigilem::X11::EventQueue do
|
6
|
+
|
7
|
+
let(:dpy) { Vigilem::X11::Display.new(ENV['DISPLAY']) }
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
[described_class, Vigilem::X11::Display].each do |klass|
|
11
|
+
(klass.instance_variables - [:@layout]).each do |ivar|
|
12
|
+
klass.send(:remove_instance_variable, ivar)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '::same_display_check' do
|
18
|
+
|
19
|
+
it %q<checks the ::all for EventQueue's that have the same fileno> do
|
20
|
+
ary = [double("EventQueue1", :display => dpy), double("EventQueue2", :display => dpy)]
|
21
|
+
described_class.all.concat(ary)
|
22
|
+
expect(described_class.same_display_check).to eql({ dpy.fileno => ary })
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '::same_display_check!' do
|
28
|
+
|
29
|
+
it %q<checks the ::all for EventQueue's that have the same fileno and raises an Error if some exist> do
|
30
|
+
ary = [double("EventQueue1", :display => dpy), double("EventQueue2", :display => dpy)]
|
31
|
+
described_class.all.concat(ary)
|
32
|
+
expect { described_class.same_display_check! }.to raise_error(ArgumentError)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#initialize' do
|
38
|
+
it 'accepts a display obj' do
|
39
|
+
expect do
|
40
|
+
described_class.new(dpy)
|
41
|
+
end.to_not raise_error and be_a described_class
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'accepts a display pointer' do
|
45
|
+
expect do
|
46
|
+
described_class.new(Xlib.XOpenDisplay(ENV['DISPLAY']))
|
47
|
+
end.to_not raise_error and be_a described_class
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'accepts a display_name' do
|
51
|
+
expect do
|
52
|
+
described_class.new(ENV['DISPLAY'])
|
53
|
+
end.to_not raise_error and be_a described_class
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '::new' do
|
59
|
+
it 'adds the instance to ' do
|
60
|
+
dpy = described_class.new(ENV['DISPLAY'])
|
61
|
+
expect(described_class.all).to include(dpy)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'calls #same_display_check!' do
|
65
|
+
ary = [double("EventQueue1", :display => dpy), double("EventQueue2", :display => dpy)]
|
66
|
+
described_class.all.concat(ary)
|
67
|
+
expect { described_class.new(dpy) }.to raise_error(ArgumentError)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '::acquire' do
|
72
|
+
it 'returns a new instance if none is found' do
|
73
|
+
described_class.all.replace([])
|
74
|
+
dspy = Vigilem::X11::Display.new(ENV['DISPLAY'])
|
75
|
+
expect(described_class.acquire(dspy)).to be_a described_class
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns the instance that has the same display#fileno' do
|
79
|
+
evq = described_class.new(dpy)
|
80
|
+
expect(described_class.acquire(dpy)).to eql(evq)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#pending!' do
|
85
|
+
it 'gets the XPending value' do
|
86
|
+
evq = described_class.new(dpy)
|
87
|
+
num = 1
|
88
|
+
allow(Xlib).to receive(:XPending) { num }
|
89
|
+
expect(evq.pending!).to eql(num)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#pending' do
|
94
|
+
it 'gets the XPending value and the size of the array not yet propagated' do
|
95
|
+
evq = described_class.new(dpy)
|
96
|
+
internal_buf = [Xlib::XEvent.new, Xlib::XEvent.new]
|
97
|
+
evq.send(:_internal_buffer).concat(internal_buf)
|
98
|
+
xpend_ret = 1
|
99
|
+
allow(Xlib).to receive(:XPending) { xpend_ret }
|
100
|
+
expect(evq.pending).to eql(xpend_ret + internal_buf.size)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe '#next_event' do
|
105
|
+
it 'gets the next event from the xwindow event queue' do
|
106
|
+
allow(Xlib).to receive(:XNextEvent)
|
107
|
+
evq = described_class.new(dpy)
|
108
|
+
expect(evq.next_event).to be_a Xlib::XEvent
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#fileno' do
|
113
|
+
it 'gets the fileno of the display' do
|
114
|
+
evq = described_class.new(dpy)
|
115
|
+
expect(evq.fileno).to eql(evq.fileno)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '#slice!' do
|
120
|
+
it 'will get the ' do
|
121
|
+
evq = described_class.new(dpy)
|
122
|
+
allow(evq).to receive(:pending!) { 1 }
|
123
|
+
empty_event = Xlib::XEvent.new
|
124
|
+
allow(evq).to receive(:next_event) { empty_event }
|
125
|
+
expect(evq.slice!(0)).to eql(empty_event)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe '#concat' do
|
130
|
+
it 'will error, not implemented' do
|
131
|
+
evq = described_class.new(dpy)
|
132
|
+
expect { evq.concat }.to raise_error(NotImplementedError)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe '#peek' do
|
137
|
+
it 'will error, no implemented' do
|
138
|
+
evq = described_class.new(dpy)
|
139
|
+
expect { evq.concat }.to raise_error(NotImplementedError)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'private' do
|
144
|
+
describe '#_internal_buffer' do
|
145
|
+
it 'defaults to an empty array' do
|
146
|
+
evq = described_class.new(dpy)
|
147
|
+
expect(evq.send(:_internal_buffer)).to eql([])
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'vigilem/x11/input_system_handler'
|
4
|
+
|
5
|
+
describe Vigilem::X11::InputSystemHandler do
|
6
|
+
|
7
|
+
subject { described_class.new(0x12123, (ENV['DISPLAY'] || ::FFI::MemoryPointer.new(:long, 296))) }
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
[described_class, Vigilem::X11::EventQueue, Vigilem::Core::Demultiplexer, Vigilem::X11::Display].each do |klass|
|
11
|
+
(klass.instance_variables - [:@layout]).each do |ivar|
|
12
|
+
klass.send(:remove_instance_variable, ivar)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#select_input' do
|
18
|
+
it 'calls XSelectInput' do
|
19
|
+
mask = Xlib::KeyPressMask | Xlib::FocusChangeMask
|
20
|
+
allow(Xlib).to receive(:XSelectInput).with(mask)
|
21
|
+
expect(Xlib).to receive(:XSelectInput).with(subject.demultiplexer.input.display, subject.window_xid, mask)
|
22
|
+
subject.select_input(mask)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#initialize' do
|
27
|
+
|
28
|
+
it 'sets up the window if the window_xid was given' do
|
29
|
+
expect(subject.window_xid).to be_an Integer
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'calls XSelectInput if passed in' do
|
33
|
+
mask = Xlib::KeyPressMask | Xlib::FocusChangeMask
|
34
|
+
allow(Xlib).to receive(:XSelectInput).with(mask)
|
35
|
+
expect(Xlib).to receive(:XSelectInput)
|
36
|
+
Vigilem::X11::EventQueue.all.replace([])
|
37
|
+
described_class.new(0x1111, ::FFI::MemoryPointer.new(:long, 296), mask)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#read_many_nonblock' do
|
42
|
+
it 'reads a max number of events from the event_queue' do
|
43
|
+
allow(subject.demultiplexer.input).to receive(:shift) { [1,2,3] }
|
44
|
+
expect(subject.read_many_nonblock(3)).to eql([1,2,3])
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'calls #synchronize' do
|
48
|
+
allow(subject.demultiplexer.input).to receive(:shift) { [1,2,3] }
|
49
|
+
expect(subject).to receive(:synchronize)
|
50
|
+
subject.read_many_nonblock(3)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'sets up the other eventable methods' do
|
54
|
+
allow(subject.demultiplexer.input).to receive(:shift) { [1] }
|
55
|
+
expect { subject.read_one_nonblock }.not_to raise_error and eql([1])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#get_input_focus' do
|
60
|
+
it 'calls ::get_input_focus' do
|
61
|
+
allow(Vigilem::X11).to receive(:get_input_focus)
|
62
|
+
expect(Vigilem::X11).to receive(:get_input_focus).with(subject.display, subject.window_xid, 0) { [1,2,3] }
|
63
|
+
subject.get_input_focus
|
64
|
+
end
|
65
|
+
|
66
|
+
if Xlib.available?
|
67
|
+
it 'returns a Fixnum, and Integer' do
|
68
|
+
allow(described_class).to receive(:get_input_focus).and_call_original
|
69
|
+
expect(subject.get_input_focus).to match [a_kind_of(Fixnum), a_kind_of(Integer)]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'vigilem/x11/system'
|
4
|
+
|
5
|
+
describe Vigilem::X11::System do
|
6
|
+
|
7
|
+
describe '::to_i!' do
|
8
|
+
it 'returns an Integer if convertable' do
|
9
|
+
expect(described_class.to_i!("1234.1234")).to eql(1234)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'returns an nil if not convertable' do
|
13
|
+
expect(described_class.to_i!("Sjaldan er ein baran stok")).to be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns 0 when the value is zero' do
|
17
|
+
expect(described_class.to_i!("0")).to eql(0)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'returns 0 when the value is zero equivilant' do
|
21
|
+
expect(described_class.to_i!(".00")).to eql(0)
|
22
|
+
end
|
23
|
+
|
24
|
+
it %q<doesn't return 0 if it contains zero> do
|
25
|
+
expect(described_class.to_i!('83886092')).to eql(83886092)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '::environ_file' do
|
30
|
+
it 'defaults to the /proc/self/environ' do
|
31
|
+
expect(described_class.environ_file.path).to eql("/proc/self/environ")
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'gets the environ file of the pid passed in' do
|
35
|
+
expect(described_class.environ_file(Process.pid).path).to eql("/proc/#{Process.pid}/environ")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '::ppid_of' do
|
40
|
+
it 'gets the ppid of the passed in pid' do
|
41
|
+
expect(described_class.ppid_of(Process.pid)).to eql(Process.ppid)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns nil if ppid cannot be found' do
|
45
|
+
expect(described_class.ppid_of(`cat /proc/sys/kernel/pid_max`.to_i + 1)).to be_nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
require 'vigilem/x11/terminal_window_utils'
|
6
|
+
|
7
|
+
describe Vigilem::X11::TerminalWindowUtils do
|
8
|
+
|
9
|
+
describe '::window_id' do
|
10
|
+
it 'returns the id of the window if it exists' do
|
11
|
+
expect(described_class.window_id).to be > 0
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'checks the environ_file if the ENV is empty' do
|
15
|
+
|
16
|
+
ENV['WINDOWID'] = ''
|
17
|
+
allow(described_class).to receive(:environ_file) { Tempfile.new('asdf') }
|
18
|
+
expect(described_class).to receive(:environ_file)
|
19
|
+
described_class.window_id
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns traverses the pid tree to find an WINDOWID in the environ_file' do
|
23
|
+
ENV['WINDOWID'] = ''
|
24
|
+
allow(described_class).to receive(:environ_file) { Tempfile.new('asdf') }
|
25
|
+
expect(described_class.window_id).to be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'vigilem/x11'
|
2
|
+
|
3
|
+
describe Vigilem::X11 do
|
4
|
+
if Xlib.available?
|
5
|
+
|
6
|
+
describe '::get_input_focus' do
|
7
|
+
|
8
|
+
let(:display) { Vigilem::X11::Display.new(ENV['DISPLAY'] || ::FFI::MemoryPointer.new(:long, 296)) }
|
9
|
+
|
10
|
+
let(:win_id) { 0x12123 }
|
11
|
+
|
12
|
+
=begin
|
13
|
+
# this should work, but allow strips out the arguments (or something) and
|
14
|
+
# then ArgumentError: "Invalid Memory object" is raised
|
15
|
+
it 'calls XGetInputFocus' do
|
16
|
+
allow(Xlib).to receive(:XGetInputFocus).with(a_kind_of(::FFI::Struct), a_kind_of(Fixnum), a_kind_of(Fixnum))
|
17
|
+
expect(Xlib).to receive(:XGetInputFocus).with(a_kind_of(::FFI::Struct), a_kind_of(Fixnum), a_kind_of(Fixnum))
|
18
|
+
|
19
|
+
subject.get_input_focus
|
20
|
+
end
|
21
|
+
=end
|
22
|
+
it 'accepts [String],[Fixnum],[Fixnum] returns [Fixnum, Integer, Fixnum]' do
|
23
|
+
expect(described_class.get_input_focus(display, win_id)).to match [
|
24
|
+
a_kind_of(Fixnum), a_kind_of(Integer), a_kind_of(Fixnum)
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'updates window ptr' do
|
29
|
+
window = FFI::MemoryPointer.new(:ulong)
|
30
|
+
window.write_ulong(win_id)
|
31
|
+
described_class.get_input_focus(display, window)
|
32
|
+
expect(window.read_int).not_to eql(win_id)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'updates revert_to_return ptr' do
|
36
|
+
revert_to_return = FFI::MemoryPointer.new(:int)
|
37
|
+
revert_to_return.write_int(0)
|
38
|
+
described_class.get_input_focus(display, win_id)
|
39
|
+
expect(revert_to_return.read_int).to be_a Fixnum
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vigilem-x11
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- jtzero
|
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: xlib
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
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: vigilem-core
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.1'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec-given
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: turnip
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: guard-rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: X11 bindings for Vigilem, currently used internally only
|
140
|
+
email:
|
141
|
+
- jtzero511@gmail
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- lib/vigilem/x11.rb
|
147
|
+
- lib/vigilem/x11/constants.rb
|
148
|
+
- lib/vigilem/x11/display.rb
|
149
|
+
- lib/vigilem/x11/event_queue.rb
|
150
|
+
- lib/vigilem/x11/input_system_handler.rb
|
151
|
+
- lib/vigilem/x11/system.rb
|
152
|
+
- lib/vigilem/x11/terminal_window_utils.rb
|
153
|
+
- lib/vigilem/x11/version.rb
|
154
|
+
- spec/spec_helper.rb
|
155
|
+
- spec/vigilem/x11/display_spec.rb
|
156
|
+
- spec/vigilem/x11/event_queue_spec.rb
|
157
|
+
- spec/vigilem/x11/input_system_handler_spec.rb
|
158
|
+
- spec/vigilem/x11/system_spec.rb
|
159
|
+
- spec/vigilem/x11/terminal_window_utils_spec.rb
|
160
|
+
- spec/vigilem/x11_spec.rb
|
161
|
+
homepage: http://rubygems.org/gems/vigilem-x11
|
162
|
+
licenses:
|
163
|
+
- MIT
|
164
|
+
metadata: {}
|
165
|
+
post_install_message:
|
166
|
+
rdoc_options: []
|
167
|
+
require_paths:
|
168
|
+
- lib
|
169
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - '>='
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
requirements: []
|
180
|
+
rubyforge_project:
|
181
|
+
rubygems_version: 2.4.6
|
182
|
+
signing_key:
|
183
|
+
specification_version: 4
|
184
|
+
summary: X11 bindings for Vigilem
|
185
|
+
test_files:
|
186
|
+
- spec/spec_helper.rb
|
187
|
+
- spec/vigilem/x11/display_spec.rb
|
188
|
+
- spec/vigilem/x11/event_queue_spec.rb
|
189
|
+
- spec/vigilem/x11/input_system_handler_spec.rb
|
190
|
+
- spec/vigilem/x11/system_spec.rb
|
191
|
+
- spec/vigilem/x11/terminal_window_utils_spec.rb
|
192
|
+
- spec/vigilem/x11_spec.rb
|