xlib_ruby 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/ext/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ Makefile
2
+ mkmf.log
3
+ x11.o
4
+ x11.so
5
+ x11_wrap.o
data/ext/Makefile.test ADDED
@@ -0,0 +1,4 @@
1
+ # DO NOT REMOVE! ITS MY GDB-TESTHELP
2
+
3
+ wm: x11.c x11.h
4
+ gcc -I/usr/X11R6/include/ -lc -L/usr/X11R6/lib -lX11 x11.c -ggdb -o wm
data/ext/extconf.rb ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mkmf'
4
+ #include <stdlib.h>
5
+ #include <stdio.h>
6
+ #include <string.h>
7
+ #include <X11/keysym.h>
8
+ #include <X11/Xatom.h>
9
+ #include <X11/Xlib.h>
10
+ #include <X11/Xproto.h>
11
+ #include <X11/Xutil.h>
12
+ #include <locale.h>
13
+
14
+
15
+ find_header("X11/Xlib.h", "/usr/X11R6/include");
16
+ find_header("X11/Xatom.h", "/usr/X11R6/include");
17
+ find_header("X11/Xproto.h", "/usr/X11R6/include");
18
+ find_header("X11/Xutil.h", "/usr/X11R6/include");
19
+ find_header("X11/keysym.h", "/usr/X11R6/include");
20
+ find_header("locale.h", ["/usr/include"]);
21
+ find_library("X11", "XOpenDisplay", "/usr/lib", "/usr/X11/lib")
22
+
23
+ $libs = append_library($libs, "X11")
24
+ $libs = append_library($libs, "c")
25
+ $libs = append_library($libs, "c")
26
+ create_makefile('x11')
data/ext/x11.c ADDED
@@ -0,0 +1,512 @@
1
+ #include "x11.h"
2
+
3
+ char* Xevents[] = {
4
+ [ButtonPress] = "button_press",
5
+ [ButtonRelease] = "button_release",
6
+ [ConfigureRequest] = "configure_request",
7
+ [ConfigureNotify] = "configure_notify",
8
+ [DestroyNotify] = "destroy_notify",
9
+ [EnterNotify] = "enter_notify",
10
+ [LeaveNotify] = "leave_notify",
11
+ [Expose] = "expose",
12
+ [FocusIn] = "focus_in",
13
+ [FocusOut] = "focus_out",
14
+ [KeyPress] = "key_press",
15
+ [KeyRelease] = "key_release",
16
+ [MappingNotify] = "mapping_notify",
17
+ [MapRequest] = "map_request",
18
+ [UnmapNotify] = "unmap_notify",
19
+ [PropertyNotify] = "property_notify"
20
+ };
21
+
22
+ /*
23
+ * This handles just some initial setup directly related to the
24
+ * Window manager object which is passed as a pointer
25
+ */
26
+ void setup(WM* wm) {
27
+ XSetWindowAttributes swa;
28
+
29
+ /* init atoms */
30
+ wm->wmatom[WMProtocols] = XInternAtom(wm->dpy, "WM_PROTOCOLS", False);
31
+ wm->wmatom[WMDelete] = XInternAtom(wm->dpy, "WM_DELETE_WINDOW", False);
32
+ wm->wmatom[WMName] = XInternAtom(wm->dpy, "WM_NAME", False);
33
+ wm->wmatom[WMState] = XInternAtom(wm->dpy, "WM_STATE", False);
34
+ wm->netatom[NetSupported] = XInternAtom(wm->dpy, "_NET_SUPPORTED", False);
35
+ wm->netatom[NetWMName] = XInternAtom(wm->dpy, "_NET_WM_NAME", False);
36
+
37
+ // init geometry
38
+ wm->sx = wm->sy = 0;
39
+ wm->sw = DisplayWidth(wm->dpy, wm->screen);
40
+ wm->sh = DisplayHeight(wm->dpy, wm->screen);
41
+
42
+ // init window area
43
+ wm->wax = wm->way = 0;
44
+ wm->waw = wm->sw;
45
+ wm->wah = wm->sh;
46
+
47
+ swa.event_mask = SubstructureRedirectMask |
48
+ SubstructureNotifyMask |
49
+ EnterWindowMask |
50
+ LeaveWindowMask |
51
+ StructureNotifyMask;
52
+ XChangeWindowAttributes(wm->dpy, wm->root, CWEventMask, &swa);
53
+ XSelectInput(wm->dpy, wm->root, swa.event_mask);
54
+
55
+ // TODO: Grabkeys, Multihead-Support, Xinerama, Compiz, Multitouch :D
56
+ }
57
+
58
+ void init_client(WM* wm, Window w, Client* c) {
59
+ char* name;
60
+ XClassHint* ch = XAllocClassHint();
61
+ memset(c,0,sizeof(Client));
62
+ c->win = w;
63
+ c->manager = wm;
64
+ c->x =c->y = 0;
65
+ c->w = c->h = 10;
66
+
67
+ if (XGetClassHint(wm->dpy, w, ch)) {
68
+ sprintf(c->class,"%s",ch->res_class);
69
+ if (ch->res_class) XFree(ch->res_class);
70
+ if (ch->res_name) XFree(ch->res_name);
71
+ }
72
+
73
+ if (XFetchName(wm->dpy,w,&name)) {
74
+ sprintf(c->name,"%s",name);
75
+ XFree(name);
76
+ }
77
+
78
+ c->x = c->y = c->w = c->h = c->oldborder = 0;
79
+ }
80
+
81
+ /*
82
+ * This will initialize a new client object at the adress c,
83
+ * its manager set to winman. The window itself and it's attributes
84
+ * must be passed as well. This function will be called each time a
85
+ * window is added to the field of managed windows in the WM object
86
+ */
87
+ void manage_client(WM* winman, XWindowAttributes *wa, Client* c) {
88
+ XWindowChanges wc;
89
+
90
+ c->x = wa->x;
91
+ c->y = wa->y;
92
+ c->w = wa->width;
93
+ c->h = wa->height;
94
+ c->oldborder = wa->border_width;
95
+
96
+ if(c->w == winman->sw && c->h == winman->sh) {
97
+ c->x = winman->sx;
98
+ c->y = winman->sy;
99
+ c->border = wa->border_width;
100
+ } else {
101
+ if(c->x + c->w + 2 * c->border > winman->wax + winman->waw)
102
+ c->x = winman->wax + winman->waw - c->w - 2 * c->border;
103
+ if(c->y + c->h + 2 * c->border > winman->way + winman->wah)
104
+ c->y = winman->way + winman->wah - c->h - 2 * c->border;
105
+ if(c->x < winman->wax)
106
+ c->x = winman->wax;
107
+ if(c->y < winman->way)
108
+ c->y = winman->way;
109
+
110
+ c->border = 0;
111
+ }
112
+
113
+ wc.border_width = c->border;
114
+ XConfigureWindow(winman->dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
115
+
116
+ XSelectInput(winman->dpy,
117
+ c->win,
118
+ ButtonPressMask |
119
+ ButtonReleaseMask |
120
+ EnterWindowMask |
121
+ LeaveWindowMask |
122
+ FocusChangeMask |
123
+ KeyPressMask |
124
+ KeyReleaseMask |
125
+ PropertyChangeMask |
126
+ StructureNotifyMask);
127
+
128
+ XMoveResizeWindow(winman->dpy, c->win, c->x, c->y, c->w, c->h); // some wins need this
129
+ XMapWindow(winman->dpy, c->win);
130
+ //XSetInputFocus(winman->dpy, c->win, RevertToNone, CurrentTime); // focus new windows
131
+ //winman->selected = c;
132
+ XSync(winman->dpy, False);
133
+ }
134
+
135
+ /*
136
+ * This function creates a simple border around a client
137
+ */
138
+ void border_client(Client* c, int w) {
139
+ XWindowChanges wc;
140
+
141
+ c->border = w;
142
+ wc.border_width = w;
143
+ fprintf(stderr,"border_client:XConfigureWindow border=%i\n", wc.border_width);
144
+ XConfigureWindow(c->manager->dpy, c->win, CWBorderWidth, &wc);
145
+ XMoveResizeWindow(c->manager->dpy, c->win, c->x, c->y, c->w, c->h); // some wins need this
146
+ XSync(c->manager->dpy, False);
147
+ }
148
+
149
+ /*
150
+ * This function resets the client's border to the preset size
151
+ */
152
+ void unborder_client(Client* c) {
153
+ XWindowChanges wc;
154
+
155
+ c->border = c->oldborder;
156
+ wc.border_width = c->border;
157
+ fprintf(stderr,"unborder_client:XConfigureWindow border=%i\n", wc.border_width);
158
+ XConfigureWindow(c->manager->dpy, c->win, CWBorderWidth, &wc);
159
+ XMoveResizeWindow(c->manager->dpy, c->win, c->x, c->y, c->w, c->h); // some wins need this
160
+ XSync(c->manager->dpy, False);
161
+ }
162
+
163
+ /*
164
+ * This function raises a client
165
+ */
166
+ void raise_client(Client* c) {
167
+ //XWindowChanges wc;
168
+ //XConfigureWindow(c->manager->dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
169
+ //XSelectInput(c->manager->dpy, c->win, EnterWindowMask | FocusChangeMask
170
+ // | PropertyChangeMask | StructureNotifyMask);
171
+ XMoveResizeWindow(c->manager->dpy, c->win, c->x, c->y, c->w, c->h); // some wins need this
172
+ XMapWindow(c->manager->dpy, c->win);
173
+ c->manager->selected = c;
174
+ XRaiseWindow(c->manager->dpy, c->win);
175
+ XSync(c->manager->dpy, False);
176
+ }
177
+
178
+ /*
179
+ * This fucntion will try to process
180
+ * the next pending event, if existant.
181
+ * This is just for the main testing
182
+ */
183
+ /*
184
+ void process_event(WM* winman) {
185
+ XEvent ev;
186
+ XWindowAttributes wa;
187
+ unsigned int i,j;
188
+ Window *wins, d1, d2;
189
+
190
+ if (XPending(winman->dpy))
191
+ XNextEvent(winman->dpy, &ev);
192
+ if ((ev.type == UnmapNotify) || (ev.type == DestroyNotify)) {
193
+ for(i=0; i<winman->clients_num; i++)
194
+ if (winman->clients[i].win == ev.xany.window) {
195
+ winman->clients_num -= 1;
196
+ for(j=i+1; j<winman->clients_num; j++)
197
+ winman->clients[j-1] = winman->clients[j];
198
+ winman->clients = realloc(winman->clients, sizeof(Client)*winman->clients_num);
199
+ }
200
+ }
201
+ else {
202
+ wins = NULL;
203
+ XQueryTree(winman->dpy, winman->root, &d1, &d2, &wins, &j)
204
+ if (j != winman->clients_num)
205
+ winman->clients_num = j;
206
+ winman->clients = realloc(winman->clients, sizeof(Client)*winman->clients_num);
207
+ for (i = 0; i < j; i++) {
208
+ XGetWindowAttributes(winman->dpy, wins[i], &wa);
209
+ if(wa.map_state == IsViewable)
210
+ manage(winman, wins[i], &wa, &winman->clients[i]);
211
+ }
212
+ }
213
+ }
214
+ */
215
+
216
+ Client* client_ftw(WM* wm, Window w) {
217
+ int i;
218
+ for (i = 0; i < wm->clients_num; i++) {
219
+ if (wm->clients[i].win == w)
220
+ return &wm->clients[i];
221
+ }
222
+ return NULL;
223
+ }
224
+
225
+ /*
226
+ * This shows which source caused the event.
227
+ * Has to be called prior to handling the actual event!!
228
+ */
229
+ int event_next_source(WM* winman) {
230
+ XEvent ev;
231
+ int i;
232
+
233
+ if (XPending(winman->dpy)) {
234
+ XPeekEvent(winman->dpy, &ev);
235
+ for(i=0; i<winman->clients_num; i++) {
236
+ if (winman->clients[i].win == ev.xany.window)
237
+ return i;
238
+ }
239
+ return -2;
240
+ }
241
+ return -1;
242
+ }
243
+
244
+ /*
245
+ * This returns the events name
246
+ */
247
+ char* event_next_type(WM* winman) {
248
+ XEvent ev;
249
+
250
+ if (XPending(winman->dpy)) {
251
+ XPeekEvent(winman->dpy, &ev);
252
+ return Xevents[ev.type];
253
+ }
254
+ return NULL;
255
+ }
256
+
257
+ /*
258
+ * This removes an event from the queue
259
+ */
260
+ void event_pop(WM* winman) {
261
+ XEvent ev;
262
+
263
+ if (XPending(winman->dpy))
264
+ XNextEvent(winman->dpy, &ev);
265
+ }
266
+
267
+ /*
268
+ * This function resizes a client
269
+ */
270
+ void
271
+ resize(WM* winman, Client *c, int x, int y, int w, int h, int sizehints) {
272
+ XWindowChanges wc;
273
+
274
+ if(sizehints != 0) {
275
+ /* set minimum possible */
276
+ if (w < 1)
277
+ w = 1;
278
+ if (h < 1)
279
+ h = 1;
280
+
281
+ /* temporarily remove base dimensions */
282
+ w -= c->basew;
283
+ h -= c->baseh;
284
+
285
+ /* adjust for aspect limits */
286
+ if (c->minay > 0 && c->maxay > 0 && c->minax > 0 && c->maxax > 0) {
287
+ if (w * c->maxay > h * c->maxax)
288
+ w = h * c->maxax / c->maxay;
289
+ else if (w * c->minay < h * c->minax)
290
+ h = w * c->minay / c->minax;
291
+ }
292
+
293
+ /* adjust for increment value */
294
+ if(c->incw)
295
+ w -= w % c->incw;
296
+ if(c->inch)
297
+ h -= h % c->inch;
298
+
299
+ /* restore base dimensions */
300
+ w += c->basew;
301
+ h += c->baseh;
302
+
303
+ if(c->minw > 0 && w < c->minw)
304
+ w = c->minw;
305
+ if(c->minh > 0 && h < c->minh)
306
+ h = c->minh;
307
+ if(c->maxw > 0 && w > c->maxw)
308
+ w = c->maxw;
309
+ if(c->maxh > 0 && h > c->maxh)
310
+ h = c->maxh;
311
+ }
312
+ if(w <= 0 || h <= 0)
313
+ return;
314
+ /* offscreen appearance fixes */
315
+ if(x > winman->sw)
316
+ x = winman->sw - w - 2 * c->border;
317
+ if(y > winman->sh)
318
+ y = winman->sh - h - 2 * c->border;
319
+ if(x + w + 2 * c->border < winman->sx)
320
+ x = winman->sx;
321
+ if(y + h + 2 * c->border < winman->sy)
322
+ y = winman->sy;
323
+ if(c->x != x || c->y != y || c->w != w || c->h != h) {
324
+ c->x = wc.x = x;
325
+ c->y = wc.y = y;
326
+ c->w = wc.width = w;
327
+ c->h = wc.height = h;
328
+ wc.border_width = c->border;
329
+ fprintf(stderr,"resize:XConfigureWindow x=%i y=%i width=%i height=%i border=%i\n", wc.x,wc.y,wc.width,wc.height,wc.border_width);
330
+ XConfigureWindow(winman->dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
331
+ XSync(winman->dpy, False);
332
+ }
333
+ }
334
+
335
+ /*
336
+ * This function "minimizes"
337
+ */
338
+ void ban_client(Client* c) {
339
+ if (c->isbanned)
340
+ return;
341
+ XMoveWindow(c->manager->dpy, c->win, c->manager->sw + 2, c->manager->sh + 2);
342
+ c->isbanned = True;
343
+ XSync(c->manager->dpy, False);
344
+ }
345
+
346
+ /*
347
+ * This function "un-minimizes"
348
+ */
349
+ void unban_client(Client*c) {
350
+ if (!(c->isbanned))
351
+ return;
352
+ XMoveWindow(c->manager->dpy, c->win, c->x, c->y);
353
+ c->isbanned = False;
354
+ XSync(c->manager->dpy, False);
355
+ }
356
+
357
+ long
358
+ getstate(WM* winman, Window w) {
359
+ int format, status;
360
+ long result = -1;
361
+ unsigned char *p = NULL;
362
+ unsigned long n, extra;
363
+ Atom real;
364
+
365
+ status = XGetWindowProperty(winman->dpy, w, winman->wmatom[WMState], 0L, 2L, False, winman->wmatom[WMState],
366
+ &real, &format, &n, &extra, (unsigned char **)&p);
367
+ if(status != Success)
368
+ return -1;
369
+ if(n != 0)
370
+ result = *p;
371
+ XFree(p);
372
+ return result;
373
+ }
374
+
375
+ int manageable_p(WM* wm, Window w) {
376
+ XWindowAttributes wa;
377
+
378
+ if (XGetWindowAttributes(wm->dpy, w, &wa)) {
379
+ if (wm->manage_override_redirect_windows) {
380
+ return (wa.map_state == IsViewable || getstate(wm,w) == IconicState);
381
+ } else {
382
+ return !wa.override_redirect &&
383
+ (wa.map_state == IsViewable || getstate(wm,w) == IconicState);
384
+ }
385
+ } else {
386
+ return 0;
387
+ }
388
+ }
389
+
390
+ /*
391
+ * This is a setup-function to fill the field
392
+ * of managed clients in the WM object.
393
+ * This should only be called during setup!
394
+ */
395
+ Client* query_clients(WM* winman) {
396
+ unsigned int i, num;
397
+ Window *wins, d1, d2;
398
+ XWindowAttributes wa;
399
+ Client* c = (Client*)malloc(sizeof(Client));
400
+
401
+ wins = NULL;
402
+ wa.width = winman->waw;
403
+ wa.height = winman->wah;
404
+ wa.x = wa.y = 0;
405
+ if (XQueryTree(winman->dpy, winman->root, &d1, &d2, &wins, &num)) {
406
+ fprintf(stderr,"Managing %i windows...\n",num);
407
+ winman->clients_num = 0;
408
+ c = (Client*)calloc(num, sizeof(Client));
409
+ for (i = 0; i < num; i++) {
410
+ if (manageable_p(winman, wins[i])) {
411
+ init_client(winman, wins[i], &c[winman->clients_num]);
412
+ manage_client(winman, &wa, &c[winman->clients_num]);
413
+ winman->clients_num += 1;
414
+ wa.x += 60;
415
+ wa.width -= 60;
416
+ wa.y += 40;
417
+ wa.height -= 40;
418
+ } else {
419
+ fprintf(stderr,"Ignoring %x (map_state=%i override_redirect=%i)\n",(int)wins[i],(int)wa.map_state,(int)wa.override_redirect);
420
+ }
421
+ }
422
+ }
423
+ if(wins)
424
+ XFree(wins);
425
+ return c;
426
+ }
427
+
428
+ /*
429
+ * This will initialize a WM object and return its adress
430
+ */
431
+ WM* Init_WM() {
432
+ WM* windowmanager;
433
+ windowmanager = calloc(1,sizeof(WM));
434
+ setlocale(LC_CTYPE, "de_DE.UTF-8");
435
+ if(!(windowmanager->dpy = XOpenDisplay(0)))
436
+ printf("Cannot open Display!!\n");fflush(stdout);
437
+ windowmanager->screen = DefaultScreen(windowmanager->dpy);
438
+ if(!(windowmanager->dpy = XOpenDisplay(0x0))) return NULL;
439
+ windowmanager->root = RootWindow(windowmanager->dpy, windowmanager->screen);
440
+
441
+ /*
442
+ XSetErrorHandler(NULL);
443
+ windowmanager->xerrorxlib = XSetErrorHandler(xerror);
444
+ XSync(windowmanager->dpy, False);
445
+ */
446
+ setup(windowmanager);
447
+ return windowmanager;
448
+ }
449
+
450
+ /*
451
+ * This will free all Client objects and the WM itself.
452
+ * This will grow with each added feature.
453
+ */
454
+ void Destroy_WM(WM* winman) {
455
+ XUngrabKey(winman->dpy, AnyKey, AnyModifier, winman->root);
456
+ XSetInputFocus(winman->dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
457
+ XSync(winman->dpy, False);
458
+ XCloseDisplay(winman->dpy);
459
+ free(winman->clients);
460
+ free(winman);
461
+ }
462
+
463
+ /*
464
+ * Here we have a test routine to test the C code by itself
465
+ */
466
+ int main() {
467
+ WM* winman;
468
+ int i;
469
+
470
+ printf("Start to init NOW!\n");fflush(stdout);
471
+ winman = Init_WM();
472
+ printf("We have a screen: %d %d %d %d\n", winman->sx, winman->sy, winman->sw, winman->sh);
473
+ printf(" ... and a window area: %d %d %d %d\n", winman->wax, winman->way, winman->waw, winman->wah);
474
+ printf("Start query NOW!\n");fflush(stdout);
475
+ winman->clients = query_clients(winman);
476
+ printf("Success! We should have clients now!\n");
477
+ printf(" And they should all have the WM ptr... (trying just the first): %d %d %d %d\n",
478
+ winman->clients[0].manager->sx, winman->clients[0].manager->sy,
479
+ winman->clients[0].manager->sw, winman->clients[0].manager->sh);
480
+ for(i=0; i < winman->clients_num; i++) {
481
+ printf(" Trying client number %d name: %s \n", i, winman->clients[i].name);
482
+ printf(" Geo: %d %d %d %d\n",
483
+ winman->clients[0].x, winman->clients[0].y, winman->clients[i].w, winman->clients[0].h);
484
+ }
485
+
486
+ printf("Great so far! Try some resizing now...\n");fflush(stdout);
487
+ resize(winman, &winman->clients[0], winman->wax, winman->way, winman->waw, winman->wah, 0);
488
+ printf("Good. Set a border around our main client now...");
489
+ border_client(&winman->clients[0], 9);
490
+
491
+ printf("Try to raise in cycles as well...\n");
492
+ for(i=0; i < winman->clients_num; i++) {
493
+ raise_client(&winman->clients[i]);
494
+ printf(" Client %d should be raised now...\n", i);fflush(stdout);
495
+ usleep(1000000);
496
+ }
497
+
498
+ printf("Ban - unban each client ...\n");
499
+ for(i=0; i < winman->clients_num; i++) {
500
+ ban_client(&winman->clients[i]);
501
+ printf(" Client %d is banned? %d \n", i, winman->clients[i].isbanned);fflush(stdout);
502
+ usleep(1000000);
503
+ unban_client(&winman->clients[i]);
504
+ printf(" ... and unbanned? %d \n", winman->clients[i].isbanned);fflush(stdout);
505
+ }
506
+
507
+ printf("Finish for now...\n");
508
+ Destroy_WM(winman);
509
+
510
+ return 0;
511
+ }
512
+