1 /* -*- Mode: C; c-set-style: python; c-basic-offset: 4 -*-
2 * pyglib - Python bindings for GLib toolkit.
3 * Copyright (C) 1998-2003 James Henstridge
4 * 2004-2008 Johan Dahlin
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <Python.h>
27 #include <pythread.h>
28 #include "pyglib.h"
29 #include "pyglib-private.h"
30 #include "pygmaincontext.h"
31 #include "pygoptioncontext.h"
32 #include "pygoptiongroup.h"
33
34 static struct _PyGLib_Functions *_PyGLib_API;
35 static int pyglib_thread_state_tls_key;
36 static PyObject *exception_table = NULL;
37
38 void
pyglib_init(void)39 pyglib_init(void)
40 {
41 PyObject *glib, *cobject;
42
43 glib = PyImport_ImportModule("glib");
44 if (!glib) {
45 if (PyErr_Occurred()) {
46 PyObject *type, *value, *traceback;
47 PyObject *py_orig_exc;
48 PyErr_Fetch(&type, &value, &traceback);
49 py_orig_exc = PyObject_Repr(value);
50 Py_XDECREF(type);
51 Py_XDECREF(value);
52 Py_XDECREF(traceback);
53 PyErr_Format(PyExc_ImportError,
54 "could not import glib (error was: %s)",
55 PYGLIB_PyUnicode_AsString(py_orig_exc));
56 Py_DECREF(py_orig_exc);
57 } else {
58 PyErr_SetString(PyExc_ImportError,
59 "could not import glib (no error given)");
60 }
61 return;
62 }
63
64 cobject = PyObject_GetAttrString(glib, "_PyGLib_API");
65 if (cobject && PYGLIB_CPointer_Check(cobject))
66 _PyGLib_API = (struct _PyGLib_Functions *) PYGLIB_CPointer_GetPointer(cobject, "glib._PyGLib_API");
67 else {
68 PyErr_SetString(PyExc_ImportError,
69 "could not import glib (could not find _PyGLib_API object)");
70 Py_DECREF(glib);
71 return;
72 }
73 }
74
75 void
pyglib_init_internal(PyObject * api)76 pyglib_init_internal(PyObject *api)
77 {
78 _PyGLib_API = (struct _PyGLib_Functions *) PYGLIB_CPointer_GetPointer(api, "glib._PyGLib_API");
79 }
80
81 gboolean
pyglib_threads_enabled(void)82 pyglib_threads_enabled(void)
83 {
84 g_return_val_if_fail (_PyGLib_API != NULL, FALSE);
85
86 return _PyGLib_API->threads_enabled;
87 }
88
89 PyGILState_STATE
pyglib_gil_state_ensure(void)90 pyglib_gil_state_ensure(void)
91 {
92 g_return_val_if_fail (_PyGLib_API != NULL, PyGILState_LOCKED);
93
94 if (!_PyGLib_API->threads_enabled)
95 return PyGILState_LOCKED;
96
97 #ifdef DISABLE_THREADING
98 return PyGILState_LOCKED;
99 #else
100 return PyGILState_Ensure();
101 #endif
102 }
103
104 void
pyglib_gil_state_release(PyGILState_STATE state)105 pyglib_gil_state_release(PyGILState_STATE state)
106 {
107 g_return_if_fail (_PyGLib_API != NULL);
108
109 if (!_PyGLib_API->threads_enabled)
110 return;
111
112 #ifndef DISABLE_THREADING
113 PyGILState_Release(state);
114 #endif
115 }
116
117 /**
118 * pyglib_enable_threads:
119 *
120 * Returns: TRUE if threading is enabled, FALSE otherwise.
121 *
122 */
123 #ifdef DISABLE_THREADING
124 gboolean
pyglib_enable_threads(void)125 pyglib_enable_threads(void)
126 {
127 PyErr_SetString(PyExc_RuntimeError,
128 "pyglib threading disabled at compile time");
129 return FALSE;
130 }
131
132 void
_pyglib_notify_on_enabling_threads(PyGLibThreadsEnabledFunc callback)133 _pyglib_notify_on_enabling_threads(PyGLibThreadsEnabledFunc callback)
134 {
135 /* Ignore, threads cannot be enabled. */
136 }
137
138 #else
139
140 static GSList *thread_enabling_callbacks = NULL;
141
142 /* Enable threading; note that the GIL must be held by the current
143 * thread when this function is called
144 */
145 gboolean
pyglib_enable_threads(void)146 pyglib_enable_threads(void)
147 {
148 GSList *callback;
149
150 g_return_val_if_fail (_PyGLib_API != NULL, FALSE);
151
152 if (_PyGLib_API->threads_enabled)
153 return TRUE;
154
155 PyEval_InitThreads();
156 if (!g_threads_got_initialized)
157 g_thread_init(NULL);
158
159 _PyGLib_API->threads_enabled = TRUE;
160 pyglib_thread_state_tls_key = PyThread_create_key();
161
162 for (callback = thread_enabling_callbacks; callback; callback = callback->next)
163 ((PyGLibThreadsEnabledFunc) callback->data) ();
164
165 g_slist_free(thread_enabling_callbacks);
166 return TRUE;
167 }
168
169 void
_pyglib_notify_on_enabling_threads(PyGLibThreadsEnabledFunc callback)170 _pyglib_notify_on_enabling_threads(PyGLibThreadsEnabledFunc callback)
171 {
172 if (callback && !pyglib_threads_enabled())
173 thread_enabling_callbacks = g_slist_append(thread_enabling_callbacks, callback);
174 }
175 #endif
176
177 int
pyglib_gil_state_ensure_py23(void)178 pyglib_gil_state_ensure_py23 (void)
179 {
180 #ifdef DISABLE_THREADING
181 return 0;
182 #else
183 return PyGILState_Ensure();
184 #endif
185 }
186
187 void
pyglib_gil_state_release_py23(int flag)188 pyglib_gil_state_release_py23 (int flag)
189 {
190 #ifndef DISABLE_THREADING
191 PyGILState_Release(flag);
192 #endif
193 }
194
195 /**
196 * pyglib_block_threads:
197 *
198 */
199 void
pyglib_block_threads(void)200 pyglib_block_threads(void)
201 {
202 g_return_if_fail (_PyGLib_API != NULL);
203
204 if (_PyGLib_API->block_threads != NULL)
205 (* _PyGLib_API->block_threads)();
206 }
207
208 /**
209 * pyglib_unblock_threads:
210 *
211 */
212 void
pyglib_unblock_threads(void)213 pyglib_unblock_threads(void)
214 {
215 g_return_if_fail (_PyGLib_API != NULL);
216 if (_PyGLib_API->unblock_threads != NULL)
217 (* _PyGLib_API->unblock_threads)();
218 }
219
220 /**
221 * pyglib_set_thread_block_funcs:
222 *
223 * hooks to register handlers for getting GDK threads to cooperate
224 * with python threading
225 */
226 void
pyglib_set_thread_block_funcs(PyGLibThreadBlockFunc block_threads_func,PyGLibThreadBlockFunc unblock_threads_func)227 pyglib_set_thread_block_funcs (PyGLibThreadBlockFunc block_threads_func,
228 PyGLibThreadBlockFunc unblock_threads_func)
229 {
230 g_return_if_fail (_PyGLib_API != NULL);
231
232 _PyGLib_API->block_threads = block_threads_func;
233 _PyGLib_API->unblock_threads = unblock_threads_func;
234 }
235
236
237 /**
238 * pyglib_error_check:
239 * @error: a pointer to the GError.
240 *
241 * Checks to see if the GError has been set. If the error has been
242 * set, then the glib.GError Python exception will be raised, and
243 * the GError cleared.
244 *
245 * Returns: True if an error was set.
246 */
247 gboolean
pyglib_error_check(GError ** error)248 pyglib_error_check(GError **error)
249 {
250 PyGILState_STATE state;
251 PyObject *exc_type;
252 PyObject *exc_instance;
253 PyObject *d;
254
255 g_return_val_if_fail(error != NULL, FALSE);
256
257 if (*error == NULL)
258 return FALSE;
259
260 state = pyglib_gil_state_ensure();
261
262 exc_type = _PyGLib_API->gerror_exception;
263 if (exception_table != NULL)
264 {
265 PyObject *item;
266 item = PyDict_GetItem(exception_table, PYGLIB_PyLong_FromLong((*error)->domain));
267 if (item != NULL)
268 exc_type = item;
269 }
270
271 exc_instance = PyObject_CallFunction(exc_type, "z", (*error)->message);
272
273 if ((*error)->domain) {
274 PyObject_SetAttrString(exc_instance, "domain",
275 d=PYGLIB_PyUnicode_FromString(g_quark_to_string((*error)->domain)));
276 Py_DECREF(d);
277 }
278 else
279 PyObject_SetAttrString(exc_instance, "domain", Py_None);
280
281 PyObject_SetAttrString(exc_instance, "code",
282 d=PYGLIB_PyLong_FromLong((*error)->code));
283 Py_DECREF(d);
284
285 if ((*error)->message) {
286 PyObject_SetAttrString(exc_instance, "message",
287 d=PYGLIB_PyUnicode_FromString((*error)->message));
288 Py_DECREF(d);
289 } else {
290 PyObject_SetAttrString(exc_instance, "message", Py_None);
291 }
292
293 PyErr_SetObject(_PyGLib_API->gerror_exception, exc_instance);
294 Py_DECREF(exc_instance);
295 g_clear_error(error);
296
297 pyglib_gil_state_release(state);
298
299 return TRUE;
300 }
301
302 /**
303 * pyglib_gerror_exception_check:
304 * @error: a standard GLib GError ** output parameter
305 *
306 * Checks to see if a GError exception has been raised, and if so
307 * translates the python exception to a standard GLib GError. If the
308 * raised exception is not a GError then PyErr_Print() is called.
309 *
310 * Returns: 0 if no exception has been raised, -1 if it is a
311 * valid glib.GError, -2 otherwise.
312 */
313 gboolean
pyglib_gerror_exception_check(GError ** error)314 pyglib_gerror_exception_check(GError **error)
315 {
316 PyObject *type, *value, *traceback;
317 PyObject *py_message, *py_domain, *py_code;
318 const char *bad_gerror_message;
319
320 PyErr_Fetch(&type, &value, &traceback);
321 if (type == NULL)
322 return 0;
323 PyErr_NormalizeException(&type, &value, &traceback);
324 if (value == NULL) {
325 PyErr_Restore(type, value, traceback);
326 PyErr_Print();
327 return -2;
328 }
329 if (!value ||
330 !PyErr_GivenExceptionMatches(type,
331 (PyObject *) _PyGLib_API->gerror_exception)) {
332 PyErr_Restore(type, value, traceback);
333 PyErr_Print();
334 return -2;
335 }
336 Py_DECREF(type);
337 Py_XDECREF(traceback);
338
339 py_message = PyObject_GetAttrString(value, "message");
340 if (!py_message || !PYGLIB_PyUnicode_Check(py_message)) {
341 bad_gerror_message = "glib.GError instances must have a 'message' string attribute";
342 goto bad_gerror;
343 }
344
345 py_domain = PyObject_GetAttrString(value, "domain");
346 if (!py_domain || !PYGLIB_PyUnicode_Check(py_domain)) {
347 bad_gerror_message = "glib.GError instances must have a 'domain' string attribute";
348 Py_DECREF(py_message);
349 goto bad_gerror;
350 }
351
352 py_code = PyObject_GetAttrString(value, "code");
353 if (!py_code || !PYGLIB_PyLong_Check(py_code)) {
354 bad_gerror_message = "glib.GError instances must have a 'code' int attribute";
355 Py_DECREF(py_message);
356 Py_DECREF(py_domain);
357 goto bad_gerror;
358 }
359
360 g_set_error(error, g_quark_from_string(PYGLIB_PyUnicode_AsString(py_domain)),
361 PYGLIB_PyLong_AsLong(py_code), "%s", PYGLIB_PyUnicode_AsString(py_message));
362
363 Py_DECREF(py_message);
364 Py_DECREF(py_code);
365 Py_DECREF(py_domain);
366 return -1;
367
368 bad_gerror:
369 Py_DECREF(value);
370 g_set_error(error, g_quark_from_static_string("pyglib"), 0, "%s", bad_gerror_message);
371 PyErr_SetString(PyExc_ValueError, bad_gerror_message);
372 PyErr_Print();
373 return -2;
374 }
375
376 /**
377 * pyglib_register_exception_for_domain:
378 * @name: name of the exception
379 * @error_domain: error domain
380 *
381 * Registers a new glib.GError exception subclass called #name for
382 * a specific #domain. This exception will be raised when a GError
383 * of the same domain is passed in to pyglib_error_check().
384 *
385 * Returns: the new exception
386 */
387 PyObject *
pyglib_register_exception_for_domain(gchar * name,gint error_domain)388 pyglib_register_exception_for_domain(gchar *name,
389 gint error_domain)
390 {
391 PyObject *exception;
392
393 exception = PyErr_NewException(name, _PyGLib_API->gerror_exception, NULL);
394
395 if (exception_table == NULL)
396 exception_table = PyDict_New();
397
398 PyDict_SetItem(exception_table,
399 PYGLIB_PyLong_FromLong(error_domain),
400 exception);
401
402 return exception;
403 }
404
405 /**
406 * pyglib_main_context_new:
407 * @context: a GMainContext.
408 *
409 * Creates a wrapper for a GMainContext.
410 *
411 * Returns: the GMainContext wrapper.
412 */
413 PyObject *
pyglib_main_context_new(GMainContext * context)414 pyglib_main_context_new(GMainContext *context)
415 {
416 return _PyGLib_API->main_context_new(context);
417 }
418
419 /**
420 * pyg_option_group_transfer_group:
421 * @group: a GOptionGroup wrapper
422 *
423 * This is used to transfer the GOptionGroup to a GOptionContext. After this
424 * is called, the calle must handle the release of the GOptionGroup.
425 *
426 * When #NULL is returned, the GOptionGroup was already transfered.
427 *
428 * Returns: Either #NULL or the wrapped GOptionGroup.
429 */
430 GOptionGroup *
pyglib_option_group_transfer_group(PyObject * obj)431 pyglib_option_group_transfer_group(PyObject *obj)
432 {
433 PyGOptionGroup *self = (PyGOptionGroup*)obj;
434
435 if (self->is_in_context)
436 return NULL;
437
438 self->is_in_context = TRUE;
439
440 /* Here we increase the reference count of the PyGOptionGroup, because now
441 * the GOptionContext holds an reference to us (it is the userdata passed
442 * to g_option_group_new().
443 *
444 * The GOptionGroup is freed with the GOptionContext.
445 *
446 * We set it here because if we would do this in the init method we would
447 * hold two references and the PyGOptionGroup would never be freed.
448 */
449 Py_INCREF(self);
450
451 return self->group;
452 }
453
454 /**
455 * pyglib_option_group_new:
456 * @group: a GOptionGroup
457 *
458 * The returned GOptionGroup can't be used to set any hooks, translation domains
459 * or add entries. It's only intend is, to use for GOptionContext.add_group().
460 *
461 * Returns: the GOptionGroup wrapper.
462 */
463 PyObject *
pyglib_option_group_new(GOptionGroup * group)464 pyglib_option_group_new (GOptionGroup *group)
465 {
466 return _PyGLib_API->option_group_new(group);
467 }
468
469 /**
470 * pyglib_option_context_new:
471 * @context: a GOptionContext
472 *
473 * Returns: A new GOptionContext wrapper.
474 */
475 PyObject *
pyglib_option_context_new(GOptionContext * context)476 pyglib_option_context_new (GOptionContext *context)
477 {
478 return _PyGLib_API->option_context_new(context);
479 }
480
481 /**
482 * pyglib_option_context_new:
483 * @context: a GTimeVal struct
484 *
485 * Converts a GTimeVal struct to a python float
486 *
487 * Returns: a float representing the timeval
488 */
489 PyObject *
pyglib_float_from_timeval(GTimeVal timeval)490 pyglib_float_from_timeval(GTimeVal timeval)
491 {
492 double ret;
493 ret = (double)timeval.tv_sec + (double)timeval.tv_usec * 0.000001;
494 return PyFloat_FromDouble(ret);
495 }
496
497
498 /****** Private *****/
499
500 /**
501 * _pyglib_destroy_notify:
502 * @user_data: a PyObject pointer.
503 *
504 * A function that can be used as a GDestroyNotify callback that will
505 * call Py_DECREF on the data.
506 */
507 void
_pyglib_destroy_notify(gpointer user_data)508 _pyglib_destroy_notify(gpointer user_data)
509 {
510 PyObject *obj = (PyObject *)user_data;
511 PyGILState_STATE state;
512
513 g_return_if_fail (_PyGLib_API != NULL);
514
515 state = pyglib_gil_state_ensure();
516 Py_DECREF(obj);
517 pyglib_gil_state_release(state);
518 }
519
520 gboolean
_pyglib_handler_marshal(gpointer user_data)521 _pyglib_handler_marshal(gpointer user_data)
522 {
523 PyObject *tuple, *ret;
524 gboolean res;
525 PyGILState_STATE state;
526
527 g_return_val_if_fail(user_data != NULL, FALSE);
528
529 state = pyglib_gil_state_ensure();
530
531 tuple = (PyObject *)user_data;
532 ret = PyObject_CallObject(PyTuple_GetItem(tuple, 0),
533 PyTuple_GetItem(tuple, 1));
534 if (!ret) {
535 PyErr_Print();
536 res = FALSE;
537 } else {
538 res = PyObject_IsTrue(ret);
539 Py_DECREF(ret);
540 }
541
542 pyglib_gil_state_release(state);
543
544 return res;
545 }
546
547 PyObject*
_pyglib_generic_ptr_richcompare(void * a,void * b,int op)548 _pyglib_generic_ptr_richcompare(void* a, void *b, int op)
549 {
550 PyObject *res;
551
552 switch (op) {
553
554 case Py_EQ:
555 res = (a == b) ? Py_True : Py_False;
556 break;
557
558 case Py_NE:
559 res = (a != b) ? Py_True : Py_False;
560 break;
561
562 case Py_LT:
563 res = (a < b) ? Py_True : Py_False;
564 break;
565
566 case Py_LE:
567 res = (a <= b) ? Py_True : Py_False;
568 break;
569
570 case Py_GT:
571 res = (a > b) ? Py_True : Py_False;
572 break;
573
574 case Py_GE:
575 res = (a >= b) ? Py_True : Py_False;
576 break;
577
578 default:
579 res = Py_NotImplemented;
580 break;
581 }
582
583 Py_INCREF(res);
584 return res;
585 }
586
587 PyObject*
_pyglib_generic_long_richcompare(long a,long b,int op)588 _pyglib_generic_long_richcompare(long a, long b, int op)
589 {
590 PyObject *res;
591
592 switch (op) {
593
594 case Py_EQ:
595 res = (a == b) ? Py_True : Py_False;
596 Py_INCREF(res);
597 break;
598
599 case Py_NE:
600 res = (a != b) ? Py_True : Py_False;
601 Py_INCREF(res);
602 break;
603
604
605 case Py_LT:
606 res = (a < b) ? Py_True : Py_False;
607 Py_INCREF(res);
608 break;
609
610 case Py_LE:
611 res = (a <= b) ? Py_True : Py_False;
612 Py_INCREF(res);
613 break;
614
615 case Py_GT:
616 res = (a > b) ? Py_True : Py_False;
617 Py_INCREF(res);
618 break;
619
620 case Py_GE:
621 res = (a >= b) ? Py_True : Py_False;
622 Py_INCREF(res);
623 break;
624
625 default:
626 res = Py_NotImplemented;
627 Py_INCREF(res);
628 break;
629 }
630
631 return res;
632 }
633
634