uh 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: af5af0168ce0db30efde0af41ae1305e659bbef7
4
+ data.tar.gz: b6da84ea86620308760a08b5d62a3a316044fbdf
5
+ SHA512:
6
+ metadata.gz: 3ad1c7c95033c4a00d6592bcb1a1cc432431295fe4edeb682471de26c140dfc4953cf41428d25138bb516a929a6aedb3245130c3a8292d050dd6cc3909351a5d
7
+ data.tar.gz: 0178679a35bd8ff65cf5ef51bf761f87d335009c66b70de2acf27e69ebb745cbfcc2edef0740c401ebbeda36720d5589fbc337f4c568597755c264a37a5e59dc
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ /Gemfile-custom.rb
2
+ /Gemfile.lock
3
+ /lib/*.so
4
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ eval File.read('Gemfile-custom.rb') if File.exist?('Gemfile-custom.rb')
data/Guardfile ADDED
@@ -0,0 +1,7 @@
1
+ directories %w[lib test]
2
+
3
+ guard :minitest do
4
+ watch(%r{\Atest/(.*)\/?test_(.*)\.rb$})
5
+ watch(%r{\Alib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
6
+ watch(%r{\Atest/test_helper\.rb$}) { 'test' }
7
+ end
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'rake/extensiontask'
2
+ require 'rake/testtask'
3
+
4
+ task default: :test
5
+
6
+ Rake::ExtensionTask.new('uh')
7
+
8
+ Rake::TestTask.new(test: :compile) do |t|
9
+ t.libs << 'lib' << 'test'
10
+ t.pattern = 'test/**/test_*.rb'
11
+ end
data/TODO ADDED
@@ -0,0 +1,17 @@
1
+ * handle multibyte strings for Pixmap#draw_string
2
+ check other WM or:
3
+ https://www.debian.org/doc/manuals/intro-i18n/ch-examples.en.html
4
+ https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=531036
5
+
6
+ * check WindowOfEvent in twm
7
+
8
+ * use rb_block_call()?
9
+
10
+ * use ALLOC? at least check our allocation and free
11
+ some free function might not be used
12
+
13
+ * valgrind suppression file
14
+ https://github.com/AlekSi/valgrind-suppressions
15
+
16
+ * http://i3wm.org/
17
+ https://wiki.archlinux.org/index.php/i3
data/ext/uh/color.c ADDED
@@ -0,0 +1,12 @@
1
+ #include "uh.h"
2
+
3
+
4
+ VALUE color_make(unsigned long pixel) {
5
+ VALUE obj;
6
+ VALUE args[0];
7
+
8
+ obj = rb_class_new_instance(0, args, cColor);
9
+ rb_ivar_set(obj, rb_intern("@pixel"), LONG2NUM(pixel));
10
+
11
+ return obj;
12
+ }
data/ext/uh/display.c ADDED
@@ -0,0 +1,234 @@
1
+ #include "uh.h"
2
+
3
+
4
+ #define DPY display->dpy
5
+
6
+
7
+ VALUE rdisplay_error_handler = Qnil;
8
+
9
+ int display_x_error_handler(Display *dpy, XErrorEvent *e);
10
+
11
+
12
+ VALUE display_s_on_error(VALUE klass, VALUE handler) {
13
+ rdisplay_error_handler = handler;
14
+ rb_global_variable(&rdisplay_error_handler);
15
+
16
+ return Qnil;
17
+ }
18
+
19
+
20
+ VALUE display_alloc(VALUE klass) {
21
+ UhDisplay *display;
22
+
23
+ return Data_Make_Struct(klass, UhDisplay, 0, free, display);
24
+ }
25
+
26
+
27
+ VALUE display_close(VALUE self) {
28
+ set_display(self);
29
+
30
+ if (DPY) {
31
+ XCloseDisplay(DPY);
32
+ }
33
+ else {
34
+ rb_raise(eDisplayError, "Can't close display");
35
+ }
36
+
37
+ return self;
38
+ }
39
+
40
+ VALUE display_color_by_name(VALUE self, VALUE rcolor) {
41
+ set_display(self);
42
+ Colormap map;
43
+ XColor color;
44
+
45
+ map = DefaultColormap(DPY, SCREEN_DEFAULT);
46
+
47
+ if (!XAllocNamedColor(DPY, map, RSTRING_PTR(rcolor), &color, &color))
48
+ rb_raise(rb_eArgError, "Invalid color name `%s'", RSTRING_PTR(rcolor));
49
+
50
+ return color_make(color.pixel);
51
+ }
52
+
53
+ VALUE display_create_pixmap(VALUE self, VALUE width, VALUE height) {
54
+ set_display(self);
55
+ Pixmap pixmap;
56
+
57
+ pixmap = XCreatePixmap(DPY, ROOT_DEFAULT, FIX2INT(width), FIX2INT(height),
58
+ DefaultDepth(DPY, SCREEN_DEFAULT)
59
+ );
60
+
61
+ return pixmap_make(DPY, pixmap, width, height);
62
+ }
63
+
64
+ VALUE display_fileno(VALUE self) {
65
+ set_display(self);
66
+
67
+ return INT2FIX(XConnectionNumber(DPY));
68
+ }
69
+
70
+ VALUE display_flush(VALUE self) {
71
+ set_display(self);
72
+
73
+ return INT2FIX(XFlush(DPY));
74
+ }
75
+
76
+ VALUE display_each_event(VALUE self) {
77
+ set_display(self);
78
+ XEvent xev;
79
+
80
+ while (1) {
81
+ XNextEvent(DPY, &xev);
82
+ rb_yield(event_make(&xev));
83
+ }
84
+
85
+ return Qnil;
86
+ }
87
+
88
+ VALUE display_grab_key(VALUE self, VALUE key, VALUE modifier) {
89
+ set_display(self);
90
+ KeySym ks;
91
+ KeyCode kc;
92
+
93
+ ks = XStringToKeysym(RSTRING_PTR(key));
94
+ if (ks == NoSymbol)
95
+ rb_raise(rb_eArgError, "Invalid KeySym %s", RSTRING_PTR(key));
96
+
97
+ kc = XKeysymToKeycode(DPY, ks);
98
+ if (kc == 0)
99
+ rb_raise(rb_eArgError, "KeySym XK_%s has no KeyCode", RSTRING_PTR(key));
100
+
101
+ XGrabKey(DPY, kc, FIX2INT(modifier), ROOT_DEFAULT, True,
102
+ GrabModeAsync, GrabModeAsync);
103
+
104
+ return Qnil;
105
+ }
106
+
107
+ VALUE display_listen_events(int argc, VALUE *argv, VALUE self) {
108
+ set_display(self);
109
+ VALUE arg1;
110
+ VALUE arg2;
111
+ Window window;
112
+ long mask;
113
+
114
+ if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) {
115
+ window = window_id(arg1);
116
+ mask = FIX2LONG(arg2);
117
+ }
118
+ else {
119
+ window = ROOT_DEFAULT;
120
+ mask = FIX2LONG(arg1);
121
+ }
122
+
123
+ XSelectInput(DPY, window, mask);
124
+
125
+ return Qnil;
126
+ }
127
+
128
+ VALUE display_next_event(VALUE self) {
129
+ set_display(self);
130
+ XEvent xev;
131
+
132
+ XNextEvent(DPY, &xev);
133
+
134
+ return event_make(&xev);
135
+ }
136
+
137
+ VALUE display_open(VALUE self) {
138
+ set_display(self);
139
+
140
+ if (!(DPY = XOpenDisplay(NULL))) {
141
+ rb_raise(eDisplayError, "Can't open display");
142
+ }
143
+
144
+ XSetErrorHandler(display_x_error_handler);
145
+
146
+ return self;
147
+ }
148
+
149
+ VALUE display_pending(VALUE self) {
150
+ set_display(self);
151
+
152
+ return INT2FIX(XPending(DPY));
153
+ }
154
+
155
+ VALUE display_query_font(VALUE self) {
156
+ set_display(self);
157
+ XFontStruct *xfs;
158
+ VALUE font;
159
+
160
+ if (!(xfs = XQueryFont(DPY,
161
+ XGContextFromGC(DefaultGC(DPY, SCREEN_DEFAULT)))))
162
+ return Qnil;
163
+
164
+ font = font_make(xfs->max_bounds.width, xfs->ascent, xfs->descent);
165
+ XFreeFontInfo(NULL, xfs, 1);
166
+
167
+ return font;
168
+ }
169
+
170
+ VALUE display_root(VALUE self) {
171
+ set_display(self);
172
+
173
+ return window_make(DPY, ROOT_DEFAULT);
174
+ }
175
+
176
+ VALUE display_screens(VALUE self) {
177
+ set_display(self);
178
+ XineramaScreenInfo *xsi;
179
+ int n;
180
+ VALUE screens = rb_ary_new();
181
+ VALUE args[5];
182
+
183
+ if (XineramaIsActive(DPY)) {
184
+ xsi = XineramaQueryScreens(DPY, &n);
185
+
186
+ for (int i = 0; i < n; i++) {
187
+ args[0] = INT2FIX(i);
188
+ args[1] = INT2FIX(xsi[i].x_org);
189
+ args[2] = INT2FIX(xsi[i].y_org);
190
+ args[3] = INT2FIX(xsi[i].width);
191
+ args[4] = INT2FIX(xsi[i].height);
192
+
193
+ rb_ary_push(screens, rb_class_new_instance(5, args, cScreen));
194
+ }
195
+ }
196
+ else {
197
+ args[0] = INT2FIX(SCREEN_DEFAULT);
198
+ args[1] = INT2FIX(0);
199
+ args[2] = INT2FIX(0);
200
+ args[3] = INT2FIX(XDisplayWidth(DPY, SCREEN_DEFAULT));
201
+ args[4] = INT2FIX(XDisplayHeight(DPY, SCREEN_DEFAULT));
202
+
203
+ rb_ary_push(screens, rb_class_new_instance(5, args, cScreen));
204
+ }
205
+
206
+ return screens;
207
+ }
208
+
209
+ VALUE display_sync(VALUE self, VALUE discard) {
210
+ set_display(self);
211
+
212
+ XSync(display->dpy, RTEST(discard));
213
+
214
+ return Qnil;
215
+ }
216
+
217
+
218
+ int display_x_error_handler(Display *dpy, XErrorEvent *e) {
219
+ char msg[80];
220
+ char req[80];
221
+ char nb[80];
222
+
223
+ XGetErrorText(dpy, e->error_code, msg, sizeof msg);
224
+ sprintf(nb, "%d", e->request_code);
225
+ XGetErrorDatabaseText(dpy, "XRequest", nb, "<unknown>", req, sizeof req);
226
+
227
+ rb_funcall(rdisplay_error_handler, rb_intern("call"), 3,
228
+ rb_str_new_cstr(req),
229
+ LONG2NUM(e->resourceid),
230
+ rb_str_new_cstr(msg)
231
+ );
232
+
233
+ return 0;
234
+ }
data/ext/uh/event.c ADDED
@@ -0,0 +1,161 @@
1
+ #include "uh.h"
2
+
3
+
4
+ #define set_xev(x) \
5
+ XEvent *xev;\
6
+ Data_Get_Struct(x, XEvent, xev);
7
+
8
+
9
+ VALUE event_make_event(VALUE klass, XEvent *xev);
10
+ void event_make_configure_request(VALUE self);
11
+ void event_make_key_any(VALUE self);
12
+ void event_make_win_any(VALUE self);
13
+
14
+
15
+ VALUE event_make(XEvent *xev) {
16
+ typedef struct {
17
+ int type;
18
+ VALUE klass;
19
+ void (*function)(VALUE self);
20
+ } EvClass;
21
+ EvClass ev_classes[] = {
22
+ {ConfigureRequest, cConfigureRequest, event_make_configure_request},
23
+ {DestroyNotify, cDestroyNotify, NULL},
24
+ {Expose, cExpose, NULL},
25
+ {KeyPress, cKeyPress, event_make_key_any},
26
+ {KeyRelease, cKeyRelease, event_make_key_any},
27
+ {MapRequest, cMapRequest, NULL},
28
+ {PropertyNotify, cPropertyNotify, NULL},
29
+ {UnmapNotify, cUnmapNotify, NULL}
30
+ };
31
+ int i;
32
+ VALUE event;
33
+
34
+ for (i = 0; i < (sizeof ev_classes / sizeof ev_classes[0]); i++) {
35
+ if (ev_classes[i].type == xev->type) {
36
+ event = event_make_event(ev_classes[i].klass, xev);
37
+ event_make_win_any(event);
38
+ if (ev_classes[i].function)
39
+ ev_classes[i].function(event);
40
+
41
+ return event;
42
+ }
43
+ }
44
+
45
+ return event_make_event(cEvent, xev);
46
+ }
47
+
48
+ VALUE event_make_event(VALUE klass, XEvent *xev) {
49
+ char *type_descs[LASTEvent];
50
+ VALUE event;
51
+
52
+ type_descs[KeyPress] = "key_press";
53
+ type_descs[KeyRelease] = "key_release";
54
+ type_descs[ButtonPress] = "button_press";
55
+ type_descs[ButtonRelease] = "button_release";
56
+ type_descs[MotionNotify] = "motion_notify";
57
+ type_descs[EnterNotify] = "enter_notify";
58
+ type_descs[LeaveNotify] = "leave_notify";
59
+ type_descs[FocusIn] = "focus_in";
60
+ type_descs[FocusOut] = "focus_out";
61
+ type_descs[KeymapNotify] = "keymap_notify";
62
+ type_descs[Expose] = "expose";
63
+ type_descs[GraphicsExpose] = "graphics_expose";
64
+ type_descs[NoExpose] = "no_expose";
65
+ type_descs[VisibilityNotify] = "visibility_notify";
66
+ type_descs[CreateNotify] = "create_notify";
67
+ type_descs[DestroyNotify] = "destroy_notify";
68
+ type_descs[UnmapNotify] = "unmap_notify";
69
+ type_descs[MapNotify] = "map_notify";
70
+ type_descs[MapRequest] = "map_request";
71
+ type_descs[ReparentNotify] = "reparent_notify";
72
+ type_descs[ConfigureNotify] = "configure_notify";
73
+ type_descs[ConfigureRequest] = "configure_request";
74
+ type_descs[GravityNotify] = "gravity_notify";
75
+ type_descs[ResizeRequest] = "resize_request";
76
+ type_descs[CirculateNotify] = "circulate_notify";
77
+ type_descs[CirculateRequest] = "circulate_request";
78
+ type_descs[PropertyNotify] = "property_notify";
79
+ type_descs[SelectionClear] = "selection_clear";
80
+ type_descs[SelectionRequest] = "selection_request";
81
+ type_descs[SelectionNotify] = "selection_notify";
82
+ type_descs[ColormapNotify] = "colormap_notify";
83
+ type_descs[ClientMessage] = "client_message";
84
+ type_descs[MappingNotify] = "mapping_notify";
85
+ type_descs[GenericEvent] = "generic";
86
+
87
+ event = Data_Wrap_Struct(klass, 0, 0, xev);
88
+ rb_ivar_set(event, rb_intern("@type"),
89
+ ID2SYM(rb_intern(type_descs[xev->type])));
90
+
91
+ return event;
92
+ }
93
+
94
+ void event_make_configure_request(VALUE self) {
95
+ set_xev(self);
96
+
97
+ if (xev->xconfigurerequest.value_mask & CWX)
98
+ rb_ivar_set(self, rb_intern("@x"), INT2FIX(xev->xconfigurerequest.x));
99
+
100
+ if (xev->xconfigurerequest.value_mask & CWY)
101
+ rb_ivar_set(self, rb_intern("@y"), INT2FIX(xev->xconfigurerequest.y));
102
+
103
+ if (xev->xconfigurerequest.value_mask & CWWidth)
104
+ rb_ivar_set(self, rb_intern("@width"),
105
+ INT2FIX(xev->xconfigurerequest.width));
106
+
107
+ if (xev->xconfigurerequest.value_mask & CWHeight)
108
+ rb_ivar_set(self, rb_intern("@height"),
109
+ INT2FIX(xev->xconfigurerequest.height));
110
+
111
+ rb_ivar_set(self, rb_intern("@above_window_id"),
112
+ LONG2NUM(xev->xconfigurerequest.above));
113
+ rb_ivar_set(self, rb_intern("@detail"),
114
+ INT2FIX(xev->xconfigurerequest.detail));
115
+ rb_ivar_set(self, rb_intern("@value_mask"),
116
+ LONG2NUM(xev->xconfigurerequest.detail));
117
+ }
118
+
119
+ void event_make_key_any(VALUE self) {
120
+ set_xev(self);
121
+ KeySym ks;
122
+
123
+ ks = XkbKeycodeToKeysym(xev->xany.display, xev->xkey.keycode, 0, 0);
124
+ if (ks == NoSymbol)
125
+ return;
126
+
127
+ rb_ivar_set(self, rb_intern("@key"), rb_str_new_cstr(XKeysymToString(ks)));
128
+ rb_ivar_set(self, rb_intern("@modifier_mask"), INT2FIX(xev->xkey.state));
129
+ }
130
+
131
+ void event_make_win_any(VALUE self) {
132
+ set_xev(self);
133
+ Window window;
134
+
135
+ switch (xev->type) {
136
+ case ConfigureRequest:
137
+ window = xev->xconfigurerequest.window;
138
+ break;
139
+ case DestroyNotify:
140
+ window = xev->xdestroywindow.window;
141
+ break;
142
+ case Expose:
143
+ window = xev->xexpose.window;
144
+ break;
145
+ case KeyPress:
146
+ window = xev->xkey.window;
147
+ break;
148
+ case MapRequest:
149
+ window = xev->xmaprequest.window;
150
+ break;
151
+ case PropertyNotify:
152
+ window = xev->xproperty.window;
153
+ break;
154
+ case UnmapNotify:
155
+ window = xev->xunmap.window;
156
+ break;
157
+ }
158
+
159
+ rb_ivar_set(self, rb_intern("@window"),
160
+ window_make(xev->xany.display, window));
161
+ }