xlib-objects 0.6.3 → 0.7.0

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,89 @@
1
+ #
2
+ # Copyright (c) 2015 Christopher Aue <mail@christopheraue.net>
3
+ #
4
+ # This file is part of the ruby xlib-objects gem. It is subject to the license
5
+ # terms in the LICENSE file found in the top-level directory of this
6
+ # distribution and at http://github.com/christopheraue/ruby-xlib-objects.
7
+ #
8
+
9
+ module XlibObj
10
+ class InputDevice
11
+ def initialize(display, device_id)
12
+ @display = display
13
+ @device_id = device_id
14
+ end
15
+
16
+ attr_reader :display
17
+
18
+ def to_native
19
+ @device_id
20
+ end
21
+ alias_method :id, :to_native
22
+
23
+ def name
24
+ device_info(:name, &:read_string)
25
+ end
26
+
27
+ def master?
28
+ [Xlib::XIMasterPointer, Xlib::XIMasterKeyboard].include? device_info(:use)
29
+ end
30
+
31
+ def slave?
32
+ [Xlib::XISlavePointer, Xlib::XISlaveKeyboard].include? device_info(:use)
33
+ end
34
+
35
+ def floating?
36
+ device_info(:use) == Xlib::XIFloatingSlave
37
+ end
38
+
39
+ def pointer?
40
+ [Xlib::XIMasterPointer, Xlib::XISlavePointer].include? device_info(:use)
41
+ end
42
+
43
+ def keyboard?
44
+ [Xlib::XIMasterKeyboard, Xlib::XISlaveKeyboard].include? device_info(:use)
45
+ end
46
+
47
+ def master
48
+ self.class.new(@display, device_info(:attachment)) if slave?
49
+ end
50
+
51
+ def slaves
52
+ @display.input_devices.select{ |device| device.master == self }
53
+ end
54
+
55
+ def enabled?
56
+ device_info(:enabled)
57
+ end
58
+
59
+ def disabled?
60
+ not enabled?
61
+ end
62
+
63
+ def focus(window = nil)
64
+ if window
65
+ Xlib::XI.set_focus(@display, self, window, Xlib::CurrentTime)
66
+ else
67
+ Xlib::XI.get_focus(@display, self) if keyboard?
68
+ end
69
+ end
70
+
71
+ def grab(report_to:, cursor: Xlib::None, mode: Xlib::GrabModeAsync, pair_mode: Xlib::GrabModeAsync,
72
+ owner_events: true, event_mask: 0)
73
+ Xlib::XI.grab_device(@display, self, report_to, Xlib::CurrentTime, cursor, mode, pair_mode, owner_events, event_mask)
74
+ end
75
+
76
+ def ungrab
77
+ Xlib::XI.ungrab_device(@display, self, Xlib::CurrentTime)
78
+ end
79
+
80
+ private
81
+
82
+ def device_info(member, &do_with_member)
83
+ device_info = Xlib::XI.query_device(@display, @device_id).first
84
+ do_with_member ? yield(device_info[member]) : device_info[member]
85
+ ensure
86
+ Xlib::XI.free_device_info(device_info)
87
+ end
88
+ end
89
+ end
data/lib/window.rb CHANGED
@@ -11,7 +11,7 @@ module XlibObj
11
11
  def initialize(display, window_id)
12
12
  @display = display
13
13
  @to_native = window_id
14
- @event_handler = EventHandler.singleton(display, window_id)
14
+ @event_handler = EventHandler.singleton(display, self)
15
15
  end
16
16
 
17
17
  # Queries
@@ -206,6 +206,13 @@ module XlibObj
206
206
  Window.new(@display, win_id)
207
207
  end
208
208
 
209
+ def create_input_window
210
+ attributes = Xlib::SetWindowAttributes.new
211
+ win_id = Xlib.XCreateWindow(@display.to_native, to_native, 0, 0, 1, 1, 0, Xlib::CopyFromParent,
212
+ Xlib::InputOnly, nil, 0, attributes.pointer)
213
+ Window.new(@display, win_id)
214
+ end
215
+
209
216
  def destroy
210
217
  @event_handler.destroy
211
218
  Xlib.XDestroyWindow(@display.to_native, to_native)
@@ -9,117 +9,75 @@
9
9
  module XlibObj
