x_do 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.project +17 -0
- data/.rspec +1 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +31 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +27 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/lib/x_do.rb +13 -0
- data/lib/x_do/context.rb +101 -0
- data/lib/x_do/ffi_autogen.rb +37 -0
- data/lib/x_do/ffi_functions.rb +63 -0
- data/lib/x_do/ffi_lib.rb +45 -0
- data/lib/x_do/ffi_lib_ext.rb +62 -0
- data/lib/x_do/keyboard.rb +51 -0
- data/lib/x_do/mouse.rb +85 -0
- data/lib/x_do/window.rb +182 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/stdlib.rb +2 -0
- data/spec/x_do/context_spec.rb +127 -0
- data/spec/x_do/ffi_lib_ext_spec.rb +126 -0
- data/spec/x_do/keyboard_spec.rb +32 -0
- data/spec/x_do/mouse_spec.rb +53 -0
- data/spec/x_do/window_spec.rb +141 -0
- data/tasks/ffi_codegen.rb +108 -0
- metadata +252 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
# Extensions to the structures in ffi_lib.
|
2
|
+
|
3
|
+
# :nodoc: namespace
|
4
|
+
class XDo
|
5
|
+
|
6
|
+
# :nodoc: namespace
|
7
|
+
module FFILib
|
8
|
+
|
9
|
+
# :nodoc: extending with better constructor
|
10
|
+
class XDoSearch
|
11
|
+
# Creates an XDoSearch structure from options passed to XDo#find_window.
|
12
|
+
def self.from_options(options = {})
|
13
|
+
search = self.new
|
14
|
+
search[:max_depth] = (options[:depth] || -1).to_i
|
15
|
+
|
16
|
+
# SEARCH_ANY vs SEARCH_ALL in xdo.h
|
17
|
+
search[:require] = (options[:require] == :any) ? 0 : 1
|
18
|
+
|
19
|
+
search[:searchmask] = 0
|
20
|
+
[
|
21
|
+
[:title, :title, XDo::FFILib::Consts::SEARCH_TITLE],
|
22
|
+
[:name, :winname, XDo::FFILib::Consts::SEARCH_NAME],
|
23
|
+
[:class, :winclass, XDo::FFILib::Consts::SEARCH_CLASS],
|
24
|
+
[:class_name, :winclassname, XDo::FFILib::Consts::SEARCH_CLASSNAME]
|
25
|
+
].each do |option, struct_key, bit|
|
26
|
+
if options[option]
|
27
|
+
search[:searchmask] |= bit
|
28
|
+
|
29
|
+
c_string = FFI::MemoryPointer.new options[option].length + 1
|
30
|
+
c_string.put_string 0, options[option]
|
31
|
+
search[struct_key] = c_string
|
32
|
+
else
|
33
|
+
search[struct_key] = nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
if options[:visible]
|
38
|
+
search[:searchmask] |= XDo::FFILib::Consts::SEARCH_ONLYVISIBLE
|
39
|
+
search[:only_visible] = 1
|
40
|
+
else
|
41
|
+
search[:only_visible] = 0
|
42
|
+
end
|
43
|
+
|
44
|
+
[
|
45
|
+
[:pid, :pid, XDo::FFILib::Consts::SEARCH_PID],
|
46
|
+
[:screen, :screen, XDo::FFILib::Consts::SEARCH_SCREEN]
|
47
|
+
].each do |option, struct_key, bit|
|
48
|
+
if options[option]
|
49
|
+
search[:searchmask] |= bit
|
50
|
+
search[struct_key] = options[option].to_i
|
51
|
+
else
|
52
|
+
search[struct_key] = 0
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
search
|
57
|
+
end
|
58
|
+
end # class XDo::FFILib::XDoSearch
|
59
|
+
|
60
|
+
end # module XDo::FFILib
|
61
|
+
|
62
|
+
end # namespace XDo
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
class XDo
|
3
|
+
|
4
|
+
# The keyboard state for a libxdo context.
|
5
|
+
class Keyboard
|
6
|
+
# Creates a keyboard state wrapper for an XDo context.
|
7
|
+
#
|
8
|
+
# This constructor is called internally by XDo#keyboard and client code
|
9
|
+
# should not need to call it directly.
|
10
|
+
#
|
11
|
+
# Args:
|
12
|
+
# xdo:: the XDo wrapping a libxdo context
|
13
|
+
def initialize(xdo)
|
14
|
+
@xdo = xdo
|
15
|
+
@_xdo_pointer = xdo._pointer
|
16
|
+
end
|
17
|
+
|
18
|
+
# The XDo context that produced the window.
|
19
|
+
attr_accessor :xdo
|
20
|
+
|
21
|
+
# Types a string into the current window.
|
22
|
+
def type_string(string, delay = 0.12)
|
23
|
+
XDo::FFILib.xdo_type @_xdo_pointer, 0, string, (delay * 100_000).to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
# Sends a keysequence to this window.
|
27
|
+
#
|
28
|
+
# Examples: "alt+Return", "Alt_L+Tab", "l", "semicolon"
|
29
|
+
def type_keysequence(keysequence, delay = 0.12)
|
30
|
+
XDo::FFILib.xdo_keysequence @_xdo_pointer, 0, keysequence,
|
31
|
+
(delay * 100_000).to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
# Presses a keysequence in this window.
|
35
|
+
#
|
36
|
+
# Examples: "alt+Return", "Alt_L+Tab", "l", "semicolon"
|
37
|
+
def press_keysequence(keysequence, delay = 0.12)
|
38
|
+
XDo::FFILib.xdo_keysequence_down @_xdo_pointer, 0, keysequence,
|
39
|
+
(delay * 100_000).to_i
|
40
|
+
end
|
41
|
+
|
42
|
+
# Releases a keysequence in this window.
|
43
|
+
#
|
44
|
+
# Examples: "alt+Return", "Alt_L+Tab", "l", "semicolon"
|
45
|
+
def release_keysequence(keysequence, delay = 0.12)
|
46
|
+
XDo::FFILib.xdo_keysequence_up @_xdo_pointer, 0, keysequence,
|
47
|
+
(delay * 100_000).to_i
|
48
|
+
end
|
49
|
+
end # class XDo::Keyboard
|
50
|
+
|
51
|
+
end # namespace XDo
|
data/lib/x_do/mouse.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
class XDo
|
3
|
+
|
4
|
+
# The mouse state for a libxdo context.
|
5
|
+
class Mouse
|
6
|
+
# Creates a mouse state wrapper for an XDo context.
|
7
|
+
#
|
8
|
+
# This constructor is called internally by XDo#mouse and client code
|
9
|
+
# should not need to call it directly.
|
10
|
+
#
|
11
|
+
# Args:
|
12
|
+
# xdo:: the XDo wrapping a libxdo context
|
13
|
+
def initialize(xdo)
|
14
|
+
@xdo = xdo
|
15
|
+
@_xdo_pointer = xdo._pointer
|
16
|
+
end
|
17
|
+
|
18
|
+
# The XDo context that produced the window.
|
19
|
+
attr_accessor :xdo
|
20
|
+
|
21
|
+
# [x, y, screen] array of mouse coordinates.
|
22
|
+
def location
|
23
|
+
x_pointer = FFI::MemoryPointer.new :int, 1
|
24
|
+
y_pointer = FFI::MemoryPointer.new :int, 1
|
25
|
+
screen_pointer = FFI::MemoryPointer.new :int, 1
|
26
|
+
XDo::FFILib.xdo_mouselocation @_xdo_pointer, x_pointer, y_pointer,
|
27
|
+
screen_pointer
|
28
|
+
[x_pointer.read_int, y_pointer.read_int, screen_pointer.read_int]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Moves the mouse to a new position.
|
32
|
+
def move(x, y, screen)
|
33
|
+
old_location = self.location
|
34
|
+
move_async x, y, screen
|
35
|
+
unless old_location[0, 2] == [x, y]
|
36
|
+
wait_for_move_from old_location[0], old_location[1]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Queues a mouse move request to the X server.
|
41
|
+
def move_async(x, y, screen)
|
42
|
+
XDo::FFILib.xdo_mousemove @_xdo_pointer, x, y, screen
|
43
|
+
end
|
44
|
+
|
45
|
+
# Moves the mouse relatively to its current position.
|
46
|
+
def move_relative(dx, dy)
|
47
|
+
old_location = self.location
|
48
|
+
move_relative_async dx, dy
|
49
|
+
unless dx == 0 && dy == 0
|
50
|
+
wait_for_move_from old_location[0], old_location[1]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Queues a mouse move request to the X server.
|
55
|
+
def move_relative_async(dx, dy)
|
56
|
+
XDo::FFILib.xdo_mousemove_relative @_xdo_pointer, dx, dy
|
57
|
+
end
|
58
|
+
|
59
|
+
# Blocks until the mouse moves away from a position on screen.
|
60
|
+
def wait_for_move_from(x, y)
|
61
|
+
XDo::FFILib.xdo_mouse_wait_for_move_from @_xdo_pointer, x, y
|
62
|
+
end
|
63
|
+
|
64
|
+
# Blocks until the mouse moves to a position on screen.
|
65
|
+
def wait_for_move_to(x, y)
|
66
|
+
XDo::FFILib.xdo_mouse_wait_for_move_to @_xdo_pointer, x, y
|
67
|
+
end
|
68
|
+
|
69
|
+
# Clicks a mouse button.
|
70
|
+
def click(button)
|
71
|
+
XDo::FFILib.xdo_click @_xdo_pointer, 0, button
|
72
|
+
end
|
73
|
+
|
74
|
+
# Presses a mouse button.
|
75
|
+
def press(button)
|
76
|
+
XDo::FFILib.xdo_mousedown @_xdo_pointer, 0, button
|
77
|
+
end
|
78
|
+
|
79
|
+
# Releases a mouse button.
|
80
|
+
def release(button)
|
81
|
+
XDo::FFILib.xdo_mouseup @_xdo_pointer, 0, button
|
82
|
+
end
|
83
|
+
end # class XDo::Mouse
|
84
|
+
|
85
|
+
end # namespace XDo
|
data/lib/x_do/window.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
class XDo
|
3
|
+
|
4
|
+
# Wraps an xdolib Window pointer.
|
5
|
+
class Window
|
6
|
+
# Brings a window forward and gives it focus.
|
7
|
+
def activate
|
8
|
+
XDo::FFILib.xdo_window_activate @_xdo_pointer, @_window
|
9
|
+
end
|
10
|
+
|
11
|
+
# Gives the input focus to a window
|
12
|
+
def focus
|
13
|
+
XDo::FFILib.xdo_window_focus @_xdo_pointer, @_window
|
14
|
+
end
|
15
|
+
|
16
|
+
# Moves the window at the top of the stack, making it visible.
|
17
|
+
def raise
|
18
|
+
XDo::FFILib.xdo_window_raise @_xdo_pointer, @_window
|
19
|
+
end
|
20
|
+
|
21
|
+
# The PID of the process owning the window.
|
22
|
+
def pid
|
23
|
+
XDo::FFILib.xdo_window_get_pid @_xdo_pointer, @_window
|
24
|
+
end
|
25
|
+
|
26
|
+
# [x, y] array containing the window's coordinates.
|
27
|
+
def location
|
28
|
+
x_pointer = FFI::MemoryPointer.new :int, 1
|
29
|
+
y_pointer = FFI::MemoryPointer.new :int, 1
|
30
|
+
XDo::FFILib.xdo_get_window_location @_xdo_pointer, @_window, x_pointer,
|
31
|
+
y_pointer, nil
|
32
|
+
[x_pointer.read_int, y_pointer.read_int]
|
33
|
+
end
|
34
|
+
|
35
|
+
# [width, height] array containing the window's size.
|
36
|
+
def size
|
37
|
+
width_pointer = FFI::MemoryPointer.new :int, 1
|
38
|
+
height_pointer = FFI::MemoryPointer.new :int, 1
|
39
|
+
XDo::FFILib.xdo_get_window_size @_xdo_pointer, @_window, width_pointer,
|
40
|
+
height_pointer
|
41
|
+
[width_pointer.read_int, height_pointer.read_int]
|
42
|
+
end
|
43
|
+
|
44
|
+
def move(x, y)
|
45
|
+
move_raw x, y
|
46
|
+
glitched_location = self.location
|
47
|
+
x_decoration = glitched_location.first - x
|
48
|
+
y_decoration = glitched_location.last - y
|
49
|
+
move_raw x - x_decoration, y - y_decoration
|
50
|
+
end
|
51
|
+
|
52
|
+
# Moves this window to a new position.
|
53
|
+
#
|
54
|
+
# The position is given directly to X, and does not account for window
|
55
|
+
# decorations.
|
56
|
+
def move_raw(x, y)
|
57
|
+
old_location = self.location
|
58
|
+
return_value = move_raw_async x, y
|
59
|
+
100.times do
|
60
|
+
break unless self.location == old_location
|
61
|
+
sleep 0.01
|
62
|
+
end
|
63
|
+
return_value
|
64
|
+
end
|
65
|
+
|
66
|
+
# Asks X to move this window to a new position.
|
67
|
+
def move_raw_async(x, y)
|
68
|
+
XDo::FFILib.xdo_window_move @_xdo_pointer, @_window, x, y
|
69
|
+
end
|
70
|
+
|
71
|
+
# Resizes this window.
|
72
|
+
#
|
73
|
+
# Args:
|
74
|
+
# width:: the new window's width
|
75
|
+
# height:: the new window's height
|
76
|
+
# use_hints:: if false, width and height are specified in pixels; otherwise,
|
77
|
+
# the unit is relative to window size hints
|
78
|
+
def resize(width, height, use_hints = false)
|
79
|
+
old_size = self.size
|
80
|
+
return_value = resize_async width, height, use_hints
|
81
|
+
100.times do
|
82
|
+
break unless self.size == old_size
|
83
|
+
sleep 0.01
|
84
|
+
end
|
85
|
+
return_value
|
86
|
+
end
|
87
|
+
|
88
|
+
# Asks X to resize this window.
|
89
|
+
def resize_async(width, height, use_hints = false)
|
90
|
+
flags = use_hints ? XDo::FFILib::Consts::SIZE_U : 0
|
91
|
+
XDo::FFILib.xdo_window_setsize @_xdo_pointer, @_window, width, height, flags
|
92
|
+
end
|
93
|
+
|
94
|
+
# Moves the mouse in window coordinates.
|
95
|
+
def move_mouse(window_x, window_y)
|
96
|
+
old_location = @xdo.mouse.location
|
97
|
+
move_mouse_async window_x, window_y
|
98
|
+
@xdo.mouse.wait_for_move_from old_location[0], old_location[1]
|
99
|
+
end
|
100
|
+
|
101
|
+
# Moves the mouse in window coordinates.
|
102
|
+
def move_mouse_async(window_x, window_y)
|
103
|
+
XDo::FFILib.xdo_mousemove_relative_to_window @_xdo_pointer, @_window,
|
104
|
+
window_x, window_y
|
105
|
+
end
|
106
|
+
|
107
|
+
# Clicks a mouse button.
|
108
|
+
def click_mouse(button)
|
109
|
+
XDo::FFILib.xdo_click @_xdo_pointer, @_window, button
|
110
|
+
end
|
111
|
+
|
112
|
+
# Presses a mouse button.
|
113
|
+
def press_mouse(button)
|
114
|
+
XDo::FFILib.xdo_mousedown @_xdo_pointer, @_window, button
|
115
|
+
end
|
116
|
+
|
117
|
+
# Releases a mouse button.
|
118
|
+
def release_mouse(button)
|
119
|
+
XDo::FFILib.xdo_mouseup @_xdo_pointer, @_window, button
|
120
|
+
end
|
121
|
+
|
122
|
+
# Types a string into this window.
|
123
|
+
def type_string(string, delay = 0.12)
|
124
|
+
XDo::FFILib.xdo_type @_xdo_pointer, @_window, string, (delay * 100_000).to_i
|
125
|
+
end
|
126
|
+
|
127
|
+
# Sends a keysequence to this window.
|
128
|
+
#
|
129
|
+
# Examples: "alt+Return", "Alt_L+Tab", "l", "semicolon"
|
130
|
+
def type_keysequence(keysequence, delay = 0.12)
|
131
|
+
XDo::FFILib.xdo_keysequence @_xdo_pointer, @_window, keysequence,
|
132
|
+
(delay * 100_000).to_i
|
133
|
+
end
|
134
|
+
|
135
|
+
# Presses a keysequence in this window.
|
136
|
+
#
|
137
|
+
# Examples: "alt+Return", "Alt_L+Tab", "l", "semicolon"
|
138
|
+
def press_keysequence(keysequence, delay = 0.12)
|
139
|
+
XDo::FFILib.xdo_keysequence_down @_xdo_pointer, @_window, keysequence,
|
140
|
+
(delay * 100_000).to_i
|
141
|
+
end
|
142
|
+
|
143
|
+
# Releases a keysequence in this window.
|
144
|
+
#
|
145
|
+
# Examples: "alt+Return", "Alt_L+Tab", "l", "semicolon"
|
146
|
+
def release_keysequence(keysequence, delay = 0.12)
|
147
|
+
XDo::FFILib.xdo_keysequence_up @_xdo_pointer, @_window, keysequence,
|
148
|
+
(delay * 100_000).to_i
|
149
|
+
end
|
150
|
+
|
151
|
+
# Creates a wrapper for an X Window handle.
|
152
|
+
#
|
153
|
+
# This constructor is called internally by XDo#find_windows and client code
|
154
|
+
# should not need to call it directly.
|
155
|
+
#
|
156
|
+
# Args:
|
157
|
+
# xdo:: the XDo wrapping the libxdo context used to get this Window
|
158
|
+
# _window:: the X Window handle to be wrapped
|
159
|
+
def initialize(xdo, _window)
|
160
|
+
@xdo = xdo
|
161
|
+
@_xdo_pointer = xdo._pointer
|
162
|
+
@_window = _window
|
163
|
+
end
|
164
|
+
|
165
|
+
# The XDo context that produced the window.
|
166
|
+
attr_accessor :xdo
|
167
|
+
|
168
|
+
# The underlying X Window handle.
|
169
|
+
attr_accessor :_window
|
170
|
+
|
171
|
+
# :nodoc: underlying window handle should impact equality
|
172
|
+
def ==(other)
|
173
|
+
other.kind_of?(XDo::Window) && @_window == other._window
|
174
|
+
end
|
175
|
+
|
176
|
+
# :nodoc: override hash to match ==
|
177
|
+
def hash
|
178
|
+
_window.hash
|
179
|
+
end
|
180
|
+
end # class XDo::Window
|
181
|
+
|
182
|
+
end # namespace XDo
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'x_do'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '../../spec_helper')
|
2
|
+
|
3
|
+
describe XDo do
|
4
|
+
describe 'with no display specification' do
|
5
|
+
let(:xdo) { XDo.new }
|
6
|
+
|
7
|
+
it 'should use the value of $DISPLAY' do
|
8
|
+
xdo.display_name.should == ENV['DISPLAY']
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'after close' do
|
12
|
+
before { xdo.close }
|
13
|
+
|
14
|
+
it 'should not accept method calls' do
|
15
|
+
lambda {
|
16
|
+
xdo.display_name
|
17
|
+
}.should raise_error(NoMethodError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should accept #close without crashing' do
|
21
|
+
lambda {
|
22
|
+
xdo.close
|
23
|
+
}.should_not raise_error
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'find_windows' do
|
29
|
+
let(:xdo) { XDo.new }
|
30
|
+
|
31
|
+
describe 'with .* name pattern' do
|
32
|
+
let(:windows) { xdo.find_windows :name => '.*' }
|
33
|
+
|
34
|
+
it 'should return at least 1 element' do
|
35
|
+
windows.should_not be_empty
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should return same number of windows as xdotool' do
|
39
|
+
windows.length.should == `xdotool search --all --name ".*"`.split.length
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should have a XDo::Window as the first element' do
|
43
|
+
windows.first.should be_kind_of(XDo::Window)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should include the active window' do
|
47
|
+
windows.should include(xdo.active_window)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should include the "real" focused window' do
|
51
|
+
windows.should include(xdo.real_focused_window)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'with no conditions' do
|
56
|
+
let(:windows) { xdo.find_windows }
|
57
|
+
|
58
|
+
it 'should include the active window' do
|
59
|
+
windows.should include(xdo.active_window)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should include the "real" focused window' do
|
63
|
+
windows.should include(xdo.real_focused_window)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should include the focused window' do
|
67
|
+
windows.should include(xdo.focused_window)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'with the current PID' do
|
72
|
+
let(:windows) { xdo.find_windows :pid => $PID }
|
73
|
+
|
74
|
+
it 'should not return any windows for console process' do
|
75
|
+
windows.should be_empty
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'active_window' do
|
81
|
+
let(:xdo) { XDo.new }
|
82
|
+
let(:window) { xdo.active_window }
|
83
|
+
|
84
|
+
it 'should be an XDo::Window' do
|
85
|
+
window.should be_kind_of(XDo::Window)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'focused_window' do
|
90
|
+
let(:xdo) { XDo.new }
|
91
|
+
let(:window) { xdo.focused_window }
|
92
|
+
|
93
|
+
it 'should be an XDo::Window' do
|
94
|
+
window.should be_kind_of(XDo::Window)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe 'mouse' do
|
99
|
+
let(:xdo) { XDo.new }
|
100
|
+
let(:mouse) { xdo.mouse }
|
101
|
+
|
102
|
+
it 'should be an XDo::Mouse' do
|
103
|
+
mouse.should be_kind_of(XDo::Mouse)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'with :0 display name' do
|
108
|
+
let(:display) { ':0'}
|
109
|
+
let(:xdo) { XDo.new display }
|
110
|
+
|
111
|
+
it 'should use given display name' do
|
112
|
+
xdo.display_name.should == display
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'lib_version' do
|
117
|
+
let(:version) { XDo.lib_version }
|
118
|
+
|
119
|
+
it 'should be non-nil' do
|
120
|
+
version.should_not be_nil
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should be non-empty' do
|
124
|
+
version.should_not be_empty
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|