--- /dev/null
+#include "openboxwrap.h"
+#include "openbox.h"
+#include "screen.h"
+#include "prop.h"
+
+/***************************************************************************
+
+ Define the type 'OpenboxWrap'
+
+ ***************************************************************************/
+
+#define IS_OWRAP(v) ((v)->ob_type == &OpenboxWrapType)
+#define CHECK_OWRAP(self, funcname) { \
+ if (!IS_OWRAP(self)) { \
+ PyErr_SetString(PyExc_TypeError, \
+ "descriptor '" funcname "' requires a 'Openbox' " \
+ "object"); \
+ return NULL; \
+ } \
+}
+
+
+staticforward PyTypeObject OpenboxWrapType;
+
+/***************************************************************************
+
+ Attribute methods
+
+ ***************************************************************************/
+
+static PyObject *owrap_shutdown(OpenboxWrap *self, PyObject *args)
+{
+ CHECK_OWRAP(self, "shutdown");
+ if (!PyArg_ParseTuple(args, ":shutdown"))
+ return NULL;
+ ob_shutdown = TRUE;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *owrap_restart(OpenboxWrap *self, PyObject *args)
+{
+ char *path = NULL;
+
+ CHECK_OWRAP(self, "restart");
+ if (!PyArg_ParseTuple(args, "|s:restart", &path))
+ return NULL;
+ ob_shutdown = ob_restart = TRUE;
+ ob_restart_path = path;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *owrap_state(OpenboxWrap *self, PyObject *args)
+{
+ CHECK_OWRAP(self, "state");
+ if (!PyArg_ParseTuple(args, ":state"))
+ return NULL;
+ return PyInt_FromLong(ob_state);
+}
+
+static PyObject *owrap_desktop(OpenboxWrap *self, PyObject *args)
+{
+ CHECK_OWRAP(self, "desktop");
+ if (!PyArg_ParseTuple(args, ":desktop"))
+ return NULL;
+ return PyInt_FromLong(screen_desktop);
+}
+
+static PyObject *owrap_setDesktop(OpenboxWrap *self, PyObject *args)
+{
+ int desktop;
+
+ CHECK_OWRAP(self, "setDesktop");
+ if (!PyArg_ParseTuple(args, "i:setDesktop", &desktop))
+ return NULL;
+ if (desktop < 0 || (unsigned)desktop >= screen_num_desktops) {
+ PyErr_SetString(PyExc_ValueError, "invalid desktop");
+ return NULL;
+ }
+ screen_set_desktop(desktop);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *owrap_setNextDesktop(OpenboxWrap *self, PyObject *args)
+{
+ gboolean wrap = TRUE;
+ guint d;
+
+ CHECK_OWRAP(self, "setNextDesktop");
+ if (!PyArg_ParseTuple(args, "|i:setNextDesktop", &wrap))
+ return NULL;
+ d = screen_desktop + 1;
+ if (d >= screen_num_desktops && wrap)
+ d = 0;
+ if (d < screen_num_desktops)
+ screen_set_desktop(d);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *owrap_setPreviousDesktop(OpenboxWrap *self, PyObject *args)
+{
+ gboolean wrap = TRUE;
+ guint d;
+
+ CHECK_OWRAP(self, "setPreviousDesktop");
+ if (!PyArg_ParseTuple(args, "|i:setPreviousDesktop", &wrap))
+ return NULL;
+ d = screen_desktop - 1;
+ if (d >= screen_num_desktops && wrap)
+ d = screen_num_desktops - 1;
+ if (d < screen_num_desktops)
+ screen_set_desktop(d);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *owrap_numDesktops(OpenboxWrap *self, PyObject *args)
+{
+ CHECK_OWRAP(self, "numDesktops");
+ if (!PyArg_ParseTuple(args, ":numDesktops"))
+ return NULL;
+ return PyInt_FromLong(screen_num_desktops);
+}
+
+static PyObject *owrap_setNumDesktops(OpenboxWrap *self, PyObject *args)
+{
+ int desktops;
+
+ CHECK_OWRAP(self, "setNumDesktops");
+ if (!PyArg_ParseTuple(args, "i:setNumDesktops", &desktops))
+ return NULL;
+ if (desktops <= 0) {
+ PyErr_SetString(PyExc_ValueError, "invalid number of desktops");
+ return NULL;
+ }
+ screen_set_num_desktops(desktops);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *owrap_desktopNames(OpenboxWrap *self, PyObject *args)
+{
+ PyObject *tuple;
+ int i, s;
+
+ CHECK_OWRAP(self, "desktopNames");
+ if (!PyArg_ParseTuple(args, ":desktopNames"))
+ return NULL;
+ s = screen_desktop_names->len;
+ tuple = PyTuple_New(s);
+ for (i = 0; i < s; ++i)
+ PyTuple_SET_ITEM(tuple, i, g_ptr_array_index(screen_desktop_names, i));
+ return tuple;
+}
+
+static PyObject *owrap_setDesktopNames(OpenboxWrap *self, PyObject *args)
+{
+ PyObject *seq;
+ int i, s;
+ GPtrArray *data;
+
+ CHECK_OWRAP(self, "setDesktopNames");
+ if (!PyArg_ParseTuple(args, "O:setDesktopNames", &seq))
+ return NULL;
+ if (!PySequence_Check(seq))
+ PyErr_SetString(PyExc_TypeError, "expected a sequence");
+ return NULL;
+
+ s = PySequence_Size(seq);
+ for (i = 0; i < s; ++i) {
+ PyObject *item;
+ gboolean check;
+ item = PySequence_GetItem(seq, i); /* new */
+ check = PyString_Check(item);
+ Py_DECREF(item);
+ if (!check) {
+ PyErr_SetString(PyExc_TypeError, "expected a sequence of strings");
+ return NULL;
+ }
+ }
+
+ data = g_ptr_array_sized_new(s);
+ for (i = 0; i < s; ++i) {
+ PyObject *item;
+ item = PySequence_GetItem(seq, i); /* new */
+ g_ptr_array_index(data, i) = PyString_AsString(item); /* borrowed */
+ Py_DECREF(item);
+ }
+
+ PROP_SETSA(ob_root, net_desktop_names, utf8, data);
+ g_ptr_array_free(data, TRUE);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *owrap_showingDesktop(OpenboxWrap *self, PyObject *args)
+{
+ CHECK_OWRAP(self, "showingDesktop");
+ if (!PyArg_ParseTuple(args, ":showingDesktop"))
+ return NULL;
+ return PyInt_FromLong(!!screen_showing_desktop);
+}
+
+static PyObject *owrap_setShowingDesktop(OpenboxWrap *self, PyObject *args)
+{
+ int show;
+
+ CHECK_OWRAP(self, "setShowingDesktop");
+ if (!PyArg_ParseTuple(args, "i:setShowingDesktop", &show))
+ return NULL;
+ screen_show_desktop(show);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *owrap_screenArea(OpenboxWrap *self, PyObject *args)
+{
+ int desktop;
+ Rect *area;
+ PyObject *tuple;
+
+ CHECK_OWRAP(self, "screenArea");
+ if (!PyArg_ParseTuple(args, "i:screenArea", &desktop))
+ return NULL;
+
+ area = screen_area(desktop);
+ if (area == NULL) {
+ PyErr_SetString(PyExc_ValueError, "invalid desktop");
+ return NULL;
+ }
+
+ tuple = PyTuple_New(4);
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(area->x));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(area->y));
+ PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(area->width));
+ PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(area->height));
+ return tuple;
+}
+
+static PyObject *owrap_screenStrut(OpenboxWrap *self, PyObject *args)
+{
+ int desktop;
+ Strut *strut;
+ PyObject *tuple;
+
+ CHECK_OWRAP(self, "screenStrut");
+ if (!PyArg_ParseTuple(args, "i:screenStrut", &desktop))
+ return NULL;
+
+ strut = screen_strut(desktop);
+ if (strut == NULL) {
+ PyErr_SetString(PyExc_ValueError, "invalid desktop");
+ return NULL;
+ }
+
+ tuple = PyTuple_New(4);
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(strut->left));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(strut->top));
+ PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(strut->right));
+ PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(strut->bottom));
+ return tuple;
+}
+
+static PyObject *owrap_physicalSize(OpenboxWrap *self, PyObject *args)
+{
+ PyObject *tuple;
+
+ CHECK_OWRAP(self, "physicalSize");
+ if (!PyArg_ParseTuple(args, ":physicalSize"))
+ return NULL;
+
+ tuple = PyTuple_New(2);
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(screen_physical_size.width));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(screen_physical_size.height));
+ return tuple;
+}
+
+static PyObject *owrap_screenNumber(OpenboxWrap *self, PyObject *args)
+{
+ CHECK_OWRAP(self, "screenNumber");
+ if (!PyArg_ParseTuple(args, ":screenNumber"))
+ return NULL;
+ return PyInt_FromLong(ob_screen);
+}
+
+static PyObject *owrap_rootWindow(OpenboxWrap *self, PyObject *args)
+{
+ CHECK_OWRAP(self, "rootWindow");
+ if (!PyArg_ParseTuple(args, ":rootWindow"))
+ return NULL;
+ return PyInt_FromLong(ob_root);
+}
+
+static PyObject *owrap_clientList(OpenboxWrap *self, PyObject *args)
+{
+ CHECK_OWRAP(self, "clientList");
+ if (!PyArg_ParseTuple(args, ":clientList"))
+ return NULL;
+ Py_INCREF(self->client_list);
+ return self->client_list;
+}
+
+#define METH(n, d) {#n, (PyCFunction)owrap_##n, METH_VARARGS, #d}
+
+static PyMethodDef OpenboxWrapMethods[] = {
+ METH(shutdown,
+ "Causes Openbox to shutdown and exit."),
+ METH(restart,
+ "Causes Openbox to shutdown and restart. If path is specified, "
+ "Openbox will shutdown and attempt to run the specified executable "
+ "instead of restarting itself. If that fails, however, it will "
+ "restart itself."),
+ METH(state,
+ "Returns Openbox's current state, this will be one of the State "
+ "constants."),
+ METH(desktop,
+ "Returns the number of the currently visible desktop. This will be "
+ "in the range of [0, numDesktops())."),
+ METH(setDesktop,
+ "Sets the specified desktop as the visible desktop."),
+ METH(setNextDesktop,
+ "Sets the visible desktop to the next desktop, optionally wrapping "
+ "around when reaching the last."),
+ METH(setPreviousDesktop,
+ "Sets the visible desktop to the previous desktop, optionally "
+ "wrapping around when reaching the first."),
+ METH(numDesktops,
+ "Returns the number of desktops available."),
+ METH(desktopNames,
+ "Returns a tuple of names, containing a name for each desktop. The "
+ "tuple may have a length greater than numDesktops() if more names "
+ "have been specified."),
+ METH(setDesktopNames,
+ "Sets the names for the desktops."),
+ METH(showingDesktop,
+ "Returns True or False, depicting if Openbox is in 'showing the "
+ "desktop' mode. In 'showing the desktop' mode, all normal clients "
+ "are hidden and the desktop is given focus if possible."),
+ METH(setShowingDesktop,
+ "Enters or leaves 'showing the desktop' mode. See showingDesktop() "
+ "for a description of this mode."),
+ METH(screenArea,
+ "Returns the on-screen available area. This is the area not reserved "
+ "by applications' struts. Windows should be placed within this area, "
+ "not within the physicalSize()."),
+ METH(screenStrut,
+ "Returns the combined strut which has been reserved by all "
+ "applications on the desktops."),
+ METH(physicalSize,
+ "Returns the physical size of the display device (in pixels)."),
+ METH(screenNumber,
+ "Returns the number of the screen on which Openbox is running."),
+ METH(rootWindow,
+ "Return the window id of the root window."),
+ METH(clientList,
+ "Returns a all clients currently being managed by Openbox. This list "
+ "is updated as clients are managed and closed/destroyed/released."),
+ { NULL, NULL, 0, NULL }
+};
+
+/***************************************************************************
+
+ Type methods/struct
+
+ ***************************************************************************/
+
+/*static PyObject *owrap_getattr(OpenboxWrap *self, char *name)
+{
+ CHECK_OWRAP(self, "getattr");
+ return Py_FindMethod(OpenboxWrapAttributeMethods, (PyObject*)self, name);
+}*/
+
+static void owrap_dealloc(OpenboxWrap *self)
+{
+ PyObject_Del((PyObject*) self);
+}
+
+static PyTypeObject OpenboxWrapType = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "Openbox",
+ sizeof(OpenboxWrap),
+ 0,
+ (destructor) owrap_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+/***************************************************************************
+
+ Define the type 'OpenboxState'
+
+ ***************************************************************************/
+
+#define IS_OSTATE(v) ((v)->ob_type == &OpenboxStateType)
+#define CHECK_OSTATE(self, funcname) { \
+ if (!IS_OSTATE(self)) { \
+ PyErr_SetString(PyExc_TypeError, \
+ "descriptor '" funcname "' requires a 'State' " \
+ "object"); \
+ return NULL; \
+ } \
+}
+
+staticforward PyTypeObject OpenboxStateType;
+
+typedef struct OpenboxState {
+ PyObject_HEAD
+} OpenboxState;
+
+static void ostate_dealloc(PyObject *self)
+{
+ PyObject_Del(self);
+}
+
+static PyObject *ostate_getattr(OpenboxState *self, char *name)
+{
+ struct S { char *name; int val; };
+ struct S s[] = {
+ { "Starting", State_Starting },
+ { "Running", State_Running },
+ { "Exiting", State_Exiting },
+ { NULL, 0 } };
+ int i;
+
+ CHECK_OSTATE(self, "__getattr__");
+
+ for (i = 0; s[i].name != NULL; ++i)
+ if (!strcmp(s[i].name, name))
+ return PyInt_FromLong(s[i].val);
+ PyErr_SetString(PyExc_AttributeError, "invalid attribute");
+ return NULL;
+}
+
+static PyTypeObject OpenboxStateType = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "State",
+ sizeof(OpenboxState),
+ 0,
+ (destructor) ostate_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ (getattrfunc) ostate_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+/***************************************************************************
+
+ External methods
+
+ ***************************************************************************/
+
+void openboxwrap_startup()
+{
+ PyObject *ob, *obdict, *state;
+
+ OpenboxWrapType.ob_type = &PyType_Type;
+ OpenboxWrapType.tp_methods = OpenboxWrapMethods;
+ PyType_Ready(&OpenboxWrapType);
+
+ /* get the ob module/dict */
+ ob = PyImport_ImportModule("ob"); /* new */
+ g_assert(ob != NULL);
+ obdict = PyModule_GetDict(ob); /* borrowed */
+ g_assert(obdict != NULL);
+
+ /* add an Openbox instance to the ob module */
+ openboxwrap_obj = PyObject_New(OpenboxWrap, &OpenboxWrapType);
+ openboxwrap_obj->client_list = PyList_New(0);
+
+ PyDict_SetItemString(obdict, "Openbox", (PyObject*) openboxwrap_obj);
+
+ /* add an instance of OpenboxState */
+ state = (PyObject*) PyObject_New(OpenboxState, &OpenboxStateType);
+ PyDict_SetItemString(obdict, "State", state);
+ Py_DECREF(state);
+
+ Py_DECREF(ob);
+}
+
+void openboxwrap_shutdown()
+{
+ Py_DECREF(openboxwrap_obj->client_list);
+ Py_DECREF(openboxwrap_obj);
+}