10
10
  class Window
11
11
  class EventHandler
12
+ @instances = {}
13
+
12
14
  class << self
13
- def singleton(display, window_id)
14
- @handlers ||= {}
15
- @handlers[display] ||= {}
16
- @handlers[display][window_id] ||= new(display, window_id)
15
+ def singleton(display, window)
16
+ @instances[display] ||= {}
17
+ @instances[display][window.id] ||= new(display, window)
17
18
  end
18
19
 
19
- def remove(display, window_id)
20
- @handlers[display].delete(window_id) if @handlers and @handlers[display]
20
+ def remove(display, window)
21
+ @instances[display].delete(window.id) if @instances[display]
21
22
  end
22
23
  end
23
24
 
24
- def initialize(display, window_id)
25
+ def initialize(display, window)
25
26
  @display = display
26
- @window_id = window_id
27
+ @window = window
27
28
  @event_handlers = {}
28
- @event_mask = 0
29
- @rr_event_mask = 0
30
29
  end
31
30
 
31
+ attr_reader :display, :window
32
+
32
33
  def on(mask, event, &handler)
33
34
  add_event_mask(mask)
34
35
  add_event_handler(mask, event, &handler)
35
36
  end
36
37
 
37
- def off(mask, type, handler = nil)
38
- remove_event_handler(mask, type, handler)
38
+ def off(mask, event, handler = nil)
39
+ remove_event_handler(mask, event, handler)
39
40
  remove_event_mask(mask)
40
41
  end
41
42
 
42
43
  def handle(event)
43
- if @event_handlers[event.name]
44
- @event_handlers[event.name].each do |_, handlers|
45
- handlers.each{ |handler| handler.call(event) }
46
- end
47
- true
48
- else
49
- false
44
+ @event_handlers.each do |mask, handlers|
45
+ next unless handlers[event.name]
46
+ handlers[event.name].each{ |handler| handler.call(event) }
50
47
  end
51
48
  end
52
49
 
53
50
  def destroy
54
- self.class.remove(@display, @window_id)
51
+ self.class.remove(@display, @window)
55
52
  end
56
53
 
57
54
  private
55
+
58
56
  def add_event_mask(mask)
59
- check_mask(mask)
60
- return if mask_in_use?(mask)
61
- @event_mask |= normalize_mask(mask)
62
- @rr_event_mask |= normalize_rr_mask(mask)
63
- select_events
57
+ return if @event_handlers[mask]
58
+
59
+ @event_handlers[mask] = {}
60
+ extension = @display.extensions.find{ |ext| ext.handles_event_mask?(mask) }
61
+ extension.select_mask(@window, mask)
64
62
  end
65
63
 
66
64
  def remove_event_mask(mask)
67
- check_mask(mask)
68
- return if mask_in_use?(mask)
69
- return unless mask_selected?(mask)
70
- @event_mask &= ~normalize_mask(mask)
71
- @rr_event_mask &= ~normalize_rr_mask(mask)
72
- select_events
65
+ return unless @event_handlers[mask].empty?
66
+
67
+ extension = @display.extensions.find{ |ext| ext.handles_event_mask?(mask) }
68
+ extension.deselect_mask(@window, mask)
69
+ @event_handlers.delete(mask)
73
70
  end
74
71
 
75
72
  def add_event_handler(mask, event, &handler)
76
- check_event(event)
77
- @event_handlers[event] ||= {}
78
- @event_handlers[event][mask] ||= []
79
- @event_handlers[event][mask] << handler
73
+ @event_handlers[mask][event] ||= []
74
+ @event_handlers[mask][event] << handler
80
75
  handler
81
76
  end
82
77
 
83
78
  def remove_event_handler(mask, event, handler)
