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 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