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