84
- check_event(event)
85
- return unless mask_in_use?(mask)
86
- return unless @event_handlers[event]
87
- @event_handlers[event][mask].delete(handler) if handler
88
- @event_handlers[event].delete(mask) if @event_handlers[event][mask].empty? or handler.nil?
89
- @event_handlers.delete(event) if @event_handlers[event].empty?
90
- end
91
-
92
- def mask_in_use?(mask)
93
- @event_handlers.select{ |_, handlers| handlers.has_key?(mask) }.any?
94
- end
95
-
96
- def mask_selected?(mask)
97
- (@event_mask & ~normalize_mask(mask) != @event_mask) or
98
- (@rr_event_mask & ~normalize_rr_mask(mask) != @rr_event_mask)
99
- end
100
-
101
- def check_mask(mask)
102
- if XlibObj::Event::MASK[mask].nil? && XlibObj::Event::RR_MASK[mask].nil?
103
- raise("Unknown event mask #{mask}.")
104
- end
105
- end
106
-
107
- def normalize_mask(mask)
108
- XlibObj::Event::MASK[mask] || 0
109
- end
110
-
111
- def normalize_rr_mask(mask)
112
- XlibObj::Event::RR_MASK[mask] || 0
113
- end
114
-
115
- def check_event(event)
116
- XlibObj::Event.valid_name?(event) || raise("Unknown event #{event}.")
117
- end
118
-
119
- def select_events
120
- Xlib.XSelectInput(@display.to_native, @window_id, @event_mask)
121
- Xlib.XRRSelectInput(@display.to_native, @window_id, @rr_event_mask)
122
- @display.flush
79
+ @event_handlers[mask][event].delete(handler)
80
+ @event_handlers[mask].delete(event) if @event_handlers[mask][event].empty?
123
81
  end
124
82
  end
125
83
  end
data/lib/xlib-objects.rb CHANGED
@@ -7,18 +7,11 @@
7
7
  #
8
8
 
9
9
  require 'xlib'
10
+ require 'xlib/xinput2'
10
11
 
11
12
  module XlibObj; end
12
13
 
