]> icculus.org git repositories - dana/openbox.git/blob - c/clientwrap.c
merge the C branch into HEAD
[dana/openbox.git] / c / clientwrap.c
1 #include "clientwrap.h"
2 #include "client.h"
3 #include "frame.h"
4 #include "stacking.h"
5 #include "focus.h"
6 #include <glib.h>
7
8 /***************************************************************************
9  
10    Define the type 'ClientWrap'
11
12  ***************************************************************************/
13
14 #define IS_CWRAP(v)  ((v)->ob_type == &ClientWrapType)
15 #define IS_VALID_CWRAP(v) ((v)->client != NULL)
16 #define CHECK_CWRAP(self, funcname) { \
17     if (!IS_CWRAP(self)) { \
18         PyErr_SetString(PyExc_TypeError, \
19                         "descriptor '" funcname "' requires a 'Client' " \
20                         "object"); \
21         return NULL; \
22     } \
23     if (!IS_VALID_CWRAP(self)) { \
24         PyErr_SetString(PyExc_ValueError, \
25                         "This 'Client' is wrapping a client which no longer "\
26                         "exists."); \
27         return NULL; \
28     } \
29 }
30
31
32 staticforward PyTypeObject ClientWrapType;
33
34 /***************************************************************************
35  
36    Attribute methods
37  
38  ***************************************************************************/
39
40 static PyObject *cwrap_window(ClientWrap *self, PyObject *args)
41 {
42     CHECK_CWRAP(self, "window");
43     if (!PyArg_ParseTuple(args, ":window"))
44         return NULL;
45     return PyInt_FromLong(self->client->window);
46 }
47
48 static PyObject *cwrap_group(ClientWrap *self, PyObject *args)
49 {
50     CHECK_CWRAP(self, "group");
51     if (!PyArg_ParseTuple(args, ":group"))
52         return NULL;
53     return PyInt_FromLong(self->client->group);
54 }
55
56 static PyObject *cwrap_parent(ClientWrap *self, PyObject *args)
57 {
58     CHECK_CWRAP(self, "parent");
59     if (!PyArg_ParseTuple(args, ":parent"))
60         return NULL;
61     if (self->client->transient_for != NULL)
62         return clientwrap_new(self->client->transient_for);
63     Py_INCREF(Py_None);
64     return Py_None;
65 }
66
67 static PyObject *cwrap_children(ClientWrap *self, PyObject *args)
68 {
69     PyObject *list;
70     GSList *it;
71     guint i, s;
72
73     CHECK_CWRAP(self, "children");
74     if (!PyArg_ParseTuple(args, ":children"))
75         return NULL;
76     s = g_slist_length(self->client->transients);
77     list = PyList_New(s);
78     for (i = 0, it = self->client->transients; i < s; ++i, it = it->next)
79         PyList_SET_ITEM(list, i, clientwrap_new(it->data));
80     return list;
81 }
82
83 static PyObject *cwrap_desktop(ClientWrap *self, PyObject *args)
84 {
85     CHECK_CWRAP(self, "desktop");
86     if (!PyArg_ParseTuple(args, ":desktop"))
87         return NULL;
88     return PyInt_FromLong(self->client->desktop);
89 }
90
91 static PyObject *cwrap_title(ClientWrap *self, PyObject *args)
92 {
93     CHECK_CWRAP(self, "title");
94     if (!PyArg_ParseTuple(args, ":title"))
95         return NULL;
96     return PyString_FromString(self->client->title);
97 }
98
99 static PyObject *cwrap_iconTitle(ClientWrap *self, PyObject *args)
100 {
101     CHECK_CWRAP(self, "iconTitle");
102     if (!PyArg_ParseTuple(args, ":iconTitle"))
103         return NULL;
104     return PyString_FromString(self->client->icon_title);
105 }
106
107 static PyObject *cwrap_resName(ClientWrap *self, PyObject *args)
108 {
109     CHECK_CWRAP(self, "resName");
110     if (!PyArg_ParseTuple(args, ":resName"))
111         return NULL;
112     return PyString_FromString(self->client->res_name);
113 }
114
115 static PyObject *cwrap_resClass(ClientWrap *self, PyObject *args)
116 {
117     CHECK_CWRAP(self, "resClass");
118     if (!PyArg_ParseTuple(args, ":resClass"))
119         return NULL;
120     return PyString_FromString(self->client->res_class);
121 }
122
123 static PyObject *cwrap_role(ClientWrap *self, PyObject *args)
124 {
125     CHECK_CWRAP(self, "role");
126     if (!PyArg_ParseTuple(args, ":role"))
127         return NULL;
128     return PyString_FromString(self->client->role);
129 }
130
131 static PyObject *cwrap_type(ClientWrap *self, PyObject *args)
132 {
133     CHECK_CWRAP(self, "type");
134     if (!PyArg_ParseTuple(args, ":type"))
135         return NULL;
136     return PyInt_FromLong(self->client->type);
137 }
138
139 static PyObject *cwrap_area(ClientWrap *self, PyObject *args)
140 {
141     PyObject *tuple;
142
143     CHECK_CWRAP(self, "area");
144     if (!PyArg_ParseTuple(args, ":area"))
145         return NULL;
146     tuple = PyTuple_New(4);
147     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->area.x));
148     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->area.y));
149     PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(self->client->area.width));
150     PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(self->client->area.height));
151     return tuple;
152 }
153
154 static PyObject *cwrap_screenArea(ClientWrap *self, PyObject *args)
155 {
156     PyObject *tuple;
157
158     CHECK_CWRAP(self, "screenArea");
159     if (!PyArg_ParseTuple(args, ":screenArea"))
160         return NULL;
161     tuple = PyTuple_New(4);
162     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->frame->area.x));
163     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->frame->area.y));
164     PyTuple_SET_ITEM(tuple, 2,
165                      PyInt_FromLong(self->client->frame->area.width));
166     PyTuple_SET_ITEM(tuple, 3,
167                      PyInt_FromLong(self->client->frame->area.height));
168     return tuple;
169 }
170
171 static PyObject *cwrap_strut(ClientWrap *self, PyObject *args)
172 {
173     PyObject *tuple;
174
175     CHECK_CWRAP(self, "strut");
176     if (!PyArg_ParseTuple(args, ":strut"))
177         return NULL;
178     tuple = PyTuple_New(4);
179     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->strut.left));
180     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->strut.top));
181     PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(self->client->strut.right));
182     PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(self->client->strut.bottom));
183     return tuple;
184 }
185
186 static PyObject *cwrap_logicalSize(ClientWrap *self, PyObject *args)
187 {
188     PyObject *tuple;
189
190     CHECK_CWRAP(self, "logicalSize");
191     if (!PyArg_ParseTuple(args, ":logicalSize"))
192         return NULL;
193     tuple = PyTuple_New(2);
194     PyTuple_SET_ITEM(tuple, 0,
195                      PyInt_FromLong(self->client->logical_size.width));
196     PyTuple_SET_ITEM(tuple, 1,
197                      PyInt_FromLong(self->client->logical_size.height));
198     return tuple;
199 }
200
201 static PyObject *cwrap_minRatio(ClientWrap *self, PyObject *args)
202 {
203     CHECK_CWRAP(self, "minRatio");
204     if (!PyArg_ParseTuple(args, ":minRatio"))
205         return NULL;
206     return PyFloat_FromDouble(self->client->min_ratio);
207 }
208
209 static PyObject *cwrap_maxRatio(ClientWrap *self, PyObject *args)
210 {
211     CHECK_CWRAP(self, "maxRatio");
212     if (!PyArg_ParseTuple(args, ":maxRatio"))
213         return NULL;
214     return PyFloat_FromDouble(self->client->max_ratio);
215 }
216
217 static PyObject *cwrap_minSize(ClientWrap *self, PyObject *args)
218 {
219     PyObject *tuple;
220
221     CHECK_CWRAP(self, "minSize");
222     if (!PyArg_ParseTuple(args, ":minSize"))
223         return NULL;
224     tuple = PyTuple_New(2);
225     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->min_size.width));
226     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->min_size.height));
227     return tuple;
228 }
229
230 static PyObject *cwrap_maxSize(ClientWrap *self, PyObject *args)
231 {
232     PyObject *tuple;
233
234     CHECK_CWRAP(self, "maxSize");
235     if (!PyArg_ParseTuple(args, ":maxSize"))
236         return NULL;
237     tuple = PyTuple_New(2);
238     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->max_size.width));
239     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->max_size.height));
240     return tuple;
241 }
242
243 static PyObject *cwrap_sizeIncrement(ClientWrap *self, PyObject *args)
244 {
245     PyObject *tuple;
246
247     CHECK_CWRAP(self, "sizeIncrement");
248     if (!PyArg_ParseTuple(args, ":sizeIncrement"))
249         return NULL;
250     tuple = PyTuple_New(2);
251     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->size_inc.width));
252     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->size_inc.height));
253     return tuple;
254 }
255
256 static PyObject *cwrap_baseSize(ClientWrap *self, PyObject *args)
257 {
258     PyObject *tuple;
259
260     CHECK_CWRAP(self, "baseSize");
261     if (!PyArg_ParseTuple(args, ":baseSize"))
262         return NULL;
263     tuple = PyTuple_New(2);
264     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->base_size.width));
265     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->base_size.height));
266     return tuple;
267 }
268
269 static PyObject *cwrap_gravity(ClientWrap *self, PyObject *args)
270 {
271     CHECK_CWRAP(self, "gravity");
272     if (!PyArg_ParseTuple(args, ":gravity"))
273         return NULL;
274     return PyInt_FromLong(self->client->gravity);
275 }
276
277 static PyObject *cwrap_canClose(ClientWrap *self, PyObject *args)
278 {
279     CHECK_CWRAP(self, "canClose");
280     if (!PyArg_ParseTuple(args, ":canClose"))
281         return NULL;
282     return PyInt_FromLong(self->client->delete_window ? 1 : 0);
283 }
284
285 static PyObject *cwrap_positionRequested(ClientWrap *self, PyObject *args)
286 {
287     CHECK_CWRAP(self, "positionRequested");
288     if (!PyArg_ParseTuple(args, ":positionRequested"))
289         return NULL;
290     return PyInt_FromLong(self->client->positioned ? 1 : 0);
291 }
292
293 static PyObject *cwrap_canFocus(ClientWrap *self, PyObject *args)
294 {
295     CHECK_CWRAP(self, "canFocus");
296     if (!PyArg_ParseTuple(args, ":canFocus"))
297         return NULL;
298     return PyInt_FromLong(self->client->can_focus ||
299                           self->client->focus_notify);
300 }
301
302 static PyObject *cwrap_urgent(ClientWrap *self, PyObject *args)
303 {
304     CHECK_CWRAP(self, "urgent");
305     if (!PyArg_ParseTuple(args, ":urgent"))
306         return NULL;
307     return PyInt_FromLong(self->client->urgent ? 1 : 0);
308 }
309
310 static PyObject *cwrap_focused(ClientWrap *self, PyObject *args)
311 {
312     CHECK_CWRAP(self, "focused");
313     if (!PyArg_ParseTuple(args, ":focused"))
314         return NULL;
315     return PyInt_FromLong(self->client->focused ? 1 : 0);
316 }
317
318 static PyObject *cwrap_modal(ClientWrap *self, PyObject *args)
319 {
320     CHECK_CWRAP(self, "modal");
321     if (!PyArg_ParseTuple(args, ":modal"))
322         return NULL;
323     return PyInt_FromLong(self->client->modal ? 1 : 0);
324 }
325
326 static PyObject *cwrap_shaded(ClientWrap *self, PyObject *args)
327 {
328     CHECK_CWRAP(self, "shaded");
329     if (!PyArg_ParseTuple(args, ":shaded"))
330         return NULL;
331     return PyInt_FromLong(self->client->shaded ? 1 : 0);
332 }
333
334 static PyObject *cwrap_iconic(ClientWrap *self, PyObject *args)
335 {
336     CHECK_CWRAP(self, "iconic");
337     if (!PyArg_ParseTuple(args, ":iconc"))
338         return NULL;
339     return PyInt_FromLong(self->client->iconic ? 1 : 0);
340 }
341
342 static PyObject *cwrap_maximizedVertical(ClientWrap *self, PyObject *args)
343 {
344     CHECK_CWRAP(self, "maximizedVertical");
345     if (!PyArg_ParseTuple(args, ":maximizedVertical"))
346         return NULL;
347     return PyInt_FromLong(self->client->max_vert ? 1 : 0);
348 }
349
350 static PyObject *cwrap_maximizedHorizontal(ClientWrap *self, PyObject *args)
351 {
352     CHECK_CWRAP(self, "maximizedHorizontal");
353     if (!PyArg_ParseTuple(args, ":maximizedHorizontal"))
354         return NULL;
355     return PyInt_FromLong(self->client->max_horz ? 1 : 0);
356 }
357
358 static PyObject *cwrap_skipPager(ClientWrap *self, PyObject *args)
359 {
360     CHECK_CWRAP(self, "skipPager");
361     if (!PyArg_ParseTuple(args, ":skipPager"))
362         return NULL;
363     return PyInt_FromLong(self->client->skip_pager ? 1 : 0);
364 }
365
366 static PyObject *cwrap_skipTaskbar(ClientWrap *self, PyObject *args)
367 {
368     CHECK_CWRAP(self, "skipTaskbar");
369     if (!PyArg_ParseTuple(args, ":skipTaskbar"))
370         return NULL;
371     return PyInt_FromLong(self->client->skip_taskbar ? 1 : 0);
372 }
373
374 static PyObject *cwrap_fullscreen(ClientWrap *self, PyObject *args)
375 {
376     CHECK_CWRAP(self, "fullscreen");
377     if (!PyArg_ParseTuple(args, ":fullscreen"))
378         return NULL;
379     return PyInt_FromLong(self->client->fullscreen ? 1 : 0);
380 }
381
382 static PyObject *cwrap_above(ClientWrap *self, PyObject *args)
383 {
384     CHECK_CWRAP(self, "above");
385     if (!PyArg_ParseTuple(args, ":above"))
386         return NULL;
387     return PyInt_FromLong(self->client->above ? 1 : 0);
388 }
389
390 static PyObject *cwrap_below(ClientWrap *self, PyObject *args)
391 {
392     CHECK_CWRAP(self, "below");
393     if (!PyArg_ParseTuple(args, ":below"))
394         return NULL;
395     return PyInt_FromLong(self->client->below ? 1 : 0);
396 }
397
398 static PyObject *cwrap_layer(ClientWrap *self, PyObject *args)
399 {
400     CHECK_CWRAP(self, "layer");
401     if (!PyArg_ParseTuple(args, ":layer"))
402         return NULL;
403     return PyInt_FromLong(self->client->layer);
404 }
405
406 static PyObject *cwrap_decorations(ClientWrap *self, PyObject *args)
407 {
408     CHECK_CWRAP(self, "decorations");
409     if (!PyArg_ParseTuple(args, ":decorations"))
410         return NULL;
411     return PyInt_FromLong(self->client->decorations);
412 }
413
414 static PyObject *cwrap_disabledDecorations(ClientWrap *self, PyObject *args)
415 {
416     CHECK_CWRAP(self, "disabledDecorations");
417     if (!PyArg_ParseTuple(args, ":disabledDecorations"))
418         return NULL;
419     return PyInt_FromLong(self->client->disabled_decorations);
420 }
421
422 static PyObject *cwrap_functions(ClientWrap *self, PyObject *args)
423 {
424     CHECK_CWRAP(self, "functions");
425     if (!PyArg_ParseTuple(args, ":functions"))
426         return NULL;
427     return PyInt_FromLong(self->client->functions);
428 }
429
430 static PyObject *cwrap_visible(ClientWrap *self, PyObject *args)
431 {
432     CHECK_CWRAP(self, "visible");
433     if (!PyArg_ParseTuple(args, ":visible"))
434         return NULL;
435     return PyInt_FromLong(self->client->frame->visible ? 1 : 0);
436 }
437
438 static PyObject *cwrap_decorationSize(ClientWrap *self, PyObject *args)
439 {
440     PyObject *tuple;
441
442     CHECK_CWRAP(self, "decorationSize");
443     if (!PyArg_ParseTuple(args, ":decorationSize"))
444         return NULL;
445     tuple = PyTuple_New(4);
446     PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(self->client->frame->size.left));
447     PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->client->frame->size.top));
448     PyTuple_SET_ITEM(tuple, 2,
449                      PyInt_FromLong(self->client->frame->size.right));
450     PyTuple_SET_ITEM(tuple, 3,
451                      PyInt_FromLong(self->client->frame->size.bottom));
452     return tuple;
453 }
454
455 static PyObject *cwrap_normal(ClientWrap *self, PyObject *args)
456 {
457     CHECK_CWRAP(self, "normal");
458     if (!PyArg_ParseTuple(args, ":normal"))
459         return NULL;
460     return PyInt_FromLong(client_normal(self->client) ? 1 : 0);
461 }
462
463 static PyObject *cwrap_setVisible(ClientWrap *self, PyObject *args)
464 {
465     int i;
466
467     CHECK_CWRAP(self, "setVisible");
468     if (!PyArg_ParseTuple(args, "i:setVisible", &i))
469         return NULL;
470     if (i)
471         frame_show(self->client->frame);
472     else
473         frame_hide(self->client->frame);
474     Py_INCREF(Py_None);
475     return Py_None;
476 }
477
478 static PyObject *cwrap_raiseWindow(ClientWrap *self, PyObject *args)
479 {
480     CHECK_CWRAP(self, "raiseWindow");
481     if (!PyArg_ParseTuple(args, ":raiseWindow"))
482         return NULL;
483     stacking_raise(self->client);
484     Py_INCREF(Py_None);
485     return Py_None;
486 }
487
488 static PyObject *cwrap_lowerWindow(ClientWrap *self, PyObject *args)
489 {
490     CHECK_CWRAP(self, "lowerWindow");
491     if (!PyArg_ParseTuple(args, ":lowerWindow"))
492         return NULL;
493     stacking_lower(self->client);
494     Py_INCREF(Py_None);
495     return Py_None;
496 }
497
498 static PyObject *cwrap_focus(ClientWrap *self, PyObject *args)
499 {
500     CHECK_CWRAP(self, "focus");
501     if (!PyArg_ParseTuple(args, ":focus"))
502         return NULL;
503     return PyInt_FromLong(client_focus(self->client) ? 1 : 0);
504 }
505
506 static PyObject *cwrap_unfocus(ClientWrap *self, PyObject *args)
507 {
508     CHECK_CWRAP(self, "unfocus");
509     if (!PyArg_ParseTuple(args, ":unfocus"))
510         return NULL;
511     client_unfocus(self->client);
512     Py_INCREF(Py_None);
513     return Py_None;
514 }
515
516 static PyObject *cwrap_move(ClientWrap *self, PyObject *args)
517 {
518     int x, y;
519     int final = TRUE;
520     CHECK_CWRAP(self, "move");
521     if (!PyArg_ParseTuple(args, "ii|i:unfocus", &x, &y, &final))
522         return NULL;
523     /* get the client's position based on x,y for the frame */
524     frame_frame_gravity(self->client->frame, &x, &y); 
525
526     client_configure(self->client, Corner_TopLeft, x, y,
527                      self->client->area.width, self->client->area.height,
528                      TRUE, final);
529     Py_INCREF(Py_None);
530     return Py_None;
531 }
532
533 #define ATTRMETH(n, d) {#n, (PyCFunction)cwrap_##n, METH_VARARGS, #d}
534
535 static PyMethodDef ClientWrapMethods[] = {
536     ATTRMETH(window,
537              "c.window() -- Returns the window id for the Client."),
538     ATTRMETH(group,
539              "c.group() -- Returns the group id for the Client."),
540     ATTRMETH(parent,
541              "c.parent() -- Returns the parent Client for the Client, or the "
542              "Client for which this Client is a transient. Returns None if it "
543              "is not a transient."),
544     ATTRMETH(children,
545              "c.parent() -- Returns a list of child Clients for the Client, "
546              "or the Clients transients."),
547     ATTRMETH(desktop,
548              "c.desktop() -- Returns the desktop on which the Client resides, "
549              "or 0xffffffff for 'all desktops'."),
550     ATTRMETH(title,
551              "c.title() -- Returns the Client's title string. This is in "
552              "UTF-8 encoding."),
553     ATTRMETH(iconTitle,
554              "c.iconTitle() -- Returns the Client's icon title string. This "
555              "is in UTF-8 encoding."),
556     ATTRMETH(resName,
557              "c.resName() -- Returns the application's specified resource "
558              "name."),
559     ATTRMETH(resClass,
560              "c.resClass() -- Returns the application's specified resource "
561              "class."),
562     ATTRMETH(role,
563              "c.role() -- Returns the window's role, which should be unique "
564              "for every window of an application, if it is not empty."),
565     ATTRMETH(type,
566              "c.type() -- Returns the window's type, one of the ob.Type_ "
567              "constants. This is the logical type of the window."),
568     ATTRMETH(area,
569              "c.area() -- Returns the area rectangle for the Client in a "
570              "tuple. The tuple's format is (x, y, width, height). This is "
571              "not the area on-screen that the Client and frame occupies, but "
572              "rather, the position and size that the Client has requested, "
573              "before its gravity() and decorations have been applied. You "
574              "should use the c.screenArea() to get the actual on-screen area "
575              "for the Client."),
576     ATTRMETH(screenArea,
577              "c.screenArea() -- Returns the on-screen area rectangle for the "
578              "Client in a tuple. The tuple's format is (x, y, width, height). "
579              "This is the actual position and size of the Client plus its "
580              "decorations."),
581     ATTRMETH(strut,
582              "c.strut() -- Returns the strut requested by the Client in a "
583              "tuple. The format of the tuple is (left, top, right, bottom)."),
584     ATTRMETH(logicalSize,
585              "c.logicalSize() -- Returns the logical size of the Client. This "
586              "is the 'user friendly' size for the Client, such as for an "
587              "xterm, it will be the number of characters in the xterm "
588              "instead of the number of pixels it takes up."),
589     ATTRMETH(minRatio,
590              "c.minRatio() -- Returns the minimum width:height ratio for "
591              "the Client. A value of 0 implies no ratio enforcement."),
592     ATTRMETH(maxRatio,
593              "c.maxRatio() -- Returns the maximum width:height ratio for "
594              "the Client. A value of 0 implies no ratio enforcement."),
595     ATTRMETH(minSize,
596              "c.minSize() -- Returns the minimum size of the Client."),
597     ATTRMETH(maxSize,
598              "c.maxSize() -- Returns the maximum size of the Client."),
599     ATTRMETH(sizeIncrement,
600              "c.sizeIncrement() -- Returns the size increments in which the "
601              "Client must be resized."),
602     ATTRMETH(baseSize,
603              "c.baseSize() -- Returns the base size of the Client, which is "
604              "subtracted from the Client's size before comparing to its "
605              "various sizing constraints."),
606     ATTRMETH(gravity,
607              "c.gravity() -- Returns the gravity for the Client. One of the "
608              "ob.Gravity_ constants."),
609     ATTRMETH(canClose,
610              "c.canClose() -- Returns whether or not the Client provides a "
611              "means for Openbox to request that it close."),
612     ATTRMETH(positionRequested,
613              "c.positionRequested() -- Returns whether or not the Client has "
614              "requested a specified position on screen. When it has it should "
615              "probably not be placed using an algorithm when it is managed."),
616     ATTRMETH(canFocus,
617              "c.canFocus() -- Returns whether or not the Client can be "
618              "given input focus."),
619     ATTRMETH(urgent,
620              "c.urgent() -- Returns the urgent state of the window (on/off)."),
621     ATTRMETH(focused,
622              "c.focused() -- Returns whether or not the Client has the input "
623              "focus."),
624     ATTRMETH(modal,
625              "c.modal() -- Returns whether or not the Client is modal. A "
626              "modal Client implies that it needs to be closed before its "
627              "parent() can be used (focsed) again."),
628     ATTRMETH(shaded,
629              "c.shaded() -- Returns whether or not the Client is shaded. "
630              "Shaded clients are hidden except for their titlebar."),
631     ATTRMETH(iconic,
632              "c.iconic() -- Returns whether or not the Client is iconic. "
633              "Iconic windows are represented only by icons, or possibly "
634              "hidden entirely."),
635     ATTRMETH(maximizedVertical,
636              "c.maximizedVertical() -- Returns whether or not the Client is "
637              "maxized vertically. When a Client is maximized it will expand "
638              "to fill as much of the screen as it can in that direction."),
639     ATTRMETH(maximizedHorizontal,
640              "c.maximizedHorizontal() -- Returns whether or not the Client is "
641              "maxized horizontally. When a Client is maximized it will expand "
642              "to fill as much of the screen as it can in that direction."),
643     ATTRMETH(skipPager,
644              "c.skipPager() -- Returns whether the Client as requested to be "
645              "skipped by pagers."),
646     ATTRMETH(skipTaskbar,
647              "c.skipTaskbar() -- Returns whether the Client as requested to "
648              "be skipped by taskbars."),
649     ATTRMETH(fullscreen,
650              "c.fullscreen() -- Returns whether the Client is in fullscreen "
651              "mode."),
652     ATTRMETH(above,
653              "c.above() -- Returns whether the Client should be stacked above "
654              "other windows of the same type."),
655     ATTRMETH(below,
656              "c.below() -- Returns whether the Client should be stacked below "
657              "other windows of the same type."),
658     ATTRMETH(layer,
659              "c.layer() -- Returns the layer in which the window should be "
660              "stacked. This is one of the ob.Layer_ constants. Windows in "
661              "layers with higher values should be kept above windows in lower "
662              "valued layers."),
663     ATTRMETH(decorations,
664              "c.decorations() -- Returns a mask of decorations which the "
665              "Client will be given. It is made up of the ob.Decor_ constants. "
666              "These can be turned off with the "
667              " disabledDecorations()."),
668     ATTRMETH(disabledDecorations,
669              "c.disabledDecorations() -- returns a mask of decorations which "
670              "are disabled on the Client. This is made up of the ob.Decor_ "
671              "constants."),
672     ATTRMETH(functions,
673              "ob.functions() -- Returns the list of functionality for the "
674              "Client, in a mask made up of the ob.Func_ constants."),
675     ATTRMETH(visible,
676              "ob.visible() -- Returns if the client is currently visible "
677              "or hidden."),
678     ATTRMETH(decorationSize,
679              "c.decorationSize() -- Returns the size of the Client's "
680              "decorations around the Client window, in a tuple. The format of "
681              "the tuple is (left, top, right, bottom)."),
682     ATTRMETH(normal,
683              "c.normal() -- Returns if the window should be treated as a "
684              "normal window. Some windows (desktops, docks, splash screens) "
685              "should have special rules applied to them in a number of "
686              "places regarding focus or user interaction."),
687     ATTRMETH(setVisible,
688              "c.setVisible(show) -- Shows or hides the Client."),
689     ATTRMETH(raiseWindow,
690              "c.raiseWindow() -- Raises the Client to the top of its layer."),
691     ATTRMETH(lowerWindow,
692              "c.lowerWindow() -- Lowers the Client to the bottom of its "
693              "layer."),
694     ATTRMETH(focus,
695              "c.focus() -- Focuses the Client. Returns 1 if the Client will "
696              "be focused, or 0 if it will not."),
697     ATTRMETH(unfocus,
698              "c.unfocus() -- Unfocuses the Client, leaving nothing focused."),
699     ATTRMETH(move,
700              "c.move(x, y) -- Moves the Client to the specified position. The "
701              "top left corner of the Client's decorations is positioned at "
702              "the given x, y."),
703     { NULL, NULL, 0, NULL }
704 };
705
706 /***************************************************************************
707  
708    Type methods/struct
709  
710  ***************************************************************************/
711
712 /*static PyObject *cwrap_getattr(ClientWrap *self, char *name)
713 {
714     CHECK_CWRAP(self, "getattr");
715     return Py_FindMethod(ClientWrapAttributeMethods, (PyObject*)self, name);
716 }*/
717
718 static void cwrap_dealloc(ClientWrap *self)
719 {
720     if (self->client != NULL)
721         self->client->wrap = NULL;
722     PyObject_Del((PyObject*) self);
723 }
724
725 static PyObject *cwrap_repr(ClientWrap *self)
726 {
727      CHECK_CWRAP(self, "repr");
728      return PyString_FromFormat("0x%x", (guint)self->client->window);
729 }
730
731 static int cwrap_compare(ClientWrap *self, ClientWrap *other)
732 {
733     Window w1, w2;
734     if (!IS_VALID_CWRAP(self)) {
735         PyErr_SetString(PyExc_ValueError,
736                         "This 'Client' is wrapping a client which no longer "
737                         "exists.");
738     }
739
740     w1 = self->client->window;
741     w2 = self->client->window;
742     return w1 > w2 ? 1 : w1 < w2 ? -1 : 0;
743 }
744
745 static PyTypeObject ClientWrapType = {
746     PyObject_HEAD_INIT(NULL)
747     0,
748     "Client",
749     sizeof(ClientWrap),
750     0,
751     (destructor) cwrap_dealloc,     /*tp_dealloc*/
752     0,                              /*tp_print*/
753     0,                              /*tp_getattr*/
754     0,                              /*tp_setattr*/
755     (cmpfunc) cwrap_compare,        /*tp_compare*/
756     (reprfunc) cwrap_repr,          /*tp_repr*/
757     0,                              /*tp_as_number*/
758     0,                              /*tp_as_sequence*/
759     0,                              /*tp_as_mapping*/
760     0,                              /*tp_hash */
761 };
762
763 /***************************************************************************
764  
765    External methods
766  
767  ***************************************************************************/
768
769 void clientwrap_startup()
770 {
771     ClientWrapType.ob_type = &PyType_Type;
772     ClientWrapType.tp_methods = ClientWrapMethods;
773     PyType_Ready(&ClientWrapType);
774 }
775
776 void clientwrap_shutdown()
777 {
778 }
779
780 PyObject *clientwrap_new(Client *client)
781 {
782     g_assert(client != NULL);
783
784     if (client->wrap != NULL) {
785         /* already has a wrapper! */
786         Py_INCREF((PyObject*) client->wrap);
787     } else {
788         client->wrap = PyObject_New(ClientWrap, &ClientWrapType);
789         client->wrap->client = client;
790     }
791     return (PyObject*) client->wrap;
792 }