xlib_ruby 0.1

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