x11_client 0.0.1 → 0.0.2
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/Gemfile +2 -1
- data/README.md +10 -1
- data/ext/x11_client_ext/x11_client_ext.c +3 -0
- data/ext/x11_client_ext/x11_client_window.c +61 -5
- data/ext/x11_client_ext/x11_client_window.h +14 -0
- data/lib/x11_client.rb +28 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/x11_client_spec.rb +48 -0
- data/x11_client.gemspec +1 -1
- metadata +8 -5
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -21,8 +21,11 @@ It can be handy if you want to controll some programs running in Xvfb.
|
|
21
21
|
* X11Client#close_display - explicit close display
|
22
22
|
* X11Client#sync - sync display
|
23
23
|
* X11Client#start(&block) - block execution and yield event attributes for each new event.
|
24
|
-
* X11Client#stop
|
24
|
+
* X11Client#stop - stop blocking loop
|
25
|
+
* X11Client#root_window_id - returns root window id in decimal.
|
26
|
+
* X11Client#root_window - returns root window attributes hash.
|
25
27
|
* X11Client#get_window(window_id) - returns window attributes hash or nil for given window_id.
|
28
|
+
* X11Client#get_window(window_id) - returns window name for given window_id.
|
26
29
|
* X11Client#mousemove(x,y) - move mouse pointer to (x,y) coordinates.
|
27
30
|
* X11Client#mousedown(button) - down mouse buton
|
28
31
|
* X11Client#mouseup(buton) - up mouse button
|
@@ -123,6 +126,12 @@ Supported events:
|
|
123
126
|
|
124
127
|
end
|
125
128
|
|
129
|
+
## Testing
|
130
|
+
|
131
|
+
$ sudo pacman -S xorg-xwininfo
|
132
|
+
$ bundle install
|
133
|
+
$ bundle exec rspec spec
|
134
|
+
|
126
135
|
## References
|
127
136
|
|
128
137
|
* [The Xlib Programming Manual](http://tronche.com/gui/x/xlib/)
|
@@ -25,7 +25,10 @@ void Init_x11_client_ext() {
|
|
25
25
|
rb_define_method(cX11Client, "start", X11Client_start, 0);
|
26
26
|
rb_define_method(cX11Client, "stop", X11Client_stop, 0);
|
27
27
|
|
28
|
+
rb_define_method(cX11Client, "root_window_id", X11Client_root_window_id, 0);
|
29
|
+
rb_define_method(cX11Client, "window_children_ids", X11Client_window_children_ids, 1);
|
28
30
|
rb_define_method(cX11Client, "get_window", X11Client_get_window, 1);
|
31
|
+
rb_define_method(cX11Client, "get_window_name", X11Client_get_window_name, 1);
|
29
32
|
|
30
33
|
rb_define_method(cX11Client, "mousemove", X11Client_mousemove, 2);
|
31
34
|
rb_define_method(cX11Client, "mousedown", X11Client_mousedown, 1);
|
@@ -4,6 +4,13 @@
|
|
4
4
|
|
5
5
|
#include "X11/Xutil.h"
|
6
6
|
|
7
|
+
VALUE X11Client_root_window_id(VALUE self) {
|
8
|
+
X11Client *client;
|
9
|
+
Data_Get_Struct(self, X11Client, client);
|
10
|
+
|
11
|
+
return LONG2FIX(DefaultRootWindow(client->display));
|
12
|
+
}
|
13
|
+
|
7
14
|
VALUE X11Client_get_window(VALUE self, VALUE window_id) {
|
8
15
|
VALUE result = Qnil;
|
9
16
|
|
@@ -11,7 +18,6 @@ VALUE X11Client_get_window(VALUE self, VALUE window_id) {
|
|
11
18
|
Data_Get_Struct(self, X11Client, client);
|
12
19
|
|
13
20
|
Window window = NUM2LONG(window_id);
|
14
|
-
char* window_name = '\0';
|
15
21
|
XWindowAttributes attributes;
|
16
22
|
XClassHint classhint;
|
17
23
|
|
@@ -27,11 +33,8 @@ VALUE X11Client_get_window(VALUE self, VALUE window_id) {
|
|
27
33
|
rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("border_width"), INT2FIX(attributes.border_width));
|
28
34
|
rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("root_id"), LONG2FIX(attributes.root));
|
29
35
|
rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("state"), X11Client_window_state(attributes));
|
36
|
+
rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("name"), X11Client_get_window_name(self, window_id));
|
30
37
|
|
31
|
-
if (XFetchName(client->display, window, &window_name)) {
|
32
|
-
rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("name"), rb_str_new2(window_name));
|
33
|
-
XFree(window_name);
|
34
|
-
}
|
35
38
|
|
36
39
|
if (XGetClassHint(client->display, window, &classhint)) {
|
37
40
|
rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("class"), rb_str_new2(classhint.res_class));
|
@@ -46,6 +49,59 @@ VALUE X11Client_get_window(VALUE self, VALUE window_id) {
|
|
46
49
|
return result;
|
47
50
|
}
|
48
51
|
|
52
|
+
VALUE X11Client_get_window_name(VALUE self, VALUE window_id) {
|
53
|
+
VALUE result = Qnil;
|
54
|
+
|
55
|
+
X11Client *client;
|
56
|
+
Data_Get_Struct(self, X11Client, client);
|
57
|
+
|
58
|
+
Window window = NUM2LONG(window_id);
|
59
|
+
char* window_name = '\0';
|
60
|
+
XTextProperty wmName;
|
61
|
+
|
62
|
+
if (XFetchName(client->display, window, &window_name)) {
|
63
|
+
result = rb_str_new2(window_name);
|
64
|
+
XFree(window_name);
|
65
|
+
} else {
|
66
|
+
Status status = XGetWMName(client->display, window, &wmName);
|
67
|
+
if(status && wmName.value && wmName.nitems) {
|
68
|
+
int list_size;
|
69
|
+
char **list;
|
70
|
+
status = XmbTextPropertyToTextList(client->display, &wmName, &list, &list_size);
|
71
|
+
if (status >= Success && list_size && *list) {
|
72
|
+
result = rb_str_new2(*list);
|
73
|
+
XFree(list);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
return result;
|
78
|
+
}
|
79
|
+
|
80
|
+
VALUE X11Client_window_children_ids(VALUE self, VALUE window_id) {
|
81
|
+
Window window = NUM2LONG(window_id);
|
82
|
+
Window dummy;
|
83
|
+
Window *children = NULL;
|
84
|
+
unsigned int i, nchildren;
|
85
|
+
|
86
|
+
X11Client *client;
|
87
|
+
Data_Get_Struct(self, X11Client, client);
|
88
|
+
|
89
|
+
XSetErrorHandler(X11Client_IgnoreBadWindowHandler);
|
90
|
+
|
91
|
+
VALUE children_ids = rb_ary_new();
|
92
|
+
if (XQueryTree(client->display, window, &dummy, &dummy, &children, &nchildren)) {
|
93
|
+
for (i = 0; i < nchildren; i++) {
|
94
|
+
Window child_id = children[i];
|
95
|
+
rb_funcall(children_ids, rb_intern("push"), 1, LONG2FIX(child_id));
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
XSetErrorHandler(NULL);
|
100
|
+
|
101
|
+
XFree(children);
|
102
|
+
return children_ids;
|
103
|
+
}
|
104
|
+
|
49
105
|
VALUE X11Client_window_state(XWindowAttributes attributes) {
|
50
106
|
VALUE state = Qnil;
|
51
107
|
switch(attributes.map_state) {
|
@@ -1,3 +1,17 @@
|
|
1
|
+
// returns root window id
|
2
|
+
VALUE X11Client_root_window_id(VALUE self);
|
3
|
+
|
4
|
+
// returns window attributes for specified window id
|
1
5
|
VALUE X11Client_get_window(VALUE self, VALUE window_id);
|
6
|
+
|
7
|
+
// return children window ids for specified window id
|
8
|
+
VALUE X11Client_window_children_ids(VALUE self, VALUE window_id);
|
9
|
+
|
10
|
+
// get window state
|
2
11
|
VALUE X11Client_window_state(XWindowAttributes attributes);
|
12
|
+
|
13
|
+
// get window name for given window id
|
14
|
+
VALUE X11Client_get_window_name(VALUE self, VALUE window_id);
|
15
|
+
|
16
|
+
// handler that ignores BadWindow error
|
3
17
|
int X11Client_IgnoreBadWindowHandler(Display *display, XErrorEvent *error);
|
data/lib/x11_client.rb
CHANGED
@@ -1,4 +1,32 @@
|
|
1
1
|
require "x11_client_ext"
|
2
2
|
|
3
3
|
class X11Client
|
4
|
+
def window_children(window_id)
|
5
|
+
window_children_ids(window_id).map do |child_id|
|
6
|
+
get_window(child_id)
|
7
|
+
end.compact
|
8
|
+
end
|
9
|
+
|
10
|
+
def window_descendants(window_id)
|
11
|
+
windows = []
|
12
|
+
ids = [window_id]
|
13
|
+
until ids.empty?
|
14
|
+
window = get_window(ids.shift)
|
15
|
+
windows << window
|
16
|
+
ids += window_children_ids(window['id'])
|
17
|
+
end
|
18
|
+
windows
|
19
|
+
end
|
20
|
+
|
21
|
+
def root_window
|
22
|
+
get_window(root_window_id)
|
23
|
+
end
|
24
|
+
|
25
|
+
def root_window_children
|
26
|
+
window_children(root_window_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
def root_window_descendants
|
30
|
+
window_descendants(root_window_id)
|
31
|
+
end
|
4
32
|
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'x11_client'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe X11Client do
|
4
|
+
let(:client) { described_class.new(ENV['DISPLAY']) }
|
5
|
+
|
6
|
+
let(:root_window_id) { `xwininfo -root -int | grep "Window id:"`.scan(/\d+/).first.to_i }
|
7
|
+
|
8
|
+
let(:root_window_children_ids) do
|
9
|
+
ids = []
|
10
|
+
`xwininfo -root -int -children`.split("\n").each do |line|
|
11
|
+
next if line =~ /\d+\s+children:/
|
12
|
+
line =~ /^\s*(\d+)/ and ids.push($1.to_i)
|
13
|
+
end
|
14
|
+
ids
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#root_window_id" do
|
18
|
+
it "should be root window integer" do
|
19
|
+
root_window_id.should_not be_zero
|
20
|
+
client.root_window_id.should == root_window_id
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#root_window" do
|
25
|
+
it "should return hash of root window attributes" do
|
26
|
+
window = client.root_window
|
27
|
+
window.should be_kind_of(Hash)
|
28
|
+
window['id'].should == root_window_id
|
29
|
+
window['root_id'].should == root_window_id
|
30
|
+
window['x'].should == 0
|
31
|
+
window['y'].should == 0
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#window_children" do
|
36
|
+
it "should return empty array if window does not exists" do
|
37
|
+
client.window_children(0).should == []
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return root window children array for roor window" do
|
41
|
+
root_window_children_ids.should_not be_empty
|
42
|
+
children = client.window_children(root_window_id)
|
43
|
+
|
44
|
+
children.should be_kind_of(Array)
|
45
|
+
children.map { |child| child['id'] }.sort.should == root_window_children_ids.sort
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/x11_client.gemspec
CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "x11_client"
|
6
|
-
s.version = "0.0.
|
6
|
+
s.version = "0.0.2"
|
7
7
|
s.authors = ["Andriy Yanko"]
|
8
8
|
s.email = ["andriy.yanko@gmail.com"]
|
9
9
|
s.homepage = "https://github.com/ayanko/x11_client"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: x11_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andriy Yanko
|
@@ -48,6 +48,8 @@ files:
|
|
48
48
|
- ext/x11_client_ext/x11_client_window.c
|
49
49
|
- ext/x11_client_ext/x11_client_window.h
|
50
50
|
- lib/x11_client.rb
|
51
|
+
- spec/spec_helper.rb
|
52
|
+
- spec/x11_client_spec.rb
|
51
53
|
- x11_client.gemspec
|
52
54
|
homepage: https://github.com/ayanko/x11_client
|
53
55
|
licenses: []
|
@@ -82,5 +84,6 @@ rubygems_version: 1.8.6
|
|
82
84
|
signing_key:
|
83
85
|
specification_version: 3
|
84
86
|
summary: X11 client
|
85
|
-
test_files:
|
86
|
-
|
87
|
+
test_files:
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
- spec/x11_client_spec.rb
|