13
- require_relative 'atom'
14
- require_relative 'display'
15
- require_relative 'event'
16
- require_relative 'error'
17
- require_relative 'event/client_message'
18
- require_relative 'event/selection_notify'
19
- require_relative 'screen'
20
- require_relative 'screen/crtc'
21
- require_relative 'screen/crtc/output'
22
- require_relative 'window'
23
- require_relative 'window/property'
24
- require_relative 'window/event_handler'
14
+ lib_dir = File.dirname __FILE__
15
+ lib_files = File.join(lib_dir, '**/*.rb')
16
+
17
+ Dir[lib_files].sort.each { |f| require f }
data/lib/xlib/x.rb ADDED
@@ -0,0 +1,57 @@
1
+ module Xlib
2
+ module X; end
3
+ class << X
4
+ def open_display(name)
5
+ display_pointer = Xlib.XOpenDisplay(name)
6
+ raise ArgumentError, "Unknown display #{name}" if display_pointer.null?
7
+ Xlib::Display.new(display_pointer)
8
+ end
9
+
10
+ def close_display(display)
11
+ Xlib.XCloseDisplay(display.to_native)
12
+ end
13
+
14
+ def list_extensions(display)
15
+ nextensions_ptr = FFI::MemoryPointer.new :pointer
16
+ extensions_ptr = Xlib.XListExtensions(display.to_native, nextensions_ptr)
17
+ nextensions = nextensions_ptr.read_int
18
+ extensions = extensions_ptr.get_array_of_string(0, nextensions)
19
+ Xlib.XFreeExtensionList(extensions_ptr)
20
+ extensions
21
+ end
22
+
23
+ def query_extension(display, name)
24
+ opcode_ptr = FFI::MemoryPointer.new :int
25
+ evcode_ptr = FFI::MemoryPointer.new :int
26
+ errcode_ptr = FFI::MemoryPointer.new :int
27
+ if Xlib.XQueryExtension(display.to_native, name, opcode_ptr, evcode_ptr, errcode_ptr)
28
+ { opcode: opcode_ptr.read_int, first_event: evcode_ptr.read_int, first_error: errcode_ptr.read_int}
29
+ else
30
+ false
31
+ end
32
+ end
33
+
34
+ def get_event_data(display, event_cookie)
35
+ Xlib::XGetEventData(display.to_native, event_cookie.pointer)
36
+ end
37
+
38
+ def select_input(display, window, mask)
39
+ Xlib.XSelectInput(display.to_native, window.to_native, mask)
40
+ flush(display)
41
+ end
42
+
43
+ def next_event(display)
44
+ xevent = Xlib::XEvent.new
45
+ Xlib.XNextEvent(display.to_native, xevent) # blocks
46
+ xevent
47
+ end
48
+
49
+ def pending(display)
50
+ Xlib.XPending(display.to_native)
51
+ end
52
+
53
+ def flush(display)
54
+ Xlib.XFlush(display.to_native)
55
+ end
56
+ end
57
+ end
data/lib/xlib/xi.rb ADDED
@@ -0,0 +1,60 @@
1
+ module Xlib
2
+ module XI
3
+ class << self
4
+ def query_device(display, device_id)
5
+ ndevices_ptr = FFI::MemoryPointer.new :int
6
+ device_infos_ptr = Xlib::XIQueryDevice(display.to_native, device_id, ndevices_ptr)
7
+ ndevices = ndevices_ptr.read_int
8
+
9
+ 0.upto(ndevices-1).map do |position|
10
+ device_info_ptr = device_infos_ptr + position * Xlib::XIDeviceInfo.size
11
+ Xlib::XIDeviceInfo.new(device_info_ptr)
12
+ end
13
+ end
14
+
15
+ def free_device_info(device_info)
16
+ Xlib.XIFreeDeviceInfo(device_info.pointer)
17
+ true
18
+ end
19
+
20
+ def set_focus(display, device, window, time)
21
+ 0 == Xlib::XISetFocus(display.to_native, device.to_native, window.to_native, time).tap do
22
+ Xlib::X.flush(display)
23
+ end
24
+ end
25
+
26
+ def get_focus(display, device)
27
+ window_id_ptr = FFI::MemoryPointer.new :Window
28
+ if 0 == Xlib::XIGetFocus(display.to_native, device.to_native, window_id_ptr)
29
+ case window_id = window_id_ptr.read_int
30
+ when Xlib::PointerRoot
31
+ display.screens.first.root_window
32
+ when Xlib::None
33
+ nil
34
+ else
35
+ XlibObj::Window.new(display, window_id)
36
+ end
37
+ end
38
+ end
39
+
40
+ def grab_device(display, device, window, time, cursor, mode, pair_mode, owner_events, event_mask)
41
+ event_mask = EventMask.new(device, event_mask)
42
+ 0 == Xlib::XIGrabDevice(display.to_native, device.to_native, window.to_native, time, cursor,
43
+ mode, pair_mode, owner_events, event_mask.to_native)
44
+ end
45
+
46
+ def ungrab_device(display, device, time)
47
+ 0 == Xlib::XIUngrabDevice(display.to_native, device.to_native, time).tap do
48
+ Xlib::X.flush(display)
49
+ end
50
+ end
51
+
52
+ def select_events(display, devices, window, event_mask)
53
+ event_mask = EventMask.new(devices, event_mask)
54
+ Xlib.XISelectEvents(display.to_native, window.to_native, event_mask.to_native, devices.size)
55
+ Xlib::X.flush(display)
56
+ true
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,32 @@
1
+ module Xlib
2
+ module XI
3
+ class EventMask
4
+ def initialize(devices, mask)
5
+ @devices = [*devices]
6
+ @mask = mask
7
+ end
8
+
9
+ attr_reader :devices, :mask
10
+
11
+ def to_native
12
+ @structs ||= begin
13
+ masks_ptr = FFI::MemoryPointer.new(Xlib::XIEventMask.size, @devices.count)
14
+
15
+ @devices.each.with_index do |device, idx|
16
+ byte_length = (@mask.bit_length/8.0).ceil
17
+ mask_ptr = FFI::MemoryPointer.new :int
18
+ mask_ptr.write_int @mask
19
+
20
+ Xlib::XIEventMask.new(masks_ptr[idx]).tap do |event_mask|
21
+ event_mask[:deviceid] = device.is_a?(XlibObj::InputDevice) ? device.id : device
22
+ event_mask[:mask_len] = FFI.type_size(:int)
23
+ event_mask[:mask] = mask_ptr
24
+ end
25
+ end
26
+
27
+ Xlib::XIEventMask.new(masks_ptr[0]).pointer
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/xlib/xrr.rb ADDED
@@ -0,0 +1,10 @@
1
+ module Xlib
2
+ module XRR
3
+ class << self
4
+ def select_input(display, window, mask)
5
+ Xlib.XRRSelectInput(display.to_native, window.to_native, mask)
6
+ Xlib::X.flush(display)
7
+ end
8
+ end
9
+ end
10
+ end