| 1 | #include "Python.h" |
|---|
| 2 | #include <stdio.h> |
|---|
| 3 | #include <pthread.h> |
|---|
| 4 | #include <stdlib.h> |
|---|
| 5 | #include "evilwm.h" |
|---|
| 6 | |
|---|
| 7 | struct cargs |
|---|
| 8 | { |
|---|
| 9 | int (*mainf)(int argc, char**argv); |
|---|
| 10 | int argc; |
|---|
| 11 | char **argv; |
|---|
| 12 | }; |
|---|
| 13 | |
|---|
| 14 | void* main_runner(void* _args) |
|---|
| 15 | { |
|---|
| 16 | struct cargs *args = (struct cargs*)_args; |
|---|
| 17 | args->mainf(args->argc, args->argv); |
|---|
| 18 | free(args); |
|---|
| 19 | return NULL; |
|---|
| 20 | } |
|---|
| 21 | |
|---|
| 22 | PyObject* run(PyObject *_, PyObject *pyargs) |
|---|
| 23 | { |
|---|
| 24 | int sz; |
|---|
| 25 | int i; |
|---|
| 26 | pthread_t t; |
|---|
| 27 | |
|---|
| 28 | PyEval_InitThreads(); |
|---|
| 29 | |
|---|
| 30 | struct cargs *args = malloc(sizeof(struct cargs)); |
|---|
| 31 | args->mainf = wm_main; |
|---|
| 32 | |
|---|
| 33 | if(!PyTuple_Check(pyargs)) return PyExc_TypeError; |
|---|
| 34 | |
|---|
| 35 | sz = PyTuple_Size(pyargs); |
|---|
| 36 | for(i = 0; i < sz; ++i) |
|---|
| 37 | if(!PyString_Check(PyTuple_GetItem(pyargs, i))) |
|---|
| 38 | return PyExc_TypeError; |
|---|
| 39 | |
|---|
| 40 | args->argc = sz + 1; |
|---|
| 41 | args->argv = malloc(args->argc * sizeof(char *)); |
|---|
| 42 | |
|---|
| 43 | args->argv[0] = "m@rcell.wm"; |
|---|
| 44 | for(i = 1; i < args->argc; ++i) { |
|---|
| 45 | const char *str = PyString_AsString(PyTuple_GetItem(pyargs, i - 1)); |
|---|
| 46 | args->argv[i] = malloc(strlen(str + 1)); |
|---|
| 47 | strcpy(args->argv[i], str); |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | pthread_create(&t, NULL, main_runner, args); |
|---|
| 51 | Py_RETURN_NONE; |
|---|
| 52 | } |
|---|
| 53 | |
|---|
| 54 | ;;;; |
|---|
| 55 | |
|---|
| 56 | typedef struct { |
|---|
| 57 | PyObject_HEAD |
|---|
| 58 | Client *cli; |
|---|
| 59 | char *name; |
|---|
| 60 | } ClientObject; |
|---|
| 61 | |
|---|
| 62 | void Client_dtor(ClientObject *o) |
|---|
| 63 | { |
|---|
| 64 | // puts("tu i tamo stogod se i obrise"); |
|---|
| 65 | free(o->name); |
|---|
| 66 | o->ob_type->tp_free((PyObject*)o); |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | int client_is_valid(Client *c) |
|---|
| 70 | { |
|---|
| 71 | Client *it; |
|---|
| 72 | for (it = head_client; it; it = it->next) |
|---|
| 73 | if(it == c) return 1; |
|---|
| 74 | return 0; |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | PyObject *Client_hide(ClientObject *self) |
|---|
| 78 | { |
|---|
| 79 | if(!client_is_valid(self->cli)) Py_RETURN_NONE; |
|---|
| 80 | hide(self->cli); |
|---|
| 81 | Py_RETURN_NONE; |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | PyObject *Client_show(ClientObject *self) |
|---|
| 85 | { |
|---|
| 86 | if(!client_is_valid(self->cli)) Py_RETURN_NONE; |
|---|
| 87 | unhide(self->cli, RAISE); |
|---|
| 88 | Py_RETURN_NONE; |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | PyObject *Client_focus(ClientObject *self) |
|---|
| 92 | { |
|---|
| 93 | if(!client_is_valid(self->cli)) Py_RETURN_NONE; |
|---|
| 94 | select_client(self->cli); |
|---|
| 95 | Py_RETURN_NONE; |
|---|
| 96 | } |
|---|
| 97 | |
|---|
| 98 | PyObject *Client_kill(ClientObject *self) |
|---|
| 99 | { |
|---|
| 100 | if(!client_is_valid(self->cli)) Py_RETURN_NONE; |
|---|
| 101 | send_wm_delete(self->cli, 1); |
|---|
| 102 | Py_RETURN_NONE; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | |
|---|
| 106 | PyObject *Client_foo(ClientObject *self) |
|---|
| 107 | { |
|---|
| 108 | //if(!client_is_valid(self->cli)) Py_RETURN_NONE; |
|---|
| 109 | printf("get attro: %x\n", ((PyObject*)self)->ob_type->tp_getattro); |
|---|
| 110 | puts("bar"); |
|---|
| 111 | Py_RETURN_NONE; |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | PyObject *Client_grab_mask(ClientObject *self) |
|---|
| 115 | { |
|---|
| 116 | if(!client_is_valid(self->cli)) Py_RETURN_NONE; |
|---|
| 117 | grab_button(self->cli->parent, grabmask2, AnyButton); |
|---|
| 118 | Py_RETURN_NONE; |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | PyObject *Client_grab_all(ClientObject *self) |
|---|
| 122 | { |
|---|
| 123 | if(!client_is_valid(self->cli)) Py_RETURN_NONE; |
|---|
| 124 | grab_button(self->cli->parent, AnyModifier, AnyButton); |
|---|
| 125 | Py_RETURN_NONE; |
|---|
| 126 | } |
|---|
| 127 | |
|---|
| 128 | |
|---|
| 129 | static PyMethodDef Client_methods [] = { |
|---|
| 130 | {"hide", (PyCFunction)Client_hide, METH_NOARGS, "Hide the client"}, |
|---|
| 131 | {"show", (PyCFunction)Client_show, METH_NOARGS, "Show the client"}, |
|---|
| 132 | {"focus", (PyCFunction)Client_focus, METH_NOARGS, "Show the client"}, |
|---|
| 133 | {"kill", (PyCFunction)Client_kill, METH_NOARGS, "Kill the client"}, |
|---|
| 134 | {"set_grab_button_mask", (PyCFunction)Client_grab_mask, METH_NOARGS, "Kill the client"}, |
|---|
| 135 | {"unset_grab_button_mask", (PyCFunction)Client_grab_all, METH_NOARGS, "Kill the client"}, //todo: remove fun, just add different args |
|---|
| 136 | {"foo", (PyCFunction)Client_foo, METH_NOARGS, "foobar the client"}, |
|---|
| 137 | {NULL} |
|---|
| 138 | }; |
|---|
| 139 | |
|---|
| 140 | PyObject *Client_get_name(ClientObject *self, void *_) |
|---|
| 141 | {return PyString_FromString(self->name);} |
|---|
| 142 | |
|---|
| 143 | #define CLIENT_GET_INT(attr) \ |
|---|
| 144 | static PyObject *Client_get_ ## attr(ClientObject *self, void *_) \ |
|---|
| 145 | {return PyInt_FromLong(self -> cli -> attr);} |
|---|
| 146 | |
|---|
| 147 | #define CLIENT_SET_INT(attr) \ |
|---|
| 148 | static int Client_set_ ## attr(ClientObject *self, PyObject *val, void *_) \ |
|---|
| 149 | { \ |
|---|
| 150 | Client *c = self -> cli; \ |
|---|
| 151 | c -> attr = PyInt_AsLong(val); \ |
|---|
| 152 | XLockDisplay(dpy); \ |
|---|
| 153 | moveresize(c); \ |
|---|
| 154 | XUnlockDisplay(dpy); \ |
|---|
| 155 | return 0; \ |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | CLIENT_GET_INT(x) |
|---|
| 159 | CLIENT_GET_INT(y) |
|---|
| 160 | CLIENT_GET_INT(width) |
|---|
| 161 | CLIENT_GET_INT(height) |
|---|
| 162 | |
|---|
| 163 | CLIENT_SET_INT(x) |
|---|
| 164 | CLIENT_SET_INT(y) |
|---|
| 165 | CLIENT_SET_INT(width) |
|---|
| 166 | CLIENT_SET_INT(height) |
|---|
| 167 | |
|---|
| 168 | static PyGetSetDef Client_getset[] = { |
|---|
| 169 | {"x", (getter)Client_get_x, (setter)Client_set_x, "x coord", NULL}, |
|---|
| 170 | {"y", (getter)Client_get_y, (setter)Client_set_y, "y coord", NULL}, |
|---|
| 171 | {"width", (getter)Client_get_width, (setter)Client_set_width, "width", NULL}, |
|---|
| 172 | {"height", (getter)Client_get_height, (setter)Client_set_height, "height", NULL}, |
|---|
| 173 | {"name", (getter)Client_get_name, NULL, "name", NULL}, |
|---|
| 174 | {NULL} |
|---|
| 175 | }; |
|---|
| 176 | |
|---|
| 177 | PyObject *Client_getattro(PyObject *self, PyObject *attr) |
|---|
| 178 | { |
|---|
| 179 | PyObject* attrval = PyObject_GenericGetAttr(self, attr); |
|---|
| 180 | if(!PyErr_ExceptionMatches(PyExc_AttributeError)) return attrval; |
|---|
| 181 | PyErr_Clear(); |
|---|
| 182 | attrval = PyDict_GetItem(((ClientObject*)self)->cli->dict, attr); |
|---|
| 183 | if(!attrval) PyErr_SetString(PyExc_AttributeError, "err!"); |
|---|
| 184 | return attrval; |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | int Client_setattro(PyObject *self, PyObject *attr, PyObject *val) |
|---|
| 188 | { |
|---|
| 189 | int ret = PyObject_GenericSetAttr(self, attr, val); |
|---|
| 190 | if(!PyErr_ExceptionMatches(PyExc_AttributeError)) return ret; |
|---|
| 191 | PyErr_Clear(); |
|---|
| 192 | return PyDict_SetItem(((ClientObject*)self)->cli->dict, attr, val); |
|---|
| 193 | } |
|---|
| 194 | |
|---|
| 195 | static PyTypeObject mwm_ClientType = { |
|---|
| 196 | PyObject_HEAD_INIT(NULL) |
|---|
| 197 | 0, /*ob_size*/ |
|---|
| 198 | "mwm.Client", /*tp_name*/ |
|---|
| 199 | sizeof(ClientObject), /*tp_basicsize*/ |
|---|
| 200 | 0, /*tp_itemsize*/ |
|---|
| 201 | (destructor)Client_dtor, /*tp_dealloc*/ |
|---|
| 202 | 0, /*tp_print*/ |
|---|
| 203 | 0, /*tp_getattr*/ |
|---|
| 204 | 0, /*tp_setattr*/ |
|---|
| 205 | 0, /*tp_compare*/ |
|---|
| 206 | 0, /*tp_repr*/ |
|---|
| 207 | 0, /*tp_as_number*/ |
|---|
| 208 | 0, /*tp_as_sequence*/ |
|---|
| 209 | 0, /*tp_as_mapping*/ |
|---|
| 210 | 0, /*tp_hash */ |
|---|
| 211 | 0, /*tp_call*/ |
|---|
| 212 | 0, /*tp_str*/ |
|---|
| 213 | Client_getattro, /*tp_getattro*/ |
|---|
| 214 | Client_setattro, /*tp_setattro*/ |
|---|
| 215 | 0, /*tp_as_buffer*/ |
|---|
| 216 | Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
|---|
| 217 | "WM client", /* tp_doc */ |
|---|
| 218 | 0, /* tp_traverse */ |
|---|
| 219 | 0, /* tp_clear */ |
|---|
| 220 | 0, /* tp_richcompare */ |
|---|
| 221 | 0, /* tp_weaklistoffset */ |
|---|
| 222 | 0, /* tp_iter */ |
|---|
| 223 | 0, /* tp_iternext */ |
|---|
| 224 | Client_methods, /* tp_methods */ |
|---|
| 225 | 0, /* tp_members */ |
|---|
| 226 | Client_getset, /* tp_getset */ |
|---|
| 227 | 0, /* tp_base */ |
|---|
| 228 | 0, /* tp_dict */ |
|---|
| 229 | 0, /* tp_descr_get */ |
|---|
| 230 | 0, /* tp_descr_set */ |
|---|
| 231 | 0, /* tp_dictoffset */ |
|---|
| 232 | 0, /* tp_init */ |
|---|
| 233 | 0, /* tp_alloc */ |
|---|
| 234 | 0, /* tp_new */ |
|---|
| 235 | }; |
|---|
| 236 | |
|---|
| 237 | |
|---|
| 238 | void set_name(ClientObject *o, const char *name) |
|---|
| 239 | { |
|---|
| 240 | int len = strlen(name); |
|---|
| 241 | o->name = malloc(len + 1); |
|---|
| 242 | strcpy(o->name, name); |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | PyObject* Client_ctor(Client*c) |
|---|
| 246 | { |
|---|
| 247 | ClientObject *o = (ClientObject*)mwm_ClientType.tp_alloc(&mwm_ClientType, 0); |
|---|
| 248 | PyObject *pyo = (PyObject*)(o); |
|---|
| 249 | o->cli = c; |
|---|
| 250 | |
|---|
| 251 | XTextProperty tp; |
|---|
| 252 | if (!XGetWMName(dpy, c->window, &tp)) { |
|---|
| 253 | set_name(o, "(no name)"); |
|---|
| 254 | } else if (tp.nitems > 0) { |
|---|
| 255 | int count = 0, i, ret; |
|---|
| 256 | char **list = NULL; |
|---|
| 257 | ret = XmbTextPropertyToTextList(dpy, &tp, &list, &count); |
|---|
| 258 | if((ret == Success || ret > 0) && list != NULL) { |
|---|
| 259 | for(i=0; i<count; i++) |
|---|
| 260 | set_name(o, list[i]); |
|---|
| 261 | XFreeStringList(list); |
|---|
| 262 | } else { |
|---|
| 263 | set_name(o, tp.value); |
|---|
| 264 | } |
|---|
| 265 | } |
|---|
| 266 | |
|---|
| 267 | //Py_INCREF(pyo); -- todo: not sure |
|---|
| 268 | return pyo; |
|---|
| 269 | } |
|---|
| 270 | |
|---|
| 271 | PyObject* list(PyObject*_, PyObject*__) |
|---|
| 272 | { |
|---|
| 273 | Client *c; |
|---|
| 274 | PyObject *lst = PyList_New(0); |
|---|
| 275 | |
|---|
| 276 | for (c = head_client; c; c = c->next) |
|---|
| 277 | PyList_Append(lst, Client_ctor(c)); |
|---|
| 278 | |
|---|
| 279 | return lst; |
|---|
| 280 | } |
|---|
| 281 | |
|---|
| 282 | PyObject* get_focused(PyObject*_, PyObject*__) |
|---|
| 283 | { |
|---|
| 284 | if(!current) Py_RETURN_NONE; |
|---|
| 285 | Client_ctor(current); |
|---|
| 286 | } |
|---|
| 287 | ;;; |
|---|
| 288 | |
|---|
| 289 | #define HOOK_HANDLE(name) \ |
|---|
| 290 | PyObject * name ## _hook = NULL; \ |
|---|
| 291 | PyObject* set_ ## name ## _hook(PyObject *_, PyObject* pyargs) \ |
|---|
| 292 | { \ |
|---|
| 293 | if(!PyTuple_Check(pyargs)) return PyExc_TypeError; \ |
|---|
| 294 | if(PyTuple_Size(pyargs) != 1) return PyExc_TypeError; \ |
|---|
| 295 | PyObject* hook = PyTuple_GetItem(pyargs, 0); \ |
|---|
| 296 | PyObject *ret = name ## _hook; \ |
|---|
| 297 | if(!PyCallable_Check(hook)) return PyExc_TypeError; \ |
|---|
| 298 | \ |
|---|
| 299 | Py_INCREF(hook); \ |
|---|
| 300 | name ## _hook = hook; \ |
|---|
| 301 | \ |
|---|
| 302 | if(ret) return ret; \ |
|---|
| 303 | Py_RETURN_NONE; \ |
|---|
| 304 | } \ |
|---|
| 305 | PyObject* run_ ## name ## _hook(Client *c) \ |
|---|
| 306 | { \ |
|---|
| 307 | PyObject *ret; \ |
|---|
| 308 | if(!name ## _hook) return NULL; \ |
|---|
| 309 | PyGILState_STATE s = PyGILState_Ensure(); \ |
|---|
| 310 | PyObject *arg = PyTuple_New(1); \ |
|---|
| 311 | PyTuple_SetItem(arg, 0, Client_ctor(c)); \ |
|---|
| 312 | ret = PyObject_CallObject(name ## _hook, arg); \ |
|---|
| 313 | Py_DECREF(arg); \ |
|---|
| 314 | PyGILState_Release(s); \ |
|---|
| 315 | return ret; \ |
|---|
| 316 | } |
|---|
| 317 | |
|---|
| 318 | HOOK_HANDLE(geometry); |
|---|
| 319 | HOOK_HANDLE(drag_start); |
|---|
| 320 | HOOK_HANDLE(drag_end); |
|---|
| 321 | HOOK_HANDLE(sweep_start); |
|---|
| 322 | HOOK_HANDLE(sweep_end); |
|---|
| 323 | HOOK_HANDLE(mouse_enter); |
|---|
| 324 | HOOK_HANDLE(mouse_leave); |
|---|
| 325 | HOOK_HANDLE(mouse_button1); |
|---|
| 326 | HOOK_HANDLE(mouse_button2); |
|---|
| 327 | HOOK_HANDLE(mouse_button3); |
|---|
| 328 | |
|---|
| 329 | ;;; |
|---|
| 330 | |
|---|
| 331 | #define HOOK_EXPOSE(sname, hname) \ |
|---|
| 332 | {#sname, set_ ## hname ## _hook, METH_VARARGS} |
|---|
| 333 | |
|---|
| 334 | PyObject* set_key_hook(PyObject *_, PyObject* pyargs); //todo: remove |
|---|
| 335 | PyMODINIT_FUNC initmwm(void) |
|---|
| 336 | { |
|---|
| 337 | static PyMethodDef mtds[] = { |
|---|
| 338 | HOOK_EXPOSE(set_post_geometry_hook, geometry), |
|---|
| 339 | HOOK_EXPOSE(set_drag_start_hook, drag_start), |
|---|
| 340 | HOOK_EXPOSE(set_drag_end_hook, drag_end), |
|---|
| 341 | HOOK_EXPOSE(set_sweep_start_hook, sweep_start), |
|---|
| 342 | HOOK_EXPOSE(set_sweep_end_hook, sweep_end), |
|---|
| 343 | HOOK_EXPOSE(set_mouse_enter_hook, mouse_enter), |
|---|
| 344 | HOOK_EXPOSE(set_mouse_leave_hook, mouse_leave), |
|---|
| 345 | HOOK_EXPOSE(set_mouse_button1_hook, mouse_button1), |
|---|
| 346 | HOOK_EXPOSE(set_mouse_button2_hook, mouse_button2), |
|---|
| 347 | HOOK_EXPOSE(set_mouse_button3_hook, mouse_button3), |
|---|
| 348 | |
|---|
| 349 | HOOK_EXPOSE(set_key, key), //todo: remove |
|---|
| 350 | // {"set_post_geometry_hook", set_post_geometry_hook, METH_VARARGS}, |
|---|
| 351 | {"list", list, METH_VARARGS}, |
|---|
| 352 | {"run", run, METH_VARARGS}, |
|---|
| 353 | {"grab_keys", grab_keys, METH_VARARGS}, |
|---|
| 354 | {"focused", get_focused, METH_VARARGS}, |
|---|
| 355 | {NULL, NULL, 0, NULL}}; |
|---|
| 356 | |
|---|
| 357 | PyObject* m; |
|---|
| 358 | |
|---|
| 359 | mwm_ClientType.tp_new = PyType_GenericNew; |
|---|
| 360 | if (PyType_Ready(&mwm_ClientType) < 0) |
|---|
| 361 | return; |
|---|
| 362 | |
|---|
| 363 | m = Py_InitModule("mwm", mtds); |
|---|
| 364 | |
|---|
| 365 | Py_INCREF(&mwm_ClientType); |
|---|
| 366 | PyModule_AddObject(m, "Client", (PyObject*)&mwm_ClientType); |
|---|
| 367 | } |
|---|