x11_client 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in x11_client.gemspec
4
3
  gemspec
4
+
5
+ gem "rspec"
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(&block) - stop blocking loop
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
@@ -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.1"
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: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
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