]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/clientwrap.c
speed up workspace switching by causing the minimal number of expose events (none...
[mikachu/openbox.git] / openbox / clientwrap.c
1 #include "clientwrap.h"
2 #include "client.h"
3 #include "frame.h"
4 #include "engine.h"
5 #include "stacking.h"
6 #include "focus.h"
7 #include "prop.h"
8 #include <glib.h>
9
10 /***************************************************************************
11  
12    Define the type 'ClientWrap'
13
14  ***************************************************************************/
15
16 #define IS_CWRAP(v)  ((v)->ob_type == &ClientWrapType)
17 #define IS_VALID_CWRAP(v) ((v)->client != NULL)
18 #define CHECK_CWRAP(self, funcname) { \
19     if (!IS_CWRAP(self)) { \
20         PyErr_SetString(PyExc_TypeError, \
21                         "descriptor '" funcname "' requires a 'Client' " \
22                         "object"); \
23         return NULL; \
24     } \
25     if (!IS_VALID_CWRAP(self)) { \
26         PyErr_SetString(PyExc_ValueError, \
27                         "This 'Client' is wrapping a client which no longer "\
28                         "exists."); \
29         return NULL; \
30     } \
31 }
32
33
34 staticforward PyTypeObject ClientWrapType;
35
36 /***************************************************************************
37  
38    Attribute methods
39  
40  ***************************************************************************/
41
42 static PyObject *cwrap_valid(ClientWrap *self, PyObject *args)
43 {
44     if (!IS_CWRAP(self)) {
45         PyErr_SetString(PyExc_TypeError,
46                         "descriptor 'valid' requires a 'Client' object");
47         return NULL;
48     }
49     return PyInt_FromLong(self->client != NULL);
50 }
51
52 static PyObject *cwrap_title(ClientWrap *self, PyObject *args)
53 {
54     CHECK_CWRAP(self, "title");
55     if (!PyArg_ParseTuple(args, ":title"))
56         return NULL;
57     return PyString_FromString(self->client->title);
58 }
59
60 static PyObject *cwrap_setTitle(ClientWrap *self, PyObject *args)
61 {
62     char *title;
63
64     CHECK_CWRAP(self, "setTitle");
65     if (!PyArg_ParseTuple(args, "s:setTitle", &title))
66         return NULL;
67
68     PROP_SETS(self->client->window, net_wm_name, utf8, title);
69
70     Py_INCREF(Py_None);
71     return Py_None;
72 }
73
74 static PyObject *cwrap_iconTitle(ClientWrap *self, PyObject *args)
75 {
76     CHECK_CWRAP(self, "iconTitle");
77     if (!PyArg_ParseTuple(args, ":iconTitle"))
78         return NULL;
79     return PyString_FromString(self->client->icon_title);
80 }
81
82 static PyObject *cwrap_setIconTitle(ClientWrap *self, PyObject *args)
83 {
84     char *title;
85
86     CHECK_CWRAP(self, "setIconTitle");
87     if (!PyArg_ParseTuple(args, "s:setIconTitle", &title))
88         return NULL;
89
90     PROP_SETS(self->client->window, net_wm_icon_name, utf8, title);
91
92     Py_INCREF(Py_None);
93     return Py_None;
94 }
95
96 static PyObject *cwrap_desktop(ClientWrap *self, PyObject *args)
97 {
98     CHECK_CWRAP(self, "desktop");
99     if (!PyArg_ParseTuple(args, ":desktop"))
100         return NULL;
101     return PyInt_FromLong(self->client->desktop);
102 }
103
104 static PyObject *cwrap_setDesktop(ClientWrap *self, PyObject *args)
105 {
106     int desktop;
107     CHECK_CWRAP(self, "setDesktop");
108     if (!PyArg_ParseTuple(args, "i:setDesktop", &desktop))
109         return NULL;
110     client_set_desktop(self->client, desktop);
111     Py_INCREF(Py_None);
112     return Py_None;
113 }
114
115 static PyObject *cwrap_resName(ClientWrap *self, PyObject *args)
116 {
117     CHECK_CWRAP(self, "resName");
118     if (!PyArg_ParseTuple(args, ":resName"))
119         return NULL;
120     return PyString_FromString(self->client->res_name);
121 }
122
123 static PyObject *cwrap_resClass(ClientWrap *self, PyObject *args)
124 {
125     CHECK_CWRAP(self, "resClass");
126     if (!PyArg_ParseTuple(args, ":resClass"))
127         return NULL;
128     return PyString_FromString(self->client->res_class);
129 }
130
131 static PyObject *cwrap_role(ClientWrap *self, PyObject *args)
132 {
133     CHECK_CWRAP(self, "role");
134     if (!PyArg_ParseTuple(args, ":role"))
135         return NULL;
136     return PyString_FromString(self->client->role);
137 }
138
139 static PyObject *cwrap_transient(ClientWrap *self, PyObject *args)
140 {
141     CHECK_CWRAP(self, "transient");
142     if (!PyArg_ParseTuple(args, ":transient"))
143         return NULL;
144     return PyInt_FromLong(!!self->client->transient);
145 }
146
147 static PyObject *cwrap_transientFor(ClientWrap *self, PyObject *args)
148 {
149     CHECK_CWRAP(self, "transientFor");
150     if (!PyArg_ParseTuple(args, ":transientFor"))
151         return NULL;
152     if (self->client->transient_for != NULL)
153         return clientwrap_new(self->client->transient_for);
154     Py_INCREF(Py_None);
155     return Py_None;
156 }
157
158 static PyObject *cwrap_transients(ClientWrap *self, PyObject *args)
159 {
160     PyObject *tuple;
161     GSList *it;
162     guint i, s;
163
164     CHECK_CWRAP(self, "transients");
165     if (!PyArg_ParseTuple(args, ":transients"))
166         return NULL;
167     s = g_slist_length(self->client->transients);
168     tuple = PyTuple_New(s);
169     for (i = 0, it = self->client->transients; i < s; ++i, it = it->next)
170         PyTuple_SET_ITEM(tuple, i, clientwrap_new(it->data));
171     return tuple;
172 }
173
174 static PyObject *cwrap_type(ClientWrap *self, PyObject *args)
175 {
176     CHECK_CWRAP(self, "type");
177     if (!PyArg_ParseTuple(args, ":type"))
178         return NULL;
179     return PyInt_FromLong(self->client->type);
180 }
181
182 static PyObject *cwrap_normal(ClientWrap *self, PyObject *args)
183 {
184     CHECK_CWRAP(self, "normal");
185     if (!PyArg_ParseTuple(args, ":normal"))
186         return NULL;
187     return PyInt_FromLong(!!client_normal(self->client));
188 }
189
190 static PyObject *cwrap_area(ClientWrap *self, PyObject *args)
191 {
192     PyObject *tuple;
193
194     CHECK_CWRAP(self, "area");
195     if (!PyArg_ParseTuple(args, ":area"))
196         return NULL;
197     tuple = PyTuple_New(4);
198     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->frame->area.x));
199     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->frame->area.y));
200     PyTuple_SET_ITEM(tuple, 2,
201                      PyInt_FromLong(self->client->frame->area.width));
202     PyTuple_SET_ITEM(tuple, 3,
203                      PyInt_FromLong(self->client->frame->area.height));
204     return tuple;
205 }
206
207 static PyObject *cwrap_setArea(ClientWrap *self, PyObject *args)
208 {
209     int x, y, w, h, final = TRUE;
210
211     CHECK_CWRAP(self, "setArea");
212     if (!PyArg_ParseTuple(args, "(iiii)|i:setArea", &x, &y, &w, &h, &final))
213         return NULL;
214
215     frame_frame_gravity(self->client->frame, &x, &y);
216     w -= self->client->frame->size.left + self->client->frame->size.right;
217     h -= self->client->frame->size.top + self->client->frame->size.bottom;
218     client_configure(self->client, Corner_TopLeft, x, y, w, h, TRUE, final);
219
220     Py_INCREF(Py_None);
221     return Py_None;
222 }
223
224 static PyObject *cwrap_clientArea(ClientWrap *self, PyObject *args)
225 {
226     PyObject *tuple;
227
228     CHECK_CWRAP(self, "clientArea");
229     if (!PyArg_ParseTuple(args, ":clientArea"))
230         return NULL;
231     tuple = PyTuple_New(4);
232     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->area.x));
233     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->area.y));
234     PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(self->client->area.width));
235     PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(self->client->area.height));
236     return tuple;
237 }
238
239 static PyObject *cwrap_setClientArea(ClientWrap *self, PyObject *args)
240 {
241     int x, y, w, h;
242
243     CHECK_CWRAP(self, "setClientArea");
244     if (!PyArg_ParseTuple(args, "(iiii)|i:setClientArea", &x, &y, &w, &h))
245         return NULL;
246
247     client_configure(self->client, Corner_TopLeft, x, y, w, h, TRUE, TRUE);
248
249     Py_INCREF(Py_None);
250     return Py_None;
251 }
252
253 static PyObject *cwrap_frameSize(ClientWrap *self, PyObject *args)
254 {
255     PyObject *tuple;
256
257     CHECK_CWRAP(self, "frameSize");
258     if (!PyArg_ParseTuple(args, ":frameSize"))
259         return NULL;
260     tuple = PyTuple_New(4);
261     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->frame->size.left));
262     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->frame->size.top));
263     PyTuple_SET_ITEM(tuple, 2,
264                      PyInt_FromLong(self->client->frame->size.right));
265     PyTuple_SET_ITEM(tuple, 3,
266                      PyInt_FromLong(self->client->frame->size.bottom));
267     return tuple;
268 }
269
270 static PyObject *cwrap_strut(ClientWrap *self, PyObject *args)
271 {
272     PyObject *tuple;
273
274     CHECK_CWRAP(self, "strut");
275     if (!PyArg_ParseTuple(args, ":strut"))
276         return NULL;
277     tuple = PyTuple_New(4);
278     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->strut.left));
279     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->strut.top));
280     PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(self->client->strut.right));
281     PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(self->client->strut.bottom));
282     return tuple;
283 }
284
285 static PyObject *cwrap_logicalSize(ClientWrap *self, PyObject *args)
286 {
287     PyObject *tuple;
288
289     CHECK_CWRAP(self, "logicalSize");
290     if (!PyArg_ParseTuple(args, ":logicalSize"))
291         return NULL;
292     tuple = PyTuple_New(2);
293     PyTuple_SET_ITEM(tuple, 0,
294                      PyInt_FromLong(self->client->logical_size.width));
295     PyTuple_SET_ITEM(tuple, 1,
296                      PyInt_FromLong(self->client->logical_size.height));
297     return tuple;
298 }
299
300 static PyObject *cwrap_canFocus(ClientWrap *self, PyObject *args)
301 {
302     CHECK_CWRAP(self, "canFocus");
303     if (!PyArg_ParseTuple(args, ":canFocus"))
304         return NULL;
305     return PyInt_FromLong(!!self->client->can_focus);
306 }
307
308 static PyObject *cwrap_focus(ClientWrap *self, PyObject *args)
309 {
310     int focus = TRUE;
311
312     CHECK_CWRAP(self, "focus");
313     if (!PyArg_ParseTuple(args, "|i:focus", &focus))
314         return NULL;
315     if (focus)
316         return PyInt_FromLong(!!client_focus(self->client));
317     else {
318         if (focus_client == self->client)
319             client_unfocus(self->client);
320         Py_INCREF(Py_None);
321         return Py_None;
322     }
323 }
324
325 static PyObject *cwrap_focused(ClientWrap *self, PyObject *args)
326 {
327     CHECK_CWRAP(self, "focused");
328     if (!PyArg_ParseTuple(args, ":focused"))
329         return NULL;
330     return PyInt_FromLong(!!self->client->focused);
331 }
332
333 static PyObject *cwrap_visible(ClientWrap *self, PyObject *args)
334 {
335     CHECK_CWRAP(self, "visible");
336     if (!PyArg_ParseTuple(args, ":visible"))
337         return NULL;
338     return PyInt_FromLong(!!self->client->frame->visible);
339 }
340
341 static PyObject *cwrap_setVisible(ClientWrap *self, PyObject *args)
342 {
343     int show;
344
345     CHECK_CWRAP(self, "setVisible");
346     if (!PyArg_ParseTuple(args, "i:setVisible", &show))
347         return NULL;
348     if (show)
349         engine_frame_show(self->client->frame);
350     else
351         engine_frame_hide(self->client->frame);
352     Py_INCREF(Py_None);
353     return Py_None;
354 }
355
356 static PyObject *cwrap_modal(ClientWrap *self, PyObject *args)
357 {
358     CHECK_CWRAP(self, "modal");
359     if (!PyArg_ParseTuple(args, ":modal"))
360         return NULL;
361     return PyInt_FromLong(!!self->client->modal);
362 }
363
364 static PyObject *cwrap_setModal(ClientWrap *self, PyObject *args)
365 {
366     int modal;
367
368     CHECK_CWRAP(self, "setModal");
369     if (!PyArg_ParseTuple(args, "i:setModal", &modal))
370         return NULL;
371
372     client_set_state(self->client,
373                      (modal ? prop_atoms.net_wm_state_add :
374                       prop_atoms.net_wm_state_remove),
375                      prop_atoms.net_wm_state_modal, 0);
376
377     Py_INCREF(Py_None);
378     return Py_None;
379 }
380
381 static PyObject *cwrap_shaded(ClientWrap *self, PyObject *args)
382 {
383     CHECK_CWRAP(self, "shaded");
384     if (!PyArg_ParseTuple(args, ":shaded"))
385         return NULL;
386     return PyInt_FromLong(!!self->client->shaded);
387 }
388
389 static PyObject *cwrap_setShaded(ClientWrap *self, PyObject *args)
390 {
391     int shaded;
392
393     CHECK_CWRAP(self, "setShaded");
394     if (!PyArg_ParseTuple(args, "i:setShaded", &shaded))
395         return NULL;
396
397     client_shade(self->client, shaded);
398
399     Py_INCREF(Py_None);
400     return Py_None;
401 }
402
403 static PyObject *cwrap_iconic(ClientWrap *self, PyObject *args)
404 {
405     CHECK_CWRAP(self, "iconic");
406     if (!PyArg_ParseTuple(args, ":iconic"))
407         return NULL;
408     return PyInt_FromLong(!!self->client->iconic);
409 }
410
411 static PyObject *cwrap_setIconic(ClientWrap *self, PyObject *args)
412 {
413     int iconify, current = TRUE;
414
415     CHECK_CWRAP(self, "setIconic");
416     if (!PyArg_ParseTuple(args, "i|i:setIconic", &iconify, &current))
417         return NULL;
418
419     client_iconify(self->client, iconify, current);
420
421     Py_INCREF(Py_None);
422     return Py_None;
423 }
424
425 static PyObject *cwrap_maximizedHorz(ClientWrap *self, PyObject *args)
426 {
427     CHECK_CWRAP(self, "maximizedHorz");
428     if (!PyArg_ParseTuple(args, ":maximizedHorz"))
429         return NULL;
430     return PyInt_FromLong(!!self->client->max_horz);
431 }
432
433 static PyObject *cwrap_setMaximizedHorz(ClientWrap *self, PyObject *args)
434 {
435     int max;
436
437     CHECK_CWRAP(self, "setMaximizedHorz");
438     if (!PyArg_ParseTuple(args, "i:setMaximizedHorz", &max))
439         return NULL;
440
441     client_set_state(self->client,
442                      (max ? prop_atoms.net_wm_state_add :
443                       prop_atoms.net_wm_state_remove),
444                      prop_atoms.net_wm_state_maximized_horz, 0);
445
446     Py_INCREF(Py_None);
447     return Py_None;
448 }
449
450 static PyObject *cwrap_maximizedVert(ClientWrap *self, PyObject *args)
451 {
452     CHECK_CWRAP(self, "maximizedVert");
453     if (!PyArg_ParseTuple(args, ":maximizedVert"))
454         return NULL;
455     return PyInt_FromLong(!!self->client->max_vert);
456 }
457
458 static PyObject *cwrap_setMaximizedVert(ClientWrap *self, PyObject *args)
459 {
460     int max;
461
462     CHECK_CWRAP(self, "setMaximizedVert");
463     if (!PyArg_ParseTuple(args, "i:setMaximizedVert", &max))
464         return NULL;
465
466     client_set_state(self->client,
467                      (max ? prop_atoms.net_wm_state_add :
468                       prop_atoms.net_wm_state_remove),
469                      prop_atoms.net_wm_state_maximized_vert, 0);
470
471     Py_INCREF(Py_None);
472     return Py_None;
473 }
474
475 static PyObject *cwrap_maximized(ClientWrap *self, PyObject *args)
476 {
477     CHECK_CWRAP(self, "maximized");
478     if (!PyArg_ParseTuple(args, ":maximized"))
479         return NULL;
480     return PyInt_FromLong(self->client->max_vert || self->client->max_horz);
481 }
482
483 static PyObject *cwrap_setMaximized(ClientWrap *self, PyObject *args)
484 {
485     int max;
486
487     CHECK_CWRAP(self, "setMaximized");
488     if (!PyArg_ParseTuple(args, "i:setMaximized", &max))
489         return NULL;
490
491     client_set_state(self->client,
492                      (max ? prop_atoms.net_wm_state_add :
493                       prop_atoms.net_wm_state_remove),
494                      prop_atoms.net_wm_state_maximized_vert,
495                      prop_atoms.net_wm_state_maximized_horz);
496
497     Py_INCREF(Py_None);
498     return Py_None;
499 }
500
501 static PyObject *cwrap_fullscreen(ClientWrap *self, PyObject *args)
502 {
503     CHECK_CWRAP(self, "fullscreen");
504     if (!PyArg_ParseTuple(args, ":fullscreen"))
505         return NULL;
506     return PyInt_FromLong(!!self->client->fullscreen);
507 }
508
509 static PyObject *cwrap_setFullscreen(ClientWrap *self, PyObject *args)
510 {
511     int fs;
512
513     CHECK_CWRAP(self, "setFullscreen");
514     if (!PyArg_ParseTuple(args, "i:setFullscreen", &fs))
515         return NULL;
516
517     client_set_state(self->client,
518                      (fs ? prop_atoms.net_wm_state_add :
519                       prop_atoms.net_wm_state_remove),
520                      prop_atoms.net_wm_state_fullscreen, 0);
521
522     Py_INCREF(Py_None);
523     return Py_None;
524 }
525
526 static PyObject *cwrap_stacking(ClientWrap *self, PyObject *args)
527 {
528     CHECK_CWRAP(self, "stacking");
529     if (!PyArg_ParseTuple(args, ":stacking"))
530         return NULL;
531     return PyInt_FromLong(self->client->above ? 1 :
532                           self->client->below ? -1 : 0);
533 }
534
535 static PyObject *cwrap_setStacking(ClientWrap *self, PyObject *args)
536 {
537     int stack;
538
539     CHECK_CWRAP(self, "setStacking");
540     if (!PyArg_ParseTuple(args, "i:setStacking", &stack))
541         return NULL;
542     client_set_state(self->client,
543                      (stack > 0 ? prop_atoms.net_wm_state_add :
544                       prop_atoms.net_wm_state_remove),
545                      prop_atoms.net_wm_state_above, 0);
546     client_set_state(self->client,
547                      (stack < 0 ? prop_atoms.net_wm_state_add :
548                       prop_atoms.net_wm_state_remove),
549                      prop_atoms.net_wm_state_below, 0);
550     Py_INCREF(Py_None);
551     return Py_None;
552 }
553
554 static PyObject *cwrap_raiseWindow(ClientWrap *self, PyObject *args)
555 {
556     CHECK_CWRAP(self, "raiseWindow");
557     if (!PyArg_ParseTuple(args, ":raiseWindow"))
558         return NULL;
559     stacking_raise(self->client);
560     Py_INCREF(Py_None);
561     return Py_None;
562 }
563
564 static PyObject *cwrap_lowerWindow(ClientWrap *self, PyObject *args)
565 {
566     CHECK_CWRAP(self, "lowerWindow");
567     if (!PyArg_ParseTuple(args, ":lowerWindow"))
568         return NULL;
569     stacking_lower(self->client);
570     Py_INCREF(Py_None);
571     return Py_None;
572 }
573
574 static PyObject *cwrap_skipPager(ClientWrap *self, PyObject *args)
575 {
576     CHECK_CWRAP(self, "skipPager");
577     if (!PyArg_ParseTuple(args, ":skipPager"))
578         return NULL;
579     return PyInt_FromLong(!!self->client->skip_pager);
580 }
581
582 static PyObject *cwrap_setSkipPager(ClientWrap *self, PyObject *args)
583 {
584     int skip;
585
586     CHECK_CWRAP(self, "setSkipPager");
587     if (!PyArg_ParseTuple(args, "i:setSkipPager", &skip))
588         return NULL;
589
590     client_set_state(self->client,
591                      (skip ? prop_atoms.net_wm_state_add :
592                       prop_atoms.net_wm_state_remove),
593                      prop_atoms.net_wm_state_skip_pager, 0);
594
595     Py_INCREF(Py_None);
596     return Py_None;
597 }
598
599 static PyObject *cwrap_skipTaskbar(ClientWrap *self, PyObject *args)
600 {
601     CHECK_CWRAP(self, "skipTaskbar");
602     if (!PyArg_ParseTuple(args, ":skipTaskbar"))
603         return NULL;
604     return PyInt_FromLong(!!self->client->skip_taskbar);
605 }
606
607 static PyObject *cwrap_setSkipTaskbar(ClientWrap *self, PyObject *args)
608 {
609     int skip;
610
611     CHECK_CWRAP(self, "setSkipTaskbar");
612     if (!PyArg_ParseTuple(args, "i:setSkipTaskbar", &skip))
613         return NULL;
614
615     client_set_state(self->client,
616                      (skip ? prop_atoms.net_wm_state_add :
617                       prop_atoms.net_wm_state_remove),
618                      prop_atoms.net_wm_state_skip_taskbar, 0);
619
620     Py_INCREF(Py_None);
621     return Py_None;
622 }
623
624 static PyObject *cwrap_disableDecorations(ClientWrap *self, PyObject *args)
625 {
626     int title, handle, border;
627
628     CHECK_CWRAP(self, "disableDecorations");
629     if (!PyArg_ParseTuple(args, "iii:disableDecorations", &title, &handle,
630                           &border))
631         return NULL;
632
633     self->client->disabled_decorations = 0;
634     if (title) self->client->disabled_decorations |= Decor_Titlebar;
635     if (handle) self->client->disabled_decorations |= Decor_Handle;
636     if (border) self->client->disabled_decorations |= Decor_Border;
637     client_setup_decor_and_functions(self->client);
638
639     Py_INCREF(Py_None);
640     return Py_None;
641 }
642
643 static PyObject *cwrap_close(ClientWrap *self, PyObject *args)
644 {
645     CHECK_CWRAP(self, "close");
646     if (!PyArg_ParseTuple(args, ":close"))
647         return NULL;
648     client_close(self->client);
649     Py_INCREF(Py_None);
650     return Py_None;
651 }
652
653 static PyObject *cwrap_window(ClientWrap *self, PyObject *args)
654 {
655     CHECK_CWRAP(self, "window");
656     if (!PyArg_ParseTuple(args, ":window"))
657         return NULL;
658     return PyInt_FromLong(self->client->window);
659 }
660
661 #define METH(n, d) {#n, (PyCFunction)cwrap_##n, METH_VARARGS, #d}
662
663 static PyMethodDef ClientWrapMethods[] = {
664     METH(valid,
665          "Returns if the Client instance is still valid. Client instances are "
666          "marked as invalid when the Client they are associated is "
667          "closed/destroyed/released."),
668     METH(title,
669          "Returns the client's title."),
670     METH(setTitle,
671          "Change the client's title to the given string. This change will be "
672          "overwritten if/when the client changes its title."),
673     METH(iconTitle,
674          "Returns's the client's icon title. The icon title is the title to "
675          "be displayed when the client is iconified."),
676     METH(setIconTitle,
677          "Change the client's icon title to the given string. This change "
678          "will be overwritten if/when the client changes its icon title."),
679     METH(desktop,
680          "Returns the desktop on which the client is visible. This value will "
681          "always be in the range [0, ob.Openbox.numDesktops()), unless it is "
682          "0xffffffff. A value of 0xffffffff indicates the client is visible "
683          "on all desktops."),
684     METH(setDesktop,
685          "Moves the client to the specified desktop. The desktop must be in "
686          "the range [0, ob.Openbox.numDesktops()), unless it is 0xffffffff. A "
687          "value of 0xffffffff indicates the client is visible on all "
688          "desktops."),
689     METH(resName,
690          "Returns the resouce name of the client. The resource name is meant "
691          "to provide an instance name for the client."),
692     METH(resClass,
693          "Returns the resouce class of the client. The resource class is "
694          "meant to provide the genereal class of the application. e.g. "
695          "'Emacs', 'Xterm', 'XClock', 'XLoad', and so on."),
696     METH(role,
697          "Returns the client's role. The role is meant to distinguish between "
698          "different windows of an application. Each window should have a "
699          "unique role."),
700     METH(transient,
701          "Returns True or False describing if the client is a transient "
702          "window. Transient windows are 'temporary' windows, such as "
703          "preference dialogs, and usually have a parent window, which can be "
704          "found from transientFor()."),
705     METH(transientFor,
706          "Returns the client for which this client is a transient. See "
707          "transient() for a description of transience."),
708     METH(transients,
709          "Returns a tuple containing all the Clients which are transients of "
710          "this window. See transient() for a description of transience."),
711     METH(type,
712          "Returns the logical type of the window. This is one of the "
713          "ClientType constants. See also normal()."),
714     METH(normal,
715          "Returns True or False for if the client is a 'normal' window. "
716          "Normal windows make up most applications. Non-normal windows have "
717          "special rules applied to them at times such as for focus handling. "
718          "An example of a non-normal window is 'gnome-panel'. This value is "
719          "determined from the client's type(), but does not imply that the "
720          "window is ClientType.Normal. Rather this is a more generic "
721          "definition of 'normal' windows, and includes dialogs and others."),
722     METH(area,
723          "Returns the area of the screen which the client occupies. It may be "
724          "important to note that this is the position and size of the client "
725          "*with* its decorations. If you want the underlying position and "
726          "size of the client itself, you should use clientArea(). See also "
727          "logicalSize()."),
728     
729     METH(setArea,
730          "Sets the client's area, moving and resizing it as specified (or as "
731          "close as can be accomidated)."),
732     METH(clientArea,
733          "Returns the area of the screen which the client considers itself to "
734          "be occupying. This value is not what you see and should not be used "
735          "for most things (it should, for example, be used for persisting a "
736          "client's dimentions across sessions). See also area()."),
737     METH(setClientArea,
738          "Sets the area of the screen which the client considers itself to be "
739          "occupying. This is not the on-screen visible position and size, and "
740          "should be used with care. You probably want to use setArea() to "
741          "adjust the client. This should be used if you want the client "
742          "window (inside the decorations) to be a specific size. Adjusting "
743          "the client's position with this function is probably always a bad "
744          "idea, because of window gravity."),
745     METH(strut,
746          "Returns the application's specified strut. The strut is the amount "
747          "of space that should be reserved for the application on each side "
748          "of the screen."),
749     METH(frameSize,
750          "Returns the size of the decorations around the client window."),
751     METH(logicalSize,
752          "Returns the client's logical size. The logical size is the client's "
753          "size in more user friendly terms. For many apps this is simply the "
754          "size of the client in pixels, however for some apps this will "
755          "differ (e.g. terminal emulators). This value should be used when "
756          "displaying an applications size to the user."),
757     METH(canFocus,
758          "Returns True or False for if the client can be focused."),
759     METH(focus,
760          "Focuses (or unfocuses) the client window. Windows which return "
761          "False for canFocus() or visible() cannot be focused. When this "
762          "function returns, the client's focused() state will not be changed "
763          "yet. This only sends the request through the X server. You should "
764          "wait for the hooks.focused hook to fire, and not assume the client "
765          "has been focused."),
766     METH(focused,
767          "Returns True or False for if the client has the input focus."),
768     METH(visible,
769          "Returns True or False for if the client is visible. A client is not "
770          "visible if it is iconic() or if its desktop() is not visible."),
771     METH(setVisible,
772          "Shows or hides the client. This has no effect if its current "
773          "visible() state is requested."),
774     METH(modal,
775          "Returns True or False for if the client is a modal window. Modal "
776          "windows indicate that they must be dealt with before the program "
777          "can continue. When a modal window is a transient(), its "
778          "transientFor() client cannot be focused or raised above it."),
779     METH(setModal,
780          "Make the client window modal or non-modal."),
781     METH(shaded,
782          "Returns True or False for if the client is shaded. Shaded windows "
783          "have only their titlebar decorations showing."),
784     METH(setShaded,
785          "Shade or unshade the client. Shaded windows have only their "
786          "titlebar decorations showing. Windows which do not have a titlebar "
787          "cannot be shaded."),
788     METH(iconic,
789          "Returns True or False for if the window is iconified. Iconified "
790          "windows are not visible on any desktops."),
791     METH(setIconic,
792          "Iconifies or restores the client window. Iconified windows are not "
793          "visible on any desktops. Iconified windows can be restored to the "
794          "currently visible desktop or to their original (native) desktop."),
795     METH(maximizedHorz,
796          "Returns whether the client is maximized in the horizontal "
797          "direction."),
798     METH(setMaximizedHorz,
799          "Maximizes or restores a client horizontally."),
800     METH(maximizedVert,
801          "Returns whether the client is maximized in the vertical direction."),
802     METH(setMaximizedVert,
803          "Maximizes or restores a client vertically."),
804     METH(maximized,
805          "Returns whether the client is maximized in the horizontal or "
806          "vertical direction."),
807     METH(setMaximized,
808          "Maximizes or restores a client vertically and horzontally."),
809     METH(fullscreen,
810          "Returns if the client is in fullscreen mode. Fullscreen windows are "
811          "kept above all other windows and are stretched to fill the entire "
812          "physical display."),
813     METH(setFullscreen,
814          "Set a client into or out of fullscreen mode. Fullscreen windows are "
815          "kept above all other windows and are stretched to fill the entire "
816          "physical display."),
817     METH(stacking,
818          "Returns if the client will be stacked above/below other clients in "
819          "the same layer."),
820     METH(setStacking,
821          "Set how the client will be stacked according to other clients in "
822          "its layer."),
823     METH(raiseWindow,
824          "Raises the window to the top of its stacking layer."),
825     METH(lowerWindow,
826          "Lowers the window to the bottom of its stacking layer."),
827     METH(skipPager,
828          "Returns if the client has requested to be skipped (not displayed) "
829          "by pagers."),
830     METH(setSkipPager,
831          "Set whether the client should be skipped (not displayed) by "
832          "pagers."),
833     METH(skipTaskbar,
834          "Returns if the client has requested to be skipped (not displayed) "
835          "by taskbars."),
836     METH(setSkipTaskbar,
837          "Set whether the client should be skipped (not displayed) by "
838          "taskbars."),
839     METH(disableDecorations,
840          "Choose which decorations to disable on the client. Note that "
841          "decorations can only be disabled, and decorations that would "
842          "normally not be shown cannot be added. These values may have "
843          "slightly different meanings in different theme engines."),
844     METH(close,
845          "Requests the client to close its window."),
846     METH(window,
847          "Returns the client's window id. This is the id by which the X "
848          "server knows the client."),
849     { NULL, NULL, 0, NULL }
850 };
851
852 /***************************************************************************
853  
854    Type methods/struct
855  
856  ***************************************************************************/
857
858 /*static PyObject *cwrap_getattr(ClientWrap *self, char *name)
859 {
860     CHECK_CWRAP(self, "getattr");
861     return Py_FindMethod(ClientWrapAttributeMethods, (PyObject*)self, name);
862 }*/
863
864 static void cwrap_dealloc(ClientWrap *self)
865 {
866     if (self->client != NULL)
867         self->client->wrap = NULL;
868     PyObject_Del((PyObject*) self);
869 }
870
871 static PyObject *cwrap_repr(ClientWrap *self)
872 {
873      CHECK_CWRAP(self, "repr");
874      return PyString_FromFormat("Client: 0x%x", (guint)self->client->window);
875 }
876
877 static int cwrap_compare(ClientWrap *self, ClientWrap *other)
878 {
879     Window w1, w2;
880     if (!IS_VALID_CWRAP(self)) {
881         PyErr_SetString(PyExc_ValueError,
882                         "This 'Client' is wrapping a client which no longer "
883                         "exists.");
884     }
885
886     w1 = self->client->window;
887     w2 = other->client->window;
888     return w1 > w2 ? 1 : w1 < w2 ? -1 : 0;
889 }
890
891 static PyTypeObject ClientWrapType = {
892     PyObject_HEAD_INIT(NULL)
893     0,
894     "Client",
895     sizeof(ClientWrap),
896     0,
897     (destructor) cwrap_dealloc,     /*tp_dealloc*/
898     0,                              /*tp_print*/
899     0,                              /*tp_getattr*/
900     0,                              /*tp_setattr*/
901     (cmpfunc) cwrap_compare,        /*tp_compare*/
902     (reprfunc) cwrap_repr,          /*tp_repr*/
903     0,                              /*tp_as_number*/
904     0,                              /*tp_as_sequence*/
905     0,                              /*tp_as_mapping*/
906     0,                              /*tp_hash */
907 };
908
909
910 /***************************************************************************
911  
912    Define the type 'ClientType'
913
914  ***************************************************************************/
915
916 #define IS_CTYPE(v)  ((v)->ob_type == &ClientTypeType)
917 #define CHECK_CTYPE(self, funcname) { \
918     if (!IS_CTYPE(self)) { \
919         PyErr_SetString(PyExc_TypeError, \
920                         "descriptor '" funcname "' requires a 'ClientType' " \
921                         "object"); \
922         return NULL; \
923     } \
924 }
925
926 staticforward PyTypeObject ClientTypeType;
927
928 typedef struct ClientType {
929     PyObject_HEAD
930 } ClientType;
931
932 static void ctype_dealloc(PyObject *self)
933 {
934     PyObject_Del(self);
935 }
936
937 static PyObject *ctype_getattr(ClientType *self, char *name)
938 {
939     struct S { char *name; int val; };
940     struct S s[] = {
941         { "Normal", Type_Normal },
942         { "Dialog", Type_Dialog },
943         { "Desktop", Type_Desktop },
944         { "Dock", Type_Dock },
945         { "Toolbar", Type_Toolbar },
946         { "Menu", Type_Menu },
947         { "Utility", Type_Utility },
948         { "Splash", Type_Splash },
949         { NULL, 0 } };
950     int i;
951
952     CHECK_CTYPE(self, "__getattr__");
953
954     for (i = 0; s[i].name != NULL; ++i)
955         if (!strcmp(s[i].name, name))
956             return PyInt_FromLong(s[i].val);
957     PyErr_SetString(PyExc_AttributeError, "invalid attribute");
958     return NULL;
959 }
960
961 static PyTypeObject ClientTypeType = {
962     PyObject_HEAD_INIT(NULL)
963     0,
964     "Type",
965     sizeof(ClientType),
966     0,
967     (destructor) ctype_dealloc,     /*tp_dealloc*/
968     0,                              /*tp_print*/
969     (getattrfunc) ctype_getattr,    /*tp_getattr*/
970     0,                              /*tp_setattr*/
971     0,                              /*tp_compare*/
972     0,                              /*tp_repr*/
973     0,                              /*tp_as_number*/
974     0,                              /*tp_as_sequence*/
975     0,                              /*tp_as_mapping*/
976     0,                              /*tp_hash */
977 };
978
979 /***************************************************************************
980  
981    External methods
982  
983  ***************************************************************************/
984
985 void clientwrap_startup()
986 {
987     PyObject *ob, *obdict, *type;
988
989     ClientWrapType.ob_type = &PyType_Type;
990     ClientWrapType.tp_methods = ClientWrapMethods;
991     PyType_Ready(&ClientWrapType);
992
993     ClientTypeType.ob_type = &PyType_Type;
994     PyType_Ready(&ClientTypeType);
995
996     /* get the ob module/dict */
997     ob = PyImport_ImportModule("ob"); /* new */
998     g_assert(ob != NULL);
999     obdict = PyModule_GetDict(ob); /* borrowed */
1000     g_assert(obdict != NULL);
1001
1002     /* add the Client type to the ob module */
1003     PyDict_SetItemString(obdict, "Client", (PyObject*) &ClientWrapType);
1004
1005     /* add an instance of ClientType */
1006     type = (PyObject*) PyObject_New(ClientType, &ClientTypeType);
1007     PyDict_SetItemString(obdict, "ClientType", type);
1008     Py_DECREF(type);
1009
1010     Py_DECREF(ob);
1011 }
1012
1013 void clientwrap_shutdown()
1014 {
1015 }
1016
1017 PyObject *clientwrap_new(Client *client)
1018 {
1019     g_assert(client != NULL);
1020
1021     if (client->wrap != NULL) {
1022         /* already has a wrapper! */
1023         Py_INCREF((PyObject*) client->wrap);
1024     } else {
1025         client->wrap = PyObject_New(ClientWrap, &ClientWrapType);
1026         client->wrap->client = client;
1027     }
1028     return (PyObject*) client->wrap;
1029 }