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