/* * Copyright (c) 2004 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #include "streamtuner.h" #include "pst.h" #include "pst-helpers.h" /*** variable declarations ***************************************************/ static PyObject *main_dict; /*** function declarations ***************************************************/ static gboolean check_api_version (GError **err); static void pst_main_init_pygobject (gboolean *status); static void pst_main_load_all_scripts (void); static void pst_main_load_scripts (const char *dirname); static gboolean pst_main_load_script (const char *filename, GError **err); /*** implementation **********************************************************/ static gboolean check_api_version (GError **err) { if (st_check_api_version(5, 8)) return TRUE; else { g_set_error(err, 0, 0, _("API version mismatch")); return FALSE; } } G_MODULE_EXPORT gboolean plugin_get_info (STPlugin *plugin, GError **err) { GdkPixbuf *pixbuf; if (! check_api_version(err)) return FALSE; st_plugin_set_name(plugin, "python"); st_plugin_set_label(plugin, "Python"); pixbuf = st_pixbuf_new_from_file(UIDIR "/python.png"); if (pixbuf) { st_plugin_set_icon_from_pixbuf(plugin, pixbuf); g_object_unref(pixbuf); } return TRUE; } G_MODULE_EXPORT gboolean plugin_init (GError **err) { gboolean status = FALSE; PyObject *module; if (! check_api_version(err)) return FALSE; /* * Workaround http://bugzilla.gnome.org/show_bug.cgi?id=160349: * always use the PyGILState API. */ if (! g_setenv("PYGTK_USE_GIL_STATE_API", "yes", TRUE)) { g_set_error(err, 0, 0, _("unable to set the PYGTK_USE_GIL_STATE_API environment variable: %s"), g_strerror(errno)); return FALSE; } Py_Initialize(); PyEval_InitThreads(); module = PyImport_AddModule("__main__"); if (! module) { pst_set_error(err); goto end; } main_dict = PyModule_GetDict(module); pst_main_init_pygobject(&status); if (! status) { pst_set_error(err); goto end; } if (! pst_init()) { status = FALSE; pst_set_error(err); goto end; } pst_main_load_all_scripts(); end: PyEval_ReleaseLock(); return status; } static void pst_main_init_pygobject (gboolean *status) { g_return_if_fail(status != NULL); *status = FALSE; init_pygobject(); if (pyg_enable_threads() == 0) *status = TRUE; } static void pst_main_load_all_scripts (void) { char *private_scriptsdir; if (g_file_test(SCRIPTS_DIR, G_FILE_TEST_IS_DIR)) pst_main_load_scripts(SCRIPTS_DIR); private_scriptsdir = g_build_filename(st_settings_get_private_dir(), "python", "scripts", NULL); if (g_file_test(private_scriptsdir, G_FILE_TEST_IS_DIR)) pst_main_load_scripts(private_scriptsdir); g_free(private_scriptsdir); } static void pst_main_load_scripts (const char *dirname) { GError *err = NULL; GDir *dir; const char *filename; g_return_if_fail(dirname != NULL); if (! (dir = g_dir_open(dirname, 0, &err))) { char *secondary; char *normalized; secondary = g_strdup_printf(_("Unable to scan Python scripts directory: %s"), err->message); g_error_free(err); normalized = st_dialog_normalize(secondary); g_free(secondary); st_error_dialog(_("A script error has occurred."), "%s", normalized); g_free(normalized); return; } while ((filename = g_dir_read_name(dir))) { char *pathname; char *extension; pathname = g_build_filename(dirname, filename, NULL); if (g_file_test(pathname, G_FILE_TEST_IS_REGULAR) && (extension = strrchr(filename, '.')) && (! strcmp(++extension, "py"))) { if (! pst_main_load_script(pathname, &err)) { char *secondary; char *normalized; secondary = g_strdup_printf(_("Script %s could not be loaded: %s"), pathname, err->message); g_clear_error(&err); normalized = st_dialog_normalize(secondary); g_free(secondary); st_error_dialog(_("A script error has occurred."), "%s", normalized); g_free(normalized); } } g_free(pathname); } g_dir_close(dir); } static gboolean pst_main_load_script (const char *filename, GError **err) { FILE *file; PyObject *dict; PyObject *result; gboolean status; g_return_val_if_fail(filename != NULL, FALSE); if (! (file = fopen(filename, "r"))) { g_set_error(err, 0, 0, _("unable to open script: %s"), g_strerror(errno)); return FALSE; } /* * We want a per-script namespace, so we do not share the main dict, * we use a copy. */ dict = PyDict_Copy(main_dict); result = PyRun_File(file, filename, Py_file_input, dict, dict); Py_DECREF(dict); if (result) { Py_DECREF(result); status = TRUE; } else { pst_set_error(err); status = FALSE; } fclose(file); return status; }