Corrected "Play queue"
[rhythmbox.git] / plugins / rb-python-module.c
bloba546924afe28d14b3c51002a7b75cf53c4c38b75
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * Copyright (C) 2005 Raphael Slinckx
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301 USA.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <pygobject.h>
26 #include <pygtk/pygtk.h>
28 #include <signal.h>
30 #include <gmodule.h>
32 #include "rb-plugin.h"
33 #include "rb-python-module.h"
34 #include "rb-python-plugin.h"
35 #include "rb-debug.h"
37 #define RB_PYTHON_MODULE_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
38 RB_TYPE_PYTHON_MODULE, \
39 RBPythonModulePrivate))
41 typedef struct
43 gchar *module;
44 gchar *path;
45 GType type;
46 } RBPythonModulePrivate;
48 enum
50 PROP_0,
51 PROP_PATH,
52 PROP_MODULE
55 /* Exported by pyrhythmdb module */
56 void pyrhythmdb_register_classes (PyObject *d);
57 void pyrhythmdb_add_constants (PyObject *module, const gchar *strip_prefix);
58 extern PyMethodDef pyrhythmdb_functions[];
60 /* Exported by pyrb module */
61 void pyrb_register_classes (PyObject *d);
62 void pyrb_add_constants (PyObject *module, const gchar *strip_prefix);
63 extern PyMethodDef pyrb_functions[];
65 /* We retreive this to check for correct class hierarchy */
66 static PyTypeObject *PyRBPlugin_Type;
68 G_DEFINE_TYPE (RBPythonModule, rb_python_module, G_TYPE_TYPE_MODULE);
70 static void
71 rb_python_module_init_python (void)
73 PyObject *pygtk, *mdict, *require;
74 PyObject *rb, *rhythmdb, *gtk, *pygtk_version, *pygtk_required_version;
75 PyObject *gettext, *install, *gettext_args;
76 PyObject *sys_path;
77 struct sigaction old_sigint;
78 gint res;
79 char *argv[] = { "rb", "rhythmdb", NULL };
80 GList *paths;
82 if (Py_IsInitialized ()) {
83 g_warning ("Python Should only be initialized once, since it's in class_init");
84 g_return_if_reached ();
87 /* Hack to make python not overwrite SIGINT: this is needed to avoid
88 * the crash reported on gedit bug #326191 */
90 /* Save old handler */
91 res = sigaction (SIGINT, NULL, &old_sigint);
92 if (res != 0) {
93 g_warning ("Error initializing Python interpreter: cannot get "
94 "handler to SIGINT signal (%s)",
95 strerror (errno));
97 return;
100 /* Python initialization */
101 Py_Initialize ();
103 /* Restore old handler */
104 res = sigaction (SIGINT, &old_sigint, NULL);
105 if (res != 0) {
106 g_warning ("Error initializing Python interpreter: cannot restore "
107 "handler to SIGINT signal (%s)",
108 strerror (errno));
109 return;
112 PySys_SetArgv (1, argv);
114 /* pygtk.require("2.8") */
115 pygtk = PyImport_ImportModule ("pygtk");
116 if (pygtk == NULL) {
117 g_warning ("Could not import pygtk");
118 PyErr_Print();
119 return;
122 mdict = PyModule_GetDict (pygtk);
123 require = PyDict_GetItemString (mdict, "require");
124 PyObject_CallObject (require, Py_BuildValue ("(S)", PyString_FromString ("2.8")));
126 /* import gobject */
127 init_pygobject ();
129 /* import gtk */
130 init_pygtk ();
132 gtk = PyImport_ImportModule ("gtk");
133 if (gtk == NULL) {
134 g_warning ("Could not import gtk");
135 PyErr_Print();
136 return;
139 mdict = PyModule_GetDict (gtk);
140 pygtk_version = PyDict_GetItemString (mdict, "pygtk_version");
141 pygtk_required_version = Py_BuildValue ("(iii)", 2, 4, 0);
142 if (PyObject_Compare (pygtk_version, pygtk_required_version) == -1) {
143 g_warning("PyGTK %s required, but %s found.",
144 PyString_AsString (PyObject_Repr (pygtk_required_version)),
145 PyString_AsString (PyObject_Repr (pygtk_version)));
146 Py_DECREF (pygtk_required_version);
147 return;
149 Py_DECREF (pygtk_required_version);
151 /* import rhythmdb */
152 rhythmdb = Py_InitModule ("rhythmdb", pyrhythmdb_functions);
153 mdict = PyModule_GetDict (rhythmdb);
155 pyrhythmdb_register_classes (mdict);
156 pyrhythmdb_add_constants (rhythmdb, "RHYTHMDB_");
158 /* import rb */
159 paths = rb_get_plugin_paths ();
160 sys_path = PySys_GetObject ("path");
161 while (paths != NULL) {
162 PyObject *path;
164 path = PyString_FromString (paths->data);
165 if (PySequence_Contains (sys_path, path) == 0) {
166 PyList_Insert (sys_path, 0, path);
168 Py_DECREF (path);
169 g_free (paths->data);
170 paths = g_list_delete_link (paths, paths);
173 rb = PyImport_ImportModule ("rb");
175 if (rb == NULL) {
176 g_warning ("could not import python module 'rb'");
177 PyErr_Print ();
178 return;
181 /* add pyrb_functions */
182 for (res = 0; pyrb_functions[res].ml_name != NULL; res++) {
183 PyObject *func;
185 func = PyCFunction_New (&pyrb_functions[res], rb);
186 if (func == NULL) {
187 g_warning ("unable object for function '%s' create", pyrb_functions[res].ml_name);
188 PyErr_Print ();
189 return;
191 if (PyModule_AddObject (rb, pyrb_functions[res].ml_name, func) < 0) {
192 g_warning ("unable to insert function '%s' in 'rb' module", pyrb_functions[res].ml_name);
193 PyErr_Print ();
194 return;
197 mdict = PyModule_GetDict (rb);
199 pyrb_register_classes (mdict);
200 pyrb_add_constants (rb, "RB_");
202 /* Retreive the Python type for rb.Plugin */
203 PyRBPlugin_Type = (PyTypeObject *) PyDict_GetItemString (mdict, "Plugin");
204 if (PyRBPlugin_Type == NULL) {
205 PyErr_Print ();
206 return;
209 /* i18n support */
210 gettext = PyImport_ImportModule ("gettext");
211 if (gettext == NULL) {
212 g_warning ("Could not import gettext");
213 PyErr_Print();
214 return;
217 mdict = PyModule_GetDict (gettext);
218 install = PyDict_GetItemString (mdict, "install");
219 gettext_args = Py_BuildValue ("ss", GETTEXT_PACKAGE, GNOMELOCALEDIR);
220 PyObject_CallObject (install, gettext_args);
221 Py_DECREF (gettext_args);
224 static gboolean
225 rb_python_module_load (GTypeModule *gmodule)
227 RBPythonModulePrivate *priv = RB_PYTHON_MODULE_GET_PRIVATE (gmodule);
228 PyObject *main_module, *main_locals, *locals, *key, *value;
229 PyObject *module, *fromlist;
230 int pos = 0;
232 main_module = PyImport_AddModule ("__main__");
233 if (main_module == NULL)
235 g_warning ("Could not get __main__.");
236 return FALSE;
239 /* If we have a special path, we register it */
240 if (priv->path != NULL)
242 PyObject *sys_path = PySys_GetObject ("path");
243 PyObject *path = PyString_FromString (priv->path);
245 if (PySequence_Contains(sys_path, path) == 0)
246 PyList_Insert (sys_path, 0, path);
248 Py_DECREF(path);
251 main_locals = PyModule_GetDict (main_module);
252 /* we need a fromlist to be able to import modules with a '.' in the
253 name. */
254 fromlist = PyTuple_New(0);
255 module = PyImport_ImportModuleEx (priv->module, main_locals,
256 main_locals, fromlist);
257 Py_DECREF (fromlist);
258 if (!module) {
259 PyErr_Print ();
260 return FALSE;
263 locals = PyModule_GetDict (module);
264 while (PyDict_Next (locals, &pos, &key, &value))
266 if (!PyType_Check(value))
267 continue;
269 if (PyObject_IsSubclass (value, (PyObject*) PyRBPlugin_Type))
271 priv->type = rb_python_object_get_type (gmodule, value);
272 return TRUE;
276 return FALSE;
279 static void
280 rb_python_module_unload (GTypeModule *module)
282 RBPythonModulePrivate *priv = RB_PYTHON_MODULE_GET_PRIVATE (module);
283 rb_debug ("Unloading python module");
285 priv->type = 0;
288 GObject *
289 rb_python_module_new_object (RBPythonModule *module)
291 RBPythonModulePrivate *priv = RB_PYTHON_MODULE_GET_PRIVATE (module);
292 RBPythonObject *object;
294 if (priv->type == 0)
295 return NULL;
297 rb_debug ("Creating object of type %s", g_type_name (priv->type));
298 object = (RBPythonObject*) (g_object_new (priv->type,
299 "name", priv->module,
300 NULL));
301 if (object->instance == NULL) {
302 g_warning ("could not instantiate python object");
303 return NULL;
306 /* FIXME, HACK: this is a hack because the gobject object->instance references
307 * isn't the same gobject as we think it is. Which Causes Issues.
309 * This still has issues, notably that it isn't safe to call any rb.Plugin methods
310 * from python before we get here.
312 * The solution is to not have weird proxy objects.
314 g_object_set (((PyGObject*)(object->instance))->obj, "name", priv->module, NULL);
316 return G_OBJECT (object);
319 static void
320 rb_python_module_init (RBPythonModule *module)
322 rb_debug ("Init of python module");
325 static void
326 rb_python_module_finalize (GObject *object)
328 RBPythonModulePrivate *priv = RB_PYTHON_MODULE_GET_PRIVATE (object);
329 rb_debug ("Finalizing python module %s", g_type_name (priv->type));
331 g_free (priv->module);
332 g_free (priv->path);
334 G_OBJECT_CLASS (rb_python_module_parent_class)->finalize (object);
337 static void
338 rb_python_module_get_property (GObject *object,
339 guint prop_id,
340 GValue *value,
341 GParamSpec *pspec)
343 /* no readable properties */
344 g_return_if_reached ();
347 static void
348 rb_python_module_set_property (GObject *object,
349 guint prop_id,
350 const GValue *value,
351 GParamSpec *pspec)
353 RBPythonModule *mod = RB_PYTHON_MODULE (object);
355 switch (prop_id)
357 case PROP_MODULE:
358 RB_PYTHON_MODULE_GET_PRIVATE (mod)->module = g_value_dup_string (value);
359 break;
360 case PROP_PATH:
361 RB_PYTHON_MODULE_GET_PRIVATE (mod)->path = g_value_dup_string (value);
362 break;
363 default:
364 g_return_if_reached ();
368 static void
369 rb_python_module_class_init (RBPythonModuleClass *class)
371 GObjectClass *object_class = G_OBJECT_CLASS (class);
372 GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
374 object_class->finalize = rb_python_module_finalize;
375 object_class->get_property = rb_python_module_get_property;
376 object_class->set_property = rb_python_module_set_property;
378 g_object_class_install_property
379 (object_class,
380 PROP_MODULE,
381 g_param_spec_string ("module",
382 "Module Name",
383 "The python module to load for this plugin",
384 NULL,
385 G_PARAM_WRITABLE | G_PARAM_READABLE | G_PARAM_CONSTRUCT_ONLY));
387 g_object_class_install_property
388 (object_class,
389 PROP_PATH,
390 g_param_spec_string ("path",
391 "Path",
392 "The python path to use when loading this module",
393 NULL,
394 G_PARAM_WRITABLE | G_PARAM_READABLE | G_PARAM_CONSTRUCT_ONLY));
396 g_type_class_add_private (object_class, sizeof (RBPythonModulePrivate));
398 module_class->load = rb_python_module_load;
399 module_class->unload = rb_python_module_unload;
401 /* Init python subsystem, this should happen only once
402 * in the process lifetime, and doing it here is ok since
403 * class_init is called once */
404 rb_python_module_init_python ();
407 RBPythonModule *
408 rb_python_module_new (const gchar *path,
409 const gchar *module)
411 RBPythonModule *result;
412 gchar *dir;
414 if (module == NULL || module[0] == '\0')
415 return NULL;
417 dir = g_path_get_dirname (path);
418 result = g_object_new (RB_TYPE_PYTHON_MODULE,
419 "module", module,
420 "path", dir,
421 NULL);
422 g_free (dir);
424 g_type_module_set_name (G_TYPE_MODULE (result), module);
426 return result;
429 /* --- these are not module methods, they are here out of convenience --- */
431 static gint idle_garbage_collect_id = 0;
433 static gboolean
434 run_gc (gpointer data)
436 while (PyGC_Collect ())
439 idle_garbage_collect_id = 0;
441 return FALSE;
444 void
445 rb_python_garbage_collect ()
447 if (Py_IsInitialized() && idle_garbage_collect_id == 0) {
448 idle_garbage_collect_id = g_idle_add (run_gc, NULL);
452 static gboolean
453 finalise_collect_cb (gpointer data)
455 while (PyGC_Collect ())
458 /* useful if python is refusing to give up it's shell reference for some reason.
459 PyRun_SimpleString ("import gc, gobject\nfor o in gc.get_objects():\n\tif isinstance(o, gobject.GObject):\n\t\tprint o, gc.get_referrers(o)");
462 return TRUE;
465 void
466 rb_python_shutdown ()
468 if (Py_IsInitialized ()) {
469 if (idle_garbage_collect_id != 0) {
470 g_source_remove (idle_garbage_collect_id);
471 idle_garbage_collect_id = 0;
474 run_gc (NULL);
475 /* this helps to force python to give up it's shell reference */
476 g_timeout_add (1000, finalise_collect_cb, NULL);
478 /* disable for now, due to bug 334188
479 Py_Finalize ();*/