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 +5 -0
- data/ext/Makefile.test +4 -0
- data/ext/extconf.rb +26 -0
- data/ext/x11.c +512 -0
- data/ext/x11.h +76 -0
- data/ext/x11_wrap.c +712 -0
- data/lib/ruby-x11.rb +119 -0
- data/lib/windowmanager.rb +56 -0
- metadata +56 -0
data/ext/.gitignore
ADDED
data/ext/Makefile.test
ADDED
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
|
+
|