uh 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +5 -0
- data/Guardfile +7 -0
- data/Rakefile +11 -0
- data/TODO +17 -0
- data/ext/uh/color.c +12 -0
- data/ext/uh/display.c +234 -0
- data/ext/uh/event.c +161 -0
- data/ext/uh/extconf.rb +13 -0
- data/ext/uh/font.c +14 -0
- data/ext/uh/pixmap.c +92 -0
- data/ext/uh/screen.c +12 -0
- data/ext/uh/uh.c +139 -0
- data/ext/uh/uh.h +106 -0
- data/ext/uh/window.c +222 -0
- data/lib/uh.rb +28 -0
- data/lib/uh/display.rb +15 -0
- data/lib/uh/drawable.rb +7 -0
- data/lib/uh/events.rb +32 -0
- data/lib/uh/font.rb +7 -0
- data/lib/uh/geo.rb +42 -0
- data/lib/uh/pixmap.rb +5 -0
- data/lib/uh/screen.rb +7 -0
- data/lib/uh/version.rb +3 -0
- data/lib/uh/window.rb +35 -0
- data/lib/uh/wm.rb +199 -0
- data/lib/uh/wm/action_handler.rb +59 -0
- data/lib/uh/wm/client.rb +76 -0
- data/lib/uh/wm/manager.rb +99 -0
- data/lib/uh/wm/workers/base_worker.rb +20 -0
- data/lib/uh/wm/workers/blocking_worker.rb +11 -0
- data/lib/uh/wm/workers/multiplexing_worker.rb +27 -0
- data/test/test_helper.rb +13 -0
- data/test/uh/test_geo.rb +48 -0
- data/uh.gemspec +21 -0
- metadata +136 -0
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
data/Gemfile
ADDED
data/Guardfile
ADDED
data/Rakefile
ADDED
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
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
|
+
}
|