x11_client 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 ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ tmp/*
6
+ lib/*.so
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in x11_client.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,128 @@
1
+ ## X11Client
2
+
3
+ X11Client is C extension that manages X11 windows/events.
4
+
5
+ It can be handy if you want to controll some programs running in Xvfb.
6
+
7
+ ## Dependencies
8
+
9
+ * Xlib
10
+ * Xtst
11
+ * Xext
12
+
13
+ ## Installation
14
+
15
+ gem install x11_client
16
+
17
+ ## API
18
+
19
+ * X11Client.new(display) - create new client for given display
20
+ * X11Client#open_display - explicit open display
21
+ * X11Client#close_display - explicit close display
22
+ * X11Client#sync - sync display
23
+ * X11Client#start(&block) - block execution and yield event attributes for each new event.
24
+ * X11Client#stop(&block) - stop blocking loop
25
+ * X11Client#get_window(window_id) - returns window attributes hash or nil for given window_id.
26
+ * X11Client#mousemove(x,y) - move mouse pointer to (x,y) coordinates.
27
+ * X11Client#mousedown(button) - down mouse buton
28
+ * X11Client#mouseup(buton) - up mouse button
29
+ * X11Client#mouseclick(button) - mousedown and mouseup
30
+
31
+ ## Mouse buttons
32
+
33
+ * 1 - left
34
+ * 2 - right
35
+ * 3 - middle
36
+ * 4 - wheel up
37
+ * 5 - wheel down
38
+
39
+ ## X11 Window attributes
40
+
41
+ * id - window id
42
+ * root_id - root window id
43
+ * x - X coordinate
44
+ * y - Y coordinate
45
+ * width - window width
46
+ * height - window height
47
+ * border_width - window border width
48
+ * state - window state
49
+ * shown
50
+ * hidden
51
+ * unmapped
52
+
53
+ ## X11 Event attributes
54
+
55
+ Supported events:
56
+
57
+ * CreateWindowEvent
58
+ * DestroyWindowEvent
59
+ * MapEvent
60
+ * UnmapEvent
61
+ * VisibilityEvent
62
+
63
+ ### CreateWindowEvent attributes:
64
+
65
+ * type
66
+ * window_id
67
+ * parent_id
68
+ * x
69
+ * y
70
+ * width
71
+ * height
72
+ * border_width
73
+
74
+ ### DestroyWindowEvent attributes:
75
+
76
+ * type
77
+ * window_id
78
+
79
+ ### MapEvent attributes:
80
+
81
+ * type
82
+ * window_id
83
+
84
+ ### UnmapEvent attributes:
85
+
86
+ * type
87
+ * window_id
88
+
89
+ ### VisibilityEvent attributes:
90
+
91
+ * type
92
+ * window_id
93
+ * state:
94
+ * unobscured
95
+ * partially_obscured
96
+ * fully_unobscured
97
+
98
+ ## Example
99
+
100
+ client = X11Client.new(":0")
101
+
102
+ client.start do |event|
103
+
104
+ case event['type']
105
+ when 'CreateWindowEvent'
106
+ window = client.get_window(event["window_id"])
107
+ next unless window
108
+
109
+ case window['class']
110
+ when /skype/i
111
+ case window['name']
112
+ when /End User License Agreement/i
113
+ # Accept Skype Aggreement
114
+ client.mousemove(window['x'] + 500, window['y'] + 340)
115
+ client.sync
116
+ sleep(1)
117
+ client.mouseclick(1)
118
+ client.stop
119
+ end
120
+ end
121
+
122
+ end
123
+
124
+ end
125
+
126
+ ## References
127
+
128
+ * [The Xlib Programming Manual](http://tronche.com/gui/x/xlib/)
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/extensiontask'
3
+
4
+ Rake::ExtensionTask.new('x11_client_ext')
@@ -0,0 +1,7 @@
1
+ require 'mkmf'
2
+
3
+ $CFLAGS << ' -Wall '
4
+
5
+ $LDFLAGS << ' ' << `pkg-config --libs x11 xtst xext`
6
+
7
+ create_makefile 'x11_client_ext'
@@ -0,0 +1,12 @@
1
+ #ifndef X11_CLIENT_H
2
+ #define X11_CLIENT_H
3
+
4
+ #include "ruby.h"
5
+ #include <X11/Xlib.h>
6
+
7
+ typedef struct {
8
+ Display *display;
9
+ int loop;
10
+ } X11Client;
11
+
12
+ #endif
@@ -0,0 +1,24 @@
1
+ #include "x11_client.h"
2
+ #include "x11_client_utils.h"
3
+ #include "x11_client_core.h"
4
+
5
+ VALUE X11Client_initialize(VALUE self, VALUE display) {
6
+ Check_Type(display, T_STRING);
7
+ rb_iv_set(self, "@display", display);
8
+ rb_funcall(self, rb_intern("open_display"), 0, 0);
9
+ return self;
10
+ }
11
+
12
+ VALUE X11Client_alloc(VALUE klass) {
13
+ VALUE obj;
14
+ X11Client *client = ALLOC_N(X11Client, 1);
15
+ client->display = NULL;
16
+
17
+ obj = Data_Wrap_Struct(klass, 0, X11Client_free, client);
18
+ return obj;
19
+ }
20
+
21
+ void X11Client_free(X11Client *client) {
22
+ X11Client_free_display(client->display);
23
+ free(client);
24
+ }
@@ -0,0 +1,6 @@
1
+ #include "ruby.h"
2
+
3
+ VALUE X11Client_initialize(VALUE self, VALUE display);
4
+ VALUE X11Client_alloc(VALUE klass);
5
+ void X11Client_free(X11Client *client);
6
+
@@ -0,0 +1,43 @@
1
+ #include "x11_client.h"
2
+
3
+ #include "x11_client_display.h"
4
+
5
+ #include "x11_client_utils.h"
6
+
7
+ static VALUE eX11ClientError = Qnil;
8
+
9
+ VALUE X11Client_open_display(VALUE self) {
10
+ X11Client *client;
11
+ Data_Get_Struct(self, X11Client, client);
12
+
13
+ if(client->display) {
14
+ rb_raise(eX11ClientError, "Display already opened");
15
+ }
16
+
17
+ client->display = XOpenDisplay(RSTRING_PTR(rb_iv_get(self, "@display")));
18
+ if( client->display == NULL ) {
19
+ rb_raise(eX11ClientError, "Can't open display");
20
+ }
21
+
22
+ return self;
23
+ }
24
+
25
+ VALUE X11Client_close_display(VALUE self) {
26
+ X11Client *client;
27
+ Data_Get_Struct(self, X11Client, client);
28
+
29
+ if(client->display == NULL) {
30
+ rb_raise(eX11ClientError, "Display already closed");
31
+ }
32
+
33
+ X11Client_free_display(client->display);
34
+ return self;
35
+ }
36
+
37
+ VALUE X11Client_sync(VALUE self) {
38
+ X11Client *client;
39
+ Data_Get_Struct(self, X11Client, client);
40
+
41
+ XSync(client->display, False);
42
+ return self;
43
+ }
@@ -0,0 +1,6 @@
1
+ #include "ruby.h"
2
+
3
+ VALUE X11Client_open_display(VALUE self);
4
+ VALUE X11Client_close_display(VALUE self);
5
+ VALUE X11Client_sync(VALUE self);
6
+
@@ -0,0 +1,118 @@
1
+ #include "x11_client.h"
2
+ #include "x11_client_event.h"
3
+
4
+ VALUE X11Client_start(VALUE self) {
5
+ rb_need_block();
6
+
7
+ X11Client *client;
8
+ Data_Get_Struct(self, X11Client, client);
9
+ client->loop = True;
10
+
11
+ XSelectInput(client->display, DefaultRootWindow(client->display), SubstructureNotifyMask);
12
+
13
+ XEvent any_event;
14
+ while ( client->loop ) {
15
+ XNextEvent(client->display, &any_event);
16
+
17
+ VALUE event = X11Client_get_event(any_event);
18
+
19
+ if(event && event != Qnil) {
20
+ rb_yield(event);
21
+ }
22
+ }
23
+ return Qnil;
24
+ }
25
+
26
+ VALUE X11Client_stop(VALUE self) {
27
+ X11Client *client;
28
+ Data_Get_Struct(self, X11Client, client);
29
+
30
+ XSelectInput(client->display, DefaultRootWindow(client->display), 0);
31
+ client->loop = False;
32
+ return Qnil;
33
+ }
34
+
35
+ VALUE X11Client_get_event(XEvent any_event) {
36
+ VALUE result = Qnil;
37
+
38
+ switch(any_event.type) {
39
+
40
+ case CreateNotify:
41
+ ;
42
+ XCreateWindowEvent *create_event = (XCreateWindowEvent *)&any_event;
43
+
44
+ result = rb_hash_new();
45
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("type"), rb_str_new2("CreateWindowEvent"));
46
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("window_id"), LONG2FIX(create_event->window) );
47
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("parent_id"), LONG2FIX(create_event->parent));
48
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("x"), INT2FIX(create_event->x));
49
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("y"), INT2FIX(create_event->y));
50
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("width"), INT2FIX(create_event->width));
51
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("height"), INT2FIX(create_event->height));
52
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("border_width"), INT2FIX(create_event->border_width));
53
+ break;
54
+
55
+ case DestroyNotify:
56
+ ;
57
+ XDestroyWindowEvent *destroy_event = (XDestroyWindowEvent *)&any_event;
58
+
59
+ result = rb_hash_new();
60
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("type"), rb_str_new2("DestroyWindowEvent"));
61
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("window_id"), LONG2FIX(destroy_event->window) );
62
+ break;
63
+
64
+ case MapNotify:
65
+ ;
66
+ XMapEvent *map_event = (XMapEvent *)&any_event;
67
+
68
+ result = rb_hash_new();
69
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("type"), rb_str_new2("MapEvent"));
70
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("window_id"), LONG2FIX(map_event->window) );
71
+ break;
72
+
73
+ case UnmapNotify:
74
+ ;
75
+ XUnmapEvent *unmap_event = (XUnmapEvent *)&any_event;
76
+
77
+ result = rb_hash_new();
78
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("type"), rb_str_new2("UnmapEvent"));
79
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("window_id"), LONG2FIX(unmap_event->window) );
80
+ break;
81
+
82
+ case VisibilityNotify:
83
+ ;
84
+ XVisibilityEvent *visibility_event = (XVisibilityEvent *)&any_event;
85
+
86
+ result = rb_hash_new();
87
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("type"), rb_str_new2("VisibilityEvent"));
88
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("window_id"), LONG2FIX(visibility_event->window) );
89
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("state"), X11Client_visibility_event_state(visibility_event));
90
+ break;
91
+
92
+ default:
93
+ result = Qnil;
94
+
95
+ }
96
+ return result;
97
+ }
98
+
99
+ VALUE X11Client_visibility_event_state(XVisibilityEvent *event) {
100
+ VALUE result;
101
+
102
+ switch(event->state) {
103
+ case VisibilityUnobscured:
104
+ rb_str_new2("unobscured");
105
+ break;
106
+ case VisibilityPartiallyObscured:
107
+ rb_str_new2("partially_obscured");
108
+ break;
109
+ case VisibilityFullyObscured:
110
+ rb_str_new2("fully_unobscured");
111
+ break;
112
+ default:
113
+ result = Qnil;
114
+ }
115
+
116
+ return result;
117
+ }
118
+
@@ -0,0 +1,7 @@
1
+ #include "ruby.h"
2
+ #include "X11/Xlib.h"
3
+
4
+ VALUE X11Client_start(VALUE self);
5
+ VALUE X11Client_stop(VALUE self);
6
+ VALUE X11Client_get_event(XEvent any_event);
7
+ VALUE X11Client_visibility_event_state(XVisibilityEvent *event);
@@ -0,0 +1,34 @@
1
+ #include "x11_client.h"
2
+
3
+ #include "x11_client_core.h"
4
+ #include "x11_client_display.h"
5
+ #include "x11_client_event.h"
6
+ #include "x11_client_mouse.h"
7
+ #include "x11_client_window.h"
8
+
9
+ static VALUE eX11ClientError = Qnil;
10
+
11
+ static VALUE cX11Client = Qnil;
12
+
13
+ void Init_x11_client_ext() {
14
+ eX11ClientError = rb_define_class("X11ClientError", rb_eStandardError);
15
+
16
+ cX11Client = rb_define_class("X11Client", rb_cObject);
17
+
18
+ rb_define_alloc_func(cX11Client, X11Client_alloc);
19
+ rb_define_method(cX11Client, "initialize", X11Client_initialize, 1);
20
+
21
+ rb_define_method(cX11Client, "open_display", X11Client_open_display, 0);
22
+ rb_define_method(cX11Client, "close_display", X11Client_close_display, 0);
23
+ rb_define_method(cX11Client, "sync", X11Client_sync, 0);
24
+
25
+ rb_define_method(cX11Client, "start", X11Client_start, 0);
26
+ rb_define_method(cX11Client, "stop", X11Client_stop, 0);
27
+
28
+ rb_define_method(cX11Client, "get_window", X11Client_get_window, 1);
29
+
30
+ rb_define_method(cX11Client, "mousemove", X11Client_mousemove, 2);
31
+ rb_define_method(cX11Client, "mousedown", X11Client_mousedown, 1);
32
+ rb_define_method(cX11Client, "mouseup", X11Client_mouseup, 1);
33
+ rb_define_method(cX11Client, "mouseclick", X11Client_mouseclick, 1);
34
+ }
@@ -0,0 +1,37 @@
1
+ #include "x11_client.h"
2
+ #include "x11_client_mouse.h"
3
+
4
+ #include <X11/extensions/XTest.h>
5
+ #include <unistd.h>
6
+
7
+ VALUE X11Client_mousemove(VALUE self, VALUE x, VALUE y) {
8
+ X11Client *client;
9
+ Data_Get_Struct(self, X11Client, client);
10
+
11
+ XTestFakeMotionEvent(client->display, 0, NUM2INT(x), NUM2INT(y), CurrentTime);
12
+ return self;
13
+ }
14
+
15
+ VALUE X11Client_mousedown(VALUE self, VALUE button) {
16
+ X11Client *client;
17
+ Data_Get_Struct(self, X11Client, client);
18
+
19
+ XTestFakeButtonEvent(client->display, NUM2INT(button), True, CurrentTime);
20
+ return self;
21
+ }
22
+
23
+ VALUE X11Client_mouseup(VALUE self, VALUE button) {
24
+ X11Client *client;
25
+ Data_Get_Struct(self, X11Client, client);
26
+
27
+ XTestFakeButtonEvent(client->display, NUM2INT(button), False, CurrentTime);
28
+ return self;
29
+ }
30
+
31
+ VALUE X11Client_mouseclick(VALUE self, VALUE button) {
32
+ X11Client_mousedown(self, button);
33
+ sleep(0.01);
34
+ X11Client_mouseup(self, button);
35
+ return self;
36
+ }
37
+
@@ -0,0 +1,6 @@
1
+ #include "ruby.h"
2
+
3
+ VALUE X11Client_mousemove(VALUE self, VALUE x, VALUE y);
4
+ VALUE X11Client_mousedown(VALUE self, VALUE button);
5
+ VALUE X11Client_mouseup(VALUE self, VALUE button);
6
+ VALUE X11Client_mouseclick(VALUE self, VALUE button);
@@ -0,0 +1,7 @@
1
+ #include "x11_client_utils.h"
2
+
3
+ void X11Client_free_display(Display *display) {
4
+ if(display) {
5
+ XCloseDisplay(display);
6
+ }
7
+ }
@@ -0,0 +1,3 @@
1
+ #include <X11/Xlib.h>
2
+
3
+ void X11Client_free_display(Display *display);
@@ -0,0 +1,71 @@
1
+ #include "x11_client.h"
2
+
3
+ #include "x11_client_window.h"
4
+
5
+ #include "X11/Xutil.h"
6
+
7
+ VALUE X11Client_get_window(VALUE self, VALUE window_id) {
8
+ VALUE result = Qnil;
9
+
10
+ X11Client *client;
11
+ Data_Get_Struct(self, X11Client, client);
12
+
13
+ Window window = NUM2LONG(window_id);
14
+ char* window_name = '\0';
15
+ XWindowAttributes attributes;
16
+ XClassHint classhint;
17
+
18
+ XSetErrorHandler(X11Client_IgnoreBadWindowHandler);
19
+
20
+ if(XGetWindowAttributes(client->display, window, &attributes)) {
21
+ result = rb_hash_new();
22
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("id"), LONG2FIX(window));
23
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("x"), INT2FIX(attributes.x));
24
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("y"), INT2FIX(attributes.y));
25
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("width"), INT2FIX(attributes.width));
26
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("height"), INT2FIX(attributes.height));
27
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("border_width"), INT2FIX(attributes.border_width));
28
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("root_id"), LONG2FIX(attributes.root));
29
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("state"), X11Client_window_state(attributes));
30
+
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
+
36
+ if (XGetClassHint(client->display, window, &classhint)) {
37
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("class"), rb_str_new2(classhint.res_class));
38
+ rb_funcall(result, rb_intern("[]="), 2, rb_str_new2("class_name"), rb_str_new2(classhint.res_name));
39
+ XFree(classhint.res_name);
40
+ XFree(classhint.res_class);
41
+ }
42
+ }
43
+
44
+ XSetErrorHandler(NULL);
45
+
46
+ return result;
47
+ }
48
+
49
+ VALUE X11Client_window_state(XWindowAttributes attributes) {
50
+ VALUE state = Qnil;
51
+ switch(attributes.map_state) {
52
+ case IsViewable:
53
+ state = rb_str_new2("shown");
54
+ break;
55
+ case IsUnviewable:
56
+ state = rb_str_new2("hidden");
57
+ break;
58
+ case IsUnmapped:
59
+ state = rb_str_new2("unmapped");
60
+ break;
61
+ }
62
+
63
+ return state;
64
+ }
65
+
66
+ int X11Client_IgnoreBadWindowHandler(Display *display, XErrorEvent *error) {
67
+ if (error->request_code != BadWindow) {
68
+ XSetErrorHandler(NULL);
69
+ }
70
+ return 1;
71
+ }
@@ -0,0 +1,3 @@
1
+ VALUE X11Client_get_window(VALUE self, VALUE window_id);
2
+ VALUE X11Client_window_state(XWindowAttributes attributes);
3
+ int X11Client_IgnoreBadWindowHandler(Display *display, XErrorEvent *error);
data/lib/x11_client.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "x11_client_ext"
2
+
3
+ class X11Client
4
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "x11_client"
6
+ s.version = "0.0.1"
7
+ s.authors = ["Andriy Yanko"]
8
+ s.email = ["andriy.yanko@gmail.com"]
9
+ s.homepage = "https://github.com/ayanko/x11_client"
10
+ s.summary = %q{X11 client}
11
+ s.description = %q{X11 client}
12
+
13
+ s.rubyforge_project = "x11_client"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.extensions = ["ext/x11_client_ext/extconf.rb"]
21
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: x11_client
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Andriy Yanko
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-11-09 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: X11 client
22
+ email:
23
+ - andriy.yanko@gmail.com
24
+ executables: []
25
+
26
+ extensions:
27
+ - ext/x11_client_ext/extconf.rb
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - .gitignore
32
+ - Gemfile
33
+ - README.md
34
+ - Rakefile
35
+ - ext/x11_client_ext/extconf.rb
36
+ - ext/x11_client_ext/x11_client.h
37
+ - ext/x11_client_ext/x11_client_core.c
38
+ - ext/x11_client_ext/x11_client_core.h
39
+ - ext/x11_client_ext/x11_client_display.c
40
+ - ext/x11_client_ext/x11_client_display.h
41
+ - ext/x11_client_ext/x11_client_event.c
42
+ - ext/x11_client_ext/x11_client_event.h
43
+ - ext/x11_client_ext/x11_client_ext.c
44
+ - ext/x11_client_ext/x11_client_mouse.c
45
+ - ext/x11_client_ext/x11_client_mouse.h
46
+ - ext/x11_client_ext/x11_client_utils.c
47
+ - ext/x11_client_ext/x11_client_utils.h
48
+ - ext/x11_client_ext/x11_client_window.c
49
+ - ext/x11_client_ext/x11_client_window.h
50
+ - lib/x11_client.rb
51
+ - x11_client.gemspec
52
+ homepage: https://github.com/ayanko/x11_client
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options: []
57
+
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ hash: 3
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ hash: 3
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ requirements: []
79
+
80
+ rubyforge_project: x11_client
81
+ rubygems_version: 1.8.6
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: X11 client
85
+ test_files: []
86
+