Blame plugins/python/glade-python.c

Packit 1e8aac
/*
Packit 1e8aac
 * Copyright (C) 2006-2015 Juan Pablo Ugarte.
Packit 1e8aac
 *
Packit 1e8aac
 * This program is free software; you can redistribute it and/or modify
Packit 1e8aac
 * it under the terms of the GNU General Public License as
Packit 1e8aac
 * published by the Free Software Foundation; either version 2 of the
Packit 1e8aac
 * License, or (at your option) any later version.
Packit 1e8aac
 *
Packit 1e8aac
 * This program is distributed in the hope that it will be useful,
Packit 1e8aac
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1e8aac
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 1e8aac
 * GNU General Public License for more details.
Packit 1e8aac
 *
Packit 1e8aac
 * You should have received a copy of the GNU General Public License
Packit 1e8aac
 * along with this program; if not, write to the Free Software
Packit 1e8aac
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 1e8aac
 *
Packit 1e8aac
 * Authors:
Packit 1e8aac
 *   Juan Pablo Ugarte <juanpablougarte@gmail.com>
Packit 1e8aac
 */
Packit 1e8aac
Packit 1e8aac
#include <config.h>
Packit 1e8aac
Packit 1e8aac
#include <Python.h>
Packit 1e8aac
#include <pygobject.h>
Packit 1e8aac
Packit 1e8aac
#include <gladeui/glade.h>
Packit 1e8aac
Packit 1e8aac
#if PY_MAJOR_VERSION >= 3
Packit 1e8aac
Packit 1e8aac
#define WCHAR(str) L##str
Packit 1e8aac
Packit 1e8aac
#define PY_STRING(str) WCHAR(str)
Packit 1e8aac
#define STRING_FROM_PYSTR(pstr) PyUnicode_AsUTF8 (pstr)
Packit 1e8aac
Packit 1e8aac
#else
Packit 1e8aac
Packit 1e8aac
/* include bytesobject.h to map PyBytes_* to PyString_* */
Packit 1e8aac
#include <bytesobject.h>
Packit 1e8aac
Packit 1e8aac
#define PY_STRING(str) str
Packit 1e8aac
#define STRING_FROM_PYSTR(pstr) PyBytes_AsString (pstr)
Packit 1e8aac
Packit 1e8aac
#endif
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
python_init (void)
Packit 1e8aac
{
Packit 1e8aac
  if (Py_IsInitialized ())
Packit 1e8aac
    return;
Packit 1e8aac
Packit 1e8aac
  Py_InitializeEx (0);
Packit 1e8aac
Packit 1e8aac
  /* if argc is 0 an empty string is prepended to sys.path */
Packit 1e8aac
  PySys_SetArgvEx (0, NULL, 0);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_python_init_pygobject_check (gint req_major, gint req_minor, gint req_micro)
Packit 1e8aac
{
Packit 1e8aac
  PyObject *gi, *gobject;
Packit 1e8aac
Packit 1e8aac
  /* import gobject */
Packit 1e8aac
  pygobject_init (req_major, req_minor, req_micro);
Packit 1e8aac
  if (PyErr_Occurred ())
Packit 1e8aac
    {
Packit 1e8aac
      g_warning ("Error initializing Python interpreter: could not "
Packit 1e8aac
                 "import pygobject");
Packit 1e8aac
Packit 1e8aac
      return;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  gi = PyImport_ImportModule ("gi");
Packit 1e8aac
  if (gi == NULL)
Packit 1e8aac
    {
Packit 1e8aac
      g_warning ("Error initializing Python interpreter: could not "
Packit 1e8aac
                 "import gi");
Packit 1e8aac
Packit 1e8aac
      return;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  gobject = PyImport_ImportModule ("gi.repository.GObject");
Packit 1e8aac
  if (gobject == NULL)
Packit 1e8aac
    {
Packit 1e8aac
      g_warning ("Error initializing Python interpreter: could not "
Packit 1e8aac
                 "import gobject");
Packit 1e8aac
Packit 1e8aac
      return;
Packit 1e8aac
    }
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gboolean
Packit 1e8aac
glade_python_setup ()
Packit 1e8aac
{
Packit 1e8aac
  GString *command;
Packit 1e8aac
  const gchar *module_path;
Packit 1e8aac
  const GList *paths;
Packit 1e8aac
Packit 1e8aac
  Py_SetProgramName (PY_STRING (PACKAGE_NAME));
Packit 1e8aac
Packit 1e8aac
  /* Initialize the Python interpreter */
Packit 1e8aac
  python_init ();
Packit 1e8aac
Packit 1e8aac
  /* Check and init pygobject */
Packit 1e8aac
Packit 1e8aac
  PyErr_Clear ();
Packit 1e8aac
  glade_python_init_pygobject_check (PYGOBJECT_REQUIRED_MAJOR,
Packit 1e8aac
                                     PYGOBJECT_REQUIRED_MINOR,
Packit 1e8aac
                                     PYGOBJECT_REQUIRED_MICRO);
Packit 1e8aac
  if (PyErr_Occurred ())
Packit 1e8aac
    {
Packit 1e8aac
      PyObject *ptype, *pvalue, *ptraceback, *pstr;
Packit 1e8aac
      char *pvalue_char = "";
Packit 1e8aac
Packit 1e8aac
      PyErr_Fetch (&ptype, &pvalue, &ptraceback);
Packit 1e8aac
      PyErr_NormalizeException (&ptype, &pvalue, &ptraceback);
Packit 1e8aac
Packit 1e8aac
      if ((pstr = PyObject_Str (pvalue)))
Packit 1e8aac
        pvalue_char = STRING_FROM_PYSTR (pstr);
Packit 1e8aac
Packit 1e8aac
      g_warning ("Unable to load pygobject module >= %d.%d.%d, "
Packit 1e8aac
                 "please make sure it is in python's path (sys.path). "
Packit 1e8aac
                 "(use PYTHONPATH env variable to specify non default paths)\n%s",
Packit 1e8aac
                 PYGOBJECT_REQUIRED_MAJOR, PYGOBJECT_REQUIRED_MINOR,
Packit 1e8aac
                 PYGOBJECT_REQUIRED_MICRO, pvalue_char);
Packit 1e8aac
Packit 1e8aac
      Py_DecRef (ptype);
Packit 1e8aac
      Py_DecRef (pvalue);
Packit 1e8aac
      Py_DecRef (ptraceback);
Packit 1e8aac
      Py_DecRef (pstr);
Packit 1e8aac
      PyErr_Clear ();
Packit 1e8aac
      Py_Finalize ();
Packit 1e8aac
Packit 1e8aac
      return TRUE;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  pyg_disable_warning_redirections ();
Packit 1e8aac
Packit 1e8aac
  /* Generate system path array */
Packit 1e8aac
  command = g_string_new ("import sys; sys.path+=[");
Packit 1e8aac
Packit 1e8aac
  /* GLADE_ENV_MODULE_PATH has priority */
Packit 1e8aac
  module_path = g_getenv (GLADE_ENV_MODULE_PATH);
Packit 1e8aac
  if (module_path)
Packit 1e8aac
    g_string_append_printf (command, "'%s', ", module_path);
Packit 1e8aac
Packit 1e8aac
  /* Append modules directory */
Packit 1e8aac
  g_string_append_printf (command, "'%s'", glade_app_get_modules_dir ());
Packit 1e8aac
  
Packit 1e8aac
  /* Append extra paths (declared in the Preferences) */
Packit 1e8aac
  for (paths = glade_catalog_get_extra_paths (); paths; paths = g_list_next (paths))
Packit 1e8aac
    g_string_append_printf (command, ", '%s'", (gchar *) paths->data);
Packit 1e8aac
Packit 1e8aac
  /* Close python statement */
Packit 1e8aac
  g_string_append (command, "];\n");
Packit 1e8aac
Packit 1e8aac
  /* Make sure we load Gtk 3 */
Packit 1e8aac
  g_string_append (command, "import gi; gi.require_version('Gtk', '3.0');\n");
Packit 1e8aac
Packit 1e8aac
  /* Finally run statement in vm */
Packit 1e8aac
  PyRun_SimpleString (command->str);
Packit 1e8aac
Packit 1e8aac
  g_string_free (command, TRUE);
Packit 1e8aac
Packit 1e8aac
  return FALSE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_python_init (const gchar *name)
Packit 1e8aac
{
Packit 1e8aac
  static gsize init = 0;
Packit 1e8aac
  gchar *import_sentence;
Packit 1e8aac
Packit 1e8aac
  if (g_once_init_enter (&init))
Packit 1e8aac
    {
Packit 1e8aac
      if (glade_python_setup ())
Packit 1e8aac
        return;
Packit 1e8aac
Packit 1e8aac
      g_once_init_leave (&init, TRUE);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  /* Yeah, we use the catalog name as the library */
Packit 1e8aac
  import_sentence = g_strdup_printf ("import %s;", name);
Packit 1e8aac
Packit 1e8aac
  /* Importing the module will create all the GTypes so that glade can use them at runtime */
Packit 1e8aac
  PyRun_SimpleString (import_sentence);
Packit 1e8aac
  
Packit 1e8aac
  g_free (import_sentence);
Packit 1e8aac
}