xlib-objects 0.6.3 → 0.7.0

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