active_window_x 0.0.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.
- data/.gitignore +25 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +60 -0
- data/Rakefile +47 -0
- data/active_window_x.gemspec +22 -0
- data/ext/active_window_x/extconf.rb +7 -0
- data/ext/active_window_x/xlib.c +751 -0
- data/lib/active_window_x/atom.rb +30 -0
- data/lib/active_window_x/client_message_event.rb +44 -0
- data/lib/active_window_x/display.rb +79 -0
- data/lib/active_window_x/event.rb +15 -0
- data/lib/active_window_x/event_listener.rb +119 -0
- data/lib/active_window_x/property_event.rb +46 -0
- data/lib/active_window_x/root_window.rb +20 -0
- data/lib/active_window_x/version.rb +3 -0
- data/lib/active_window_x/window.rb +123 -0
- data/lib/active_window_x/xid.rb +29 -0
- data/lib/active_window_x.rb +30 -0
- data/sample/active_window_dump.rb +30 -0
- data/sample/simple.rb +6 -0
- data/spec/atom_spec.rb +27 -0
- data/spec/display_spec.rb +63 -0
- data/spec/root_window_spec.rb +47 -0
- data/spec/window_spec.rb +285 -0
- data/spec/xlib_spec.rb +245 -0
- metadata +136 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- coding:utf-8; mode:ruby; -*-
|
2
|
+
|
3
|
+
module ActiveWindowX
|
4
|
+
|
5
|
+
# binding for Atom on X11
|
6
|
+
class Atom < Xid
|
7
|
+
@@cache = {}
|
8
|
+
|
9
|
+
def initialize display, second
|
10
|
+
if second.kind_of? Numeric
|
11
|
+
super
|
12
|
+
elsif second.kind_of? String
|
13
|
+
super
|
14
|
+
@id = display.intern_atom second
|
15
|
+
if @id == Xlib::None
|
16
|
+
raise ArgumentError, 'invalid an atom name: #{second}'
|
17
|
+
end
|
18
|
+
else
|
19
|
+
raise ArgumentError, 'expect Numeric or String with the second argument'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias :intern :id
|
24
|
+
|
25
|
+
def name
|
26
|
+
@display.atom_name @id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- coding:utf-8; mode:ruby; -*-
|
2
|
+
|
3
|
+
module ActiveWindowX
|
4
|
+
|
5
|
+
# binding for XClientMessageEvent on X11
|
6
|
+
class ClientMessageEvent < Event
|
7
|
+
|
8
|
+
# the number of last request processed by server
|
9
|
+
attr_reader :serial
|
10
|
+
|
11
|
+
# true if this came from a SendEvent request
|
12
|
+
attr_reader :send_event
|
13
|
+
|
14
|
+
# Display the event was read from
|
15
|
+
attr_reader :display
|
16
|
+
|
17
|
+
# the window whose associated property was changed
|
18
|
+
attr_reader :window
|
19
|
+
|
20
|
+
# an atom that indicates how the data should be interpreted
|
21
|
+
# by the receiving client
|
22
|
+
attr_reader :message_type
|
23
|
+
|
24
|
+
# 8, 16, or 32 and specifies whether the data should be viewed
|
25
|
+
# as a list of bytes, shorts, or longs
|
26
|
+
attr_reader :format
|
27
|
+
|
28
|
+
# a union that contains the members b, s, and l. The b, s, and l members
|
29
|
+
# represent data of twenty 8-bit values, ten 16-bit values,
|
30
|
+
# and five 32-bit values
|
31
|
+
attr_reader :data
|
32
|
+
|
33
|
+
def initialize display, raw
|
34
|
+
super
|
35
|
+
@serial = raw.serial
|
36
|
+
@send_event = (raw.send_event != 0)
|
37
|
+
@display = display
|
38
|
+
@window = Window.new display, raw.window
|
39
|
+
@message_type = Atom.new display, raw.message_type
|
40
|
+
@format = raw.message_type
|
41
|
+
@data = raw.data
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# -*- coding:utf-8; mode:ruby; -*-
|
2
|
+
|
3
|
+
module ActiveWindowX
|
4
|
+
|
5
|
+
# binding for Display on X11
|
6
|
+
class Display
|
7
|
+
|
8
|
+
# raw class of Display
|
9
|
+
attr_reader :raw
|
10
|
+
|
11
|
+
# a boolean which be true if this display was closed
|
12
|
+
attr_reader :closed
|
13
|
+
alias :closed? :closed
|
14
|
+
|
15
|
+
def initialize arg=nil
|
16
|
+
@raw =
|
17
|
+
if arg.nil? or arg.kind_of? String
|
18
|
+
Xlib::x_open_display arg
|
19
|
+
elsif arg.kind_of? Xlib::Display
|
20
|
+
arg
|
21
|
+
else
|
22
|
+
raise ArgumentError, 'expect nil, String or Xlib::Display'
|
23
|
+
end
|
24
|
+
@closed = false
|
25
|
+
@root_window = nil
|
26
|
+
@cache = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def close
|
30
|
+
Xlib::x_close_display @raw
|
31
|
+
@closed = true
|
32
|
+
end
|
33
|
+
|
34
|
+
def root_window
|
35
|
+
@root_window ||= RootWindow.new(self, Xlib::default_root_window(@raw))
|
36
|
+
end
|
37
|
+
|
38
|
+
# return IO to select and poll a XEvent with timeout
|
39
|
+
def connection
|
40
|
+
@conn ||= IO.new(Xlib::connection_number @raw)
|
41
|
+
end
|
42
|
+
|
43
|
+
# return the number of events that have been received from the X server
|
44
|
+
def pending
|
45
|
+
Xlib::x_pending @raw
|
46
|
+
end
|
47
|
+
|
48
|
+
def active_window
|
49
|
+
root_window.active_window
|
50
|
+
end
|
51
|
+
|
52
|
+
def intern_atom name
|
53
|
+
if @cache.has_key? name
|
54
|
+
@cache[name]
|
55
|
+
else
|
56
|
+
@cache[name] = Xlib::x_intern_atom @raw, name, false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def atom_name id
|
61
|
+
if @cache.has_key? id
|
62
|
+
@cache[id]
|
63
|
+
else
|
64
|
+
@cache[id] = Xlib::x_get_atom_name @raw, id
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def next_event
|
69
|
+
xevent = Xlib::x_next_event @raw
|
70
|
+
|
71
|
+
case xevent.type
|
72
|
+
when Xlib::PropertyNotify; PropertyEvent.new self, xevent
|
73
|
+
when Xlib::ClientMessage; ClientMessageEvent.new self, xevent
|
74
|
+
else Event.new self, xevent
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# -*- coding:utf-8; mode:ruby; -*-
|
2
|
+
|
3
|
+
module ActiveWindowX
|
4
|
+
|
5
|
+
# listen event changing active window
|
6
|
+
class EventListener
|
7
|
+
|
8
|
+
DEFAULT_TIMEOUT = 0.5
|
9
|
+
|
10
|
+
# current active window
|
11
|
+
attr_reader :active_window
|
12
|
+
|
13
|
+
# true if #start loop continued
|
14
|
+
# false if #start loop did not continue
|
15
|
+
# nil if #start loop was not started
|
16
|
+
# set false if you want to terminate #start loop when next timeout or event receiving
|
17
|
+
attr_accessor :continue
|
18
|
+
|
19
|
+
def initialize name=nil, timeout=DEFAULT_TIMEOUT, &block
|
20
|
+
@display = Display.new name
|
21
|
+
@default_timeout = timeout
|
22
|
+
|
23
|
+
@root = @display.root_window
|
24
|
+
@aw_atom = Atom.new @display, '_NET_ACTIVE_WINDOW'
|
25
|
+
@name_atom = Atom.new @display, 'WM_NAME'
|
26
|
+
@delete_atom = Atom.new @display, 'WM_DELETE_WINDOW'
|
27
|
+
@conn = @display.connection
|
28
|
+
@active_window = @root.active_window
|
29
|
+
|
30
|
+
@active_window.select_input Xlib::PropertyChangeMask if @active_window
|
31
|
+
@root.select_input Xlib::PropertyChangeMask
|
32
|
+
|
33
|
+
if block_given?
|
34
|
+
start @default_timeout, &block
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# event listener loop
|
39
|
+
#
|
40
|
+
# ActiveWindowX::EventListener.new.start do |e|
|
41
|
+
# puts e.type, e.window.id
|
42
|
+
# end
|
43
|
+
def start timeout=@default_timeout
|
44
|
+
|
45
|
+
if not block_given?
|
46
|
+
raise ArgumentError, 'expect to give a block'
|
47
|
+
end
|
48
|
+
|
49
|
+
@continue = true
|
50
|
+
begin
|
51
|
+
while @continue
|
52
|
+
event = listen timeout
|
53
|
+
next if not event
|
54
|
+
|
55
|
+
if window_closed?(event.window)
|
56
|
+
event.window = @root.active_window
|
57
|
+
end
|
58
|
+
yield event if event.type
|
59
|
+
end
|
60
|
+
ensure
|
61
|
+
destroy
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def destroy
|
66
|
+
@display.close if @display.closed?
|
67
|
+
end
|
68
|
+
|
69
|
+
# receive a event
|
70
|
+
#
|
71
|
+
# return value:
|
72
|
+
# a ActiveWindowX::EventListener::Event if an event was send within _timeout_ sec
|
73
|
+
# nil if timeout
|
74
|
+
def listen timeout=nil
|
75
|
+
if @display.pending == 0 and
|
76
|
+
select([@conn], [], [], timeout) == nil
|
77
|
+
# ope on timeout
|
78
|
+
return nil
|
79
|
+
end
|
80
|
+
|
81
|
+
type = nil
|
82
|
+
active_window = nil
|
83
|
+
|
84
|
+
event = @display.next_event
|
85
|
+
if event.atom == @aw_atom
|
86
|
+
type = :active_window
|
87
|
+
active_window = @root.active_window
|
88
|
+
elsif event.atom == @name_atom
|
89
|
+
type = :title
|
90
|
+
active_window = event.window
|
91
|
+
end
|
92
|
+
|
93
|
+
if type == :active_window and @active_window != active_window
|
94
|
+
@active_window.select_input(Xlib::NoEventMask) if @active_window
|
95
|
+
@active_window = active_window
|
96
|
+
@active_window.select_input(Xlib::PropertyChangeMask) if @active_window
|
97
|
+
end
|
98
|
+
|
99
|
+
Event.new type, active_window
|
100
|
+
end
|
101
|
+
|
102
|
+
def window_closed? w
|
103
|
+
return false if w.nil?
|
104
|
+
begin
|
105
|
+
w.prop_raw 'WM_STATE'
|
106
|
+
false
|
107
|
+
rescue Xlib::XErrorEvent
|
108
|
+
true
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class Event
|
113
|
+
attr_accessor :type, :window
|
114
|
+
def initialize type, window
|
115
|
+
@type = type; @window = window
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# -*- coding:utf-8; mode:ruby; -*-
|
2
|
+
|
3
|
+
module ActiveWindowX
|
4
|
+
|
5
|
+
# binding for XPropertyEvent on X11
|
6
|
+
class PropertyEvent < Event
|
7
|
+
|
8
|
+
# the number of last request processed by server
|
9
|
+
attr_reader :serial
|
10
|
+
|
11
|
+
# true if this came from a SendEvent request
|
12
|
+
attr_reader :send_event
|
13
|
+
|
14
|
+
# Display the event was read from
|
15
|
+
attr_reader :display
|
16
|
+
|
17
|
+
# the window whose associated property was changed
|
18
|
+
attr_reader :window
|
19
|
+
|
20
|
+
# the property's atom and indicates which property was changed or desired
|
21
|
+
attr_reader :atom
|
22
|
+
|
23
|
+
# the server time when the property was changed
|
24
|
+
attr_reader :time
|
25
|
+
|
26
|
+
# * PropertyNewValue when a property of the window is changed using
|
27
|
+
# XChangeProperty or XRotateWindowProperties (even when adding zero-length
|
28
|
+
# data using XChangeProperty) and when replacing all or part of a property
|
29
|
+
# with identical data using XChangeProperty or XRotateWindowProperties.
|
30
|
+
# * PropertyDelete when a property of the window is deleted using
|
31
|
+
# XDeleteProperty or, if the delete argument is True, XGetWindowProperty
|
32
|
+
attr_reader :state
|
33
|
+
|
34
|
+
def initialize display, raw
|
35
|
+
super
|
36
|
+
@serial = raw.serial
|
37
|
+
@send_event = (raw.send_event != 0)
|
38
|
+
@display = display
|
39
|
+
@window = Window.new display, raw.window
|
40
|
+
@atom = Atom.new display, raw.atom
|
41
|
+
@time = raw.time
|
42
|
+
@state = raw.state
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- coding:utf-8; mode:ruby; -*-
|
2
|
+
|
3
|
+
require "active_window_x/window"
|
4
|
+
|
5
|
+
module ActiveWindowX
|
6
|
+
|
7
|
+
# binding for a root Window on X11
|
8
|
+
class RootWindow < Window
|
9
|
+
|
10
|
+
def active_window
|
11
|
+
prop_val = prop '_NET_ACTIVE_WINDOW'
|
12
|
+
if prop_val.nil? or prop_val.first == Xlib::None
|
13
|
+
nil
|
14
|
+
else
|
15
|
+
Window.new(@display, prop_val.first)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# -*- coding:utf-8; mode:ruby; -*-
|
2
|
+
|
3
|
+
module ActiveWindowX
|
4
|
+
|
5
|
+
# binding for Window on X11
|
6
|
+
class Window < Xid
|
7
|
+
|
8
|
+
# a buffer for #x_get_window_property
|
9
|
+
READ_BUFF_LENGTH = 1024
|
10
|
+
|
11
|
+
def x_query_tree
|
12
|
+
Xlib::x_query_tree @display.raw, @id
|
13
|
+
end
|
14
|
+
|
15
|
+
# a return value of XQueryTree
|
16
|
+
# which is the root window for a display contains this window
|
17
|
+
def root
|
18
|
+
(r = x_query_tree[0]) and Window.new(@display, r)
|
19
|
+
end
|
20
|
+
|
21
|
+
# a return value of XQueryTree
|
22
|
+
# which is nil, if this window is RootWindow, or a Window.
|
23
|
+
def parent
|
24
|
+
(r = x_query_tree[1]) and Window.new(@display, r)
|
25
|
+
end
|
26
|
+
|
27
|
+
# a return value of XQueryTree
|
28
|
+
# which is an Array of Window
|
29
|
+
def children
|
30
|
+
x_query_tree[2].map{|w| Window.new(@display, w)}
|
31
|
+
end
|
32
|
+
|
33
|
+
# window title (current web page title in browser, current command or dir in terminal app, etc.)
|
34
|
+
def title
|
35
|
+
title = prop('_NET_WM_NAME')
|
36
|
+
title or prop('WM_NAME')
|
37
|
+
end
|
38
|
+
|
39
|
+
# window name (terminal, google-chrome, etc.)
|
40
|
+
def app_name
|
41
|
+
val = app_class_prop
|
42
|
+
val and val[0]
|
43
|
+
end
|
44
|
+
|
45
|
+
# window class (Terminal, Google-chrome, etc.)
|
46
|
+
# TODO write the difference of app_name and app_class
|
47
|
+
def app_class
|
48
|
+
val = app_class_prop
|
49
|
+
val and val[1]
|
50
|
+
end
|
51
|
+
|
52
|
+
def app_class_prop
|
53
|
+
val = prop('WM_CLASS')
|
54
|
+
val and val.split("\0")
|
55
|
+
end
|
56
|
+
|
57
|
+
def pid
|
58
|
+
val = prop('_NET_WM_PID')
|
59
|
+
val and val.first
|
60
|
+
end
|
61
|
+
|
62
|
+
def command
|
63
|
+
id = pid
|
64
|
+
return nil if id.nil?
|
65
|
+
|
66
|
+
path = "/proc/#{id}/cmdline"
|
67
|
+
return nil unless File.readable_real? path
|
68
|
+
|
69
|
+
File.read path
|
70
|
+
end
|
71
|
+
|
72
|
+
# window property getter with easy way for XGetWindowProperty
|
73
|
+
# which return nil, if the specified property name does not exist,
|
74
|
+
# a String or a Array of Number
|
75
|
+
def prop atom
|
76
|
+
val, format, nitems = prop_raw atom
|
77
|
+
case format
|
78
|
+
when 32; val.unpack("l!#{nitems}")
|
79
|
+
when 16; val.unpack("s#{nitems}")
|
80
|
+
when 8; val[0, nitems]
|
81
|
+
when 0; nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# window property getter with easy way for XGetWindowProperty
|
86
|
+
# which return [propety_value, format, number_of_items]
|
87
|
+
def prop_raw atom
|
88
|
+
if atom.kind_of?(Numeric) or atom.kind_of?(String)
|
89
|
+
atom = Atom.new @display, atom
|
90
|
+
elsif not atom.kind_of? Atom
|
91
|
+
raise ArgumentError, "expect Numeric, String or #{Atom.name}"
|
92
|
+
end
|
93
|
+
actual_type, actual_format, nitems, bytes_after, val =
|
94
|
+
Xlib::x_get_window_property @display.raw, @id, atom.id, 0, READ_BUFF_LENGTH, false, Xlib::AnyPropertyType
|
95
|
+
return [val, actual_format, nitems]
|
96
|
+
end
|
97
|
+
|
98
|
+
# Array of the property atom ID(Numeric) list for this window
|
99
|
+
def prop_atom_ids
|
100
|
+
r = Xlib::x_list_properties @display.raw, @id
|
101
|
+
r.nil? ? [] : r
|
102
|
+
end
|
103
|
+
|
104
|
+
# Array of the property atom list for this window
|
105
|
+
def prop_atoms
|
106
|
+
prop_atom_ids.map{|i| Atom.new @display, i}
|
107
|
+
end
|
108
|
+
|
109
|
+
def select_input mask
|
110
|
+
Xlib::x_select_input @display.raw, @id, mask
|
111
|
+
end
|
112
|
+
|
113
|
+
def set_wm_protocols msgs
|
114
|
+
atoms =
|
115
|
+
if msgs.kind_of? Atom then [msgs.id]
|
116
|
+
elsif msgs.kind_of? Array then msgs.map {|m| m.id }
|
117
|
+
else raise ArgumentError, 'expect Atom or Array of Atom'
|
118
|
+
end
|
119
|
+
Xlib::x_set_wm_protocols @display.raw, @id, atoms
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- coding:utf-8; mode:ruby; -*-
|
2
|
+
|
3
|
+
module ActiveWindowX
|
4
|
+
|
5
|
+
# binding for XID on X11
|
6
|
+
class Xid
|
7
|
+
# a display which has this XID
|
8
|
+
attr_reader :display
|
9
|
+
|
10
|
+
# raw XID (#define Window unsinged long)
|
11
|
+
attr_reader :id
|
12
|
+
|
13
|
+
def initialize display, id
|
14
|
+
if display.kind_of? Display
|
15
|
+
@display = display
|
16
|
+
elsif display.kind_of? Xlib::Display
|
17
|
+
@display = Display.new display
|
18
|
+
else
|
19
|
+
raise ArgumentError, "expect #{Display.name} or #{Xlib::Display.name}"
|
20
|
+
end
|
21
|
+
@id ||= id
|
22
|
+
end
|
23
|
+
|
24
|
+
def == xid
|
25
|
+
xid.kind_of?(Xid) and (xid.id == @id)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- coding:undecided-unix; mode:ruby; -*-
|
2
|
+
|
3
|
+
require "active_window_x/version"
|
4
|
+
require "active_window_x/xlib"
|
5
|
+
require "active_window_x/display"
|
6
|
+
require "active_window_x/xid"
|
7
|
+
require "active_window_x/window"
|
8
|
+
require "active_window_x/root_window"
|
9
|
+
require "active_window_x/atom"
|
10
|
+
require "active_window_x/event"
|
11
|
+
require "active_window_x/property_event"
|
12
|
+
require "active_window_x/client_message_event"
|
13
|
+
require "active_window_x/event_listener"
|
14
|
+
|
15
|
+
module ActiveWindowX
|
16
|
+
module Xlib; end
|
17
|
+
|
18
|
+
class Display; end
|
19
|
+
|
20
|
+
class XID; end
|
21
|
+
class Window < Xid; end
|
22
|
+
class RootWindow < Window; end
|
23
|
+
class Atom < Xid; end
|
24
|
+
|
25
|
+
class Event; end
|
26
|
+
class PropertyEvent < Event; end
|
27
|
+
class ClientMessageEvent < Event; end
|
28
|
+
|
29
|
+
class EventListener; end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# dump all properties of window on changing active window
|
2
|
+
|
3
|
+
require 'active_window_x'
|
4
|
+
|
5
|
+
@listener = ActiveWindowX::EventListener.new
|
6
|
+
|
7
|
+
# when pressing Ctrl-C
|
8
|
+
trap :INT do
|
9
|
+
@listener.destroy
|
10
|
+
exit true
|
11
|
+
end
|
12
|
+
|
13
|
+
@listener.start do |e|
|
14
|
+
next until e.window
|
15
|
+
|
16
|
+
w = e.window
|
17
|
+
puts <<__OUTPUT__ if e.type == :active_window
|
18
|
+
######### change active window #########
|
19
|
+
id: #{w.id}
|
20
|
+
title: #{w.title}
|
21
|
+
name: #{w.app_name}
|
22
|
+
class: #{w.app_class}
|
23
|
+
pid: #{w.pid}
|
24
|
+
command: #{w.command}
|
25
|
+
__OUTPUT__
|
26
|
+
puts <<__OUTPUT__ if e.type == :title
|
27
|
+
######### change title #########
|
28
|
+
title: #{w.title}
|
29
|
+
__OUTPUT__
|
30
|
+
end
|
data/sample/simple.rb
ADDED
data/spec/atom_spec.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- coding:utf-8; mode:ruby; -*-
|
2
|
+
|
3
|
+
require 'active_window_x'
|
4
|
+
|
5
|
+
include ActiveWindowX
|
6
|
+
|
7
|
+
describe Atom do
|
8
|
+
before do
|
9
|
+
@raw_display = mock Xlib::Display
|
10
|
+
@display = mock Display
|
11
|
+
@display.stub(:raw){@raw_display}
|
12
|
+
@display.stub(:kind_of?).with(Display).and_return(true)
|
13
|
+
@id = 123
|
14
|
+
@atom = Atom.new @display, @id
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#name' do
|
18
|
+
before do
|
19
|
+
@name = 'FOOO'
|
20
|
+
@display.should_receive(:atom_name).twice.with(@id).and_return(@name)
|
21
|
+
end
|
22
|
+
it 'should return a String as an atom name' do
|
23
|
+
@atom.name.should == @name
|
24
|
+
@atom.name.should == @name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# -*- coding:utf-8; mode:ruby; -*-
|
2
|
+
|
3
|
+
require 'active_window_x'
|
4
|
+
|
5
|
+
include ActiveWindowX
|
6
|
+
|
7
|
+
describe Display do
|
8
|
+
before do
|
9
|
+
@display_raw = mock Xlib::Display
|
10
|
+
Xlib.stub(:x_open_display).and_return(@display_raw)
|
11
|
+
@display = Display.new nil
|
12
|
+
@root_id = 9999
|
13
|
+
Xlib.stub(:default_root_window).with(@display_raw).and_return(@root_id)
|
14
|
+
Xlib.stub(:x_select_input).and_return(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#root_window' do
|
18
|
+
it 'should return the root window' do
|
19
|
+
r = @display.root_window
|
20
|
+
r.id.should == @root_id
|
21
|
+
r.should be_a RootWindow
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#next_event' do
|
26
|
+
before do
|
27
|
+
@root = @display.root_window
|
28
|
+
@root.select_input Xlib::PropertyChangeMask
|
29
|
+
@event = mock Xlib::XPropertyEvent
|
30
|
+
@event.stub(:type){@type}
|
31
|
+
@event.stub(:serial){1000}
|
32
|
+
@event.stub(:send_event){0}
|
33
|
+
@event.stub(:time){2000}
|
34
|
+
@event.stub(:state){nil}
|
35
|
+
@window_id = 222
|
36
|
+
@event.stub(:window){@window_id}
|
37
|
+
@atom_id = 333
|
38
|
+
@event.stub(:atom){@atom_id}
|
39
|
+
Xlib.should_receive(:x_next_event).and_return(@event)
|
40
|
+
end
|
41
|
+
context 'with PropertyChangeMask' do
|
42
|
+
before do
|
43
|
+
@type = Xlib::PropertyNotify
|
44
|
+
end
|
45
|
+
it 'should return a PropertyEvent' do
|
46
|
+
ev = @display.next_event
|
47
|
+
ev.type.should == @event.type
|
48
|
+
ev.window.id.should == @event.window
|
49
|
+
ev.atom.id.should == @event.atom
|
50
|
+
end
|
51
|
+
end
|
52
|
+
context 'with other event type' do
|
53
|
+
before do
|
54
|
+
@type = 0
|
55
|
+
end
|
56
|
+
it 'should return a PropertyEvent' do
|
57
|
+
ev = @display.next_event
|
58
|
+
ev.type.should == @event.type
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|