x11_client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+