python.c 10.2 KB
Newer Older
1

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/* gcompris - python.c
 *
 * Copyright (C) 2003 GCompris Developpement Team
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <Python.h>
#include <pygobject.h>
#include "gcompris/gcompris.h"
#include "py-gcompris-board.h"
25
#include "py-mod-gcompris.h"
26 27 28 29

static GcomprisBoard *gcomprisBoard = NULL;
static PyObject* python_gcomprisBoard = NULL;
static PyObject* python_board_module = NULL;
30
static PyObject* python_board_instance = NULL;
31

Olivier Samyn's avatar
Olivier Samyn committed
32
static void	 pythonboard_init ();
33 34 35 36 37 38 39 40 41 42 43 44
static void	 pythonboard_start (GcomprisBoard *agcomprisBoard);
static void	 pythonboard_pause (gboolean pause);
static void	 pythonboard_end (void);

static gboolean	 pythonboard_is_our_board (GcomprisBoard *agcomprisBoard);

static gint	 pythonboard_key_press (guint keyval);
static void	 pythonboard_ok (void);
static void	 pythonboard_set_level (guint level);
static void	 pythonboard_config(void);
static void	 pythonboard_repeat (void);

Olivier Samyn's avatar
Olivier Samyn committed
45 46
static gboolean  pythonboard_is_ready = FALSE;

47 48

/* Description of this plugin */
49
static BoardPlugin pythonboard_bp =
50 51 52 53
{
   NULL,
   NULL,
   N_("Python Board"),
54
   N_("Special board that embeds python into gcompris."),
55
   "Olivier Samyn <osamyn@ulb.ac.be>",
Olivier Samyn's avatar
Olivier Samyn committed
56
   pythonboard_init,
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
   NULL,
   NULL,
   NULL,
   pythonboard_start,
   pythonboard_pause,
   pythonboard_end,
   pythonboard_is_our_board,
   pythonboard_key_press,
   pythonboard_ok,
   pythonboard_set_level,
   pythonboard_config,
   pythonboard_repeat
};


/*
Olivier Samyn's avatar
Olivier Samyn committed
73
 * Return the plugin structure (Common to all gcompris boards)
74 75
 */

76
GET_BPLUGIN_INFO(python)
77 78


Olivier Samyn's avatar
Olivier Samyn committed
79 80 81 82
/*
 * Tests if a python interpreter is available
 * and that all required imports can be loaded.
 */
83
static void
Olivier Samyn's avatar
Olivier Samyn committed
84 85 86 87
pythonboard_init (){
  PyObject* main_module;
  PyObject* globals;
  gchar* execstr;
88
  gchar* userplugindir;
Olivier Samyn's avatar
Olivier Samyn committed
89 90 91 92 93 94 95 96 97 98

  /* Initialize the python interpreter */
  Py_Initialize();

  pythonboard_is_ready = TRUE;

  main_module = PyImport_AddModule("__main__"); /* Borrowed reference */
  globals = PyModule_GetDict(main_module); /* Borrowed reference */

  if(globals==NULL){
99
    g_warning("! Python disabled: Cannot get info from the python interpreter.\n");
Olivier Samyn's avatar
Olivier Samyn committed
100 101 102
    pythonboard_is_ready = FALSE;
  } else {
    /* Add the python plugins dir to the python's search path */
103
    execstr = g_strdup_printf("import sys; sys.path.append('%s')",PYTHON_PLUGIN_DIR);
104 105
#ifndef DISABLE_USER_PLUGIN_DIR
    userplugindir = g_strconcat(g_get_home_dir(), "/.gcompris/Plugins/", NULL);
106 107
    execstr = g_strdup_printf("import sys; sys.path.append('%s/python'); sys.path.append('%s')",
      userplugindir, PYTHON_PLUGIN_DIR);
108 109
    g_free(userplugindir);
#else
110
    execstr = g_strdup_printf("import sys; sys.path.append('%s')",PYTHON_PLUGIN_DIR );
111
#endif
Olivier Samyn's avatar
Olivier Samyn committed
112 113
    if(PyRun_SimpleString(execstr)!=0){
      pythonboard_is_ready = FALSE;
114
      g_warning("! Python disabled: Cannot add plugins dir into search path\n");
Olivier Samyn's avatar
Olivier Samyn committed
115 116 117
    } else {
      /* Load the gcompris modules */
      python_gcompris_module_init();
118

Olivier Samyn's avatar
Olivier Samyn committed
119 120
      /* Try to import pygtk modules */
      g_free(execstr);
121
      execstr = g_strdup("import gtk; import gtk.gdk");
Olivier Samyn's avatar
Olivier Samyn committed
122 123
      if(PyRun_SimpleString(execstr)!=0){
	pythonboard_is_ready = FALSE;
124
	g_warning("! Python disabled: Cannot import pygtk modules\n");
Olivier Samyn's avatar
Olivier Samyn committed
125 126 127
      } else {
	/* Try to import gnome-python modules */
	g_free(execstr);
128
	execstr = g_strdup("import gnome; import gnome.canvas");
Olivier Samyn's avatar
Olivier Samyn committed
129 130
	if(PyRun_SimpleString(execstr)!=0){
	  pythonboard_is_ready = FALSE;
131
	  g_warning("! Python disabled: Cannot import gnome-python modules\n");
Olivier Samyn's avatar
Olivier Samyn committed
132 133 134
	} else {
	  /* Try to import gcompris modules */
	  g_free(execstr);
135 136 137
	  execstr = g_strdup("import gcompris; import gcompris.bonus; "
			     "import gcompris.score; import gcompris.sound;"
			     "import gcompris.skin; import gcompris.timer;"
138
			     "import gcompris.utils; import gcompris.anim");
Olivier Samyn's avatar
Olivier Samyn committed
139 140
	  if(PyRun_SimpleString(execstr)!=0){
	    pythonboard_is_ready = FALSE;
141
	    g_warning("! Python disabled: Cannot import gcompris modules\n");
Olivier Samyn's avatar
Olivier Samyn committed
142 143 144 145
	  }
	}
      }
    }
146
    g_free(execstr);
Olivier Samyn's avatar
Olivier Samyn committed
147 148 149 150 151 152 153

  }

  /* Finalize the python interpreter */
  Py_Finalize();
}

154
/*
155 156
 * Start the board.
 * In this case:
157 158 159 160 161 162
 * - initialize python interpreter
 * - import gcompris functions/objects
 * - import gtk/gnome functions/objects
 * - load the python written board
 * - call the board start function
 */
163
static void
Olivier Samyn's avatar
Olivier Samyn committed
164
pythonboard_start (GcomprisBoard *agcomprisBoard){
165 166 167
  PyObject* main_module;
  PyObject* py_function_result;
  PyObject* module_dict;
168 169
  PyObject* py_boardclass;
  PyObject* py_boardclass_args;
170 171 172 173
  PyObject* globals;
  static char *python_args[]={ "" };
  static char* python_prog_name="gcompris";
  char* boarddir;
174
  char* boardclass;
175
  char* board_file_name;
176 177
  gchar *userplugindir;

178 179 180 181
  if(agcomprisBoard!=NULL){
    /* Initialize the python interpreter */
    Py_SetProgramName(python_prog_name);
    Py_Initialize();
182

183
    PySys_SetArgv(1, python_args);
184

185 186 187 188
    init_pygobject();

    main_module = PyImport_AddModule("__main__");
    globals = PyModule_GetDict(main_module);
189

190
    if(globals==NULL){
191
      g_print("Cannot get info from the python interpreter. Seems there is a problem with this one.\n");
192 193 194 195 196 197
      return;
    } else {
      gcomprisBoard = agcomprisBoard;
    }

    /* Add the python plugins dir to the python's search path */
198 199
#ifndef DISABLE_USER_PLUGIN_DIR
    userplugindir = g_strconcat(g_get_home_dir(), "/.gcompris/Plugins/", NULL);
200 201 202 203
    boarddir = g_strdup_printf("import sys; sys.path.append('%s/python'); sys.path.append('%s'); sys.path.append('%s')",
			       userplugindir,
			       PYTHON_PLUGIN_DIR,
			       gcomprisBoard->board_dir);
204
#else
205
    boarddir = g_strdup_printf("import sys; sys.path.append('%s')",PYTHON_PLUGIN_DIR );
206
#endif
207

208 209
    PyRun_SimpleString(boarddir);
    g_free(boarddir);
210

211 212 213
#ifndef DISABLE_USER_PLUGIN_DIR
    g_free(userplugindir);
#endif
214 215 216 217

    /* Load the gcompris modules */
    python_gcompris_module_init();

218
    /* Python is now initialized we create some usefull variables */
219 220
    board_file_name = strchr(agcomprisBoard->type, ':')+1;
    boardclass = g_strdup_printf("Gcompris_%s", board_file_name);
221

222
    /* Insert the board module into the python's interpreter */
223
    python_board_module = PyImport_ImportModuleEx(board_file_name,
224 225
 						  globals,
 						  globals,
226 227 228
 						  NULL);

    if(python_board_module!=NULL){
229
      /* Get the module dictionnary */
230
      module_dict = PyModule_GetDict(python_board_module);
231

232 233 234 235
      /* Get the python board class */
      py_boardclass = PyDict_GetItemString(module_dict, boardclass);

      /* Create a python gcompris board */
236 237
      python_gcomprisBoard=gcompris_new_pyGcomprisBoardObject(agcomprisBoard);

238 239 240 241 242 243
      /* Create an instance of the board class */
      py_boardclass_args = PyTuple_New(1);
      Py_INCREF(python_gcomprisBoard);
      PyTuple_SetItem(py_boardclass_args, 0, python_gcomprisBoard);
      python_board_instance = PyInstance_New(py_boardclass, py_boardclass_args, NULL);
      Py_DECREF(py_boardclass_args);
244 245

      /* Call the function */
246 247 248 249
      py_function_result = PyObject_CallMethod(python_board_instance, "start", NULL);
      if( py_function_result != NULL){
	Py_DECREF(py_function_result);
      } else {
250
	PyErr_Print();
251
      }
252 253
    } else {
      PyErr_Print();
254
    }
255 256

    g_free(boardclass);
257 258 259 260 261 262
  }
}

/*
 * Pause the board.
 */
263
static void pythonboard_pause (gboolean pause){
264 265
  PyObject* result = NULL;

266 267 268 269
  result = PyObject_CallMethod(python_board_instance, "pause", "i", pause);
  if( result != NULL){
    Py_DECREF(result);
  } else {
270
    PyErr_Print();
271
  }
272 273 274 275 276 277 278 279
}

/*
 * End the board.
 * In this case:
 * - call the board end function
 * - finalise python interpreter
 */
280
static void pythonboard_end (void){
281
  PyObject* result = NULL;
282

283
  if(python_gcomprisBoard!=NULL){
284 285
    result = PyObject_CallMethod(python_board_instance, "end", NULL);
    if( result == NULL){
286
      PyErr_Print();
287 288 289
    } else {
      Py_DECREF(result);
    }
290
    Py_XDECREF(python_board_module);
291
    Py_XDECREF(python_board_instance);
292 293 294 295 296 297 298 299
    Py_XDECREF(python_gcomprisBoard);
    Py_Finalize();
  }
}

/*
 * Return TRUE if the board is a python one.
 */
300 301
static gboolean pythonboard_is_our_board (GcomprisBoard *agcomprisBoard){

302 303
  if(pythonboard_is_ready) {
    if (agcomprisBoard!=NULL) {
304 305

      if (g_ascii_strncasecmp(agcomprisBoard->type, "python", 6)==0) {
306 307 308 309 310 311
	/* Set the plugin entry */
	agcomprisBoard->plugin=&pythonboard_bp;
	
	//g_print("pythonboard: is our board = TRUE\n");
	
	return TRUE;
Olivier Samyn's avatar
Olivier Samyn committed
312
      }
313
    }
Olivier Samyn's avatar
Olivier Samyn committed
314
  }
315
  return FALSE;
316 317 318 319 320
}

/*
 * Key press
 */
321
static gint pythonboard_key_press (guint keyval){
322 323
  PyObject* result = NULL;

324
  result = PyObject_CallMethod(python_board_instance, "key_press", "i", keyval);
325 326 327

  if (result==NULL) return FALSE;

328
  if (PyInt_Check(result) && (PyInt_AsLong(result)>0)){
329 330 331 332 333 334 335 336 337 338 339
    Py_DECREF(result);
    return TRUE;
  } else {
    Py_DECREF(result);
    return FALSE;
  }
}

/*
 * OK button pressed
 */
340
static void pythonboard_ok (void){
341
  PyObject* result = NULL;
342 343 344 345
  result = PyObject_CallMethod(python_board_instance, "ok", NULL);
  if( result != NULL){
    Py_DECREF(result);
  } else {
346
    PyErr_Print();
347
  }
348 349 350 351 352
}

/*
 * Set Level
 */
353
static void pythonboard_set_level (guint level){
354 355
  PyObject* result = NULL;

356 357 358 359
  result = PyObject_CallMethod(python_board_instance, "set_level", "i", level);
  if( result != NULL){
    Py_DECREF(result);
  } else {
360
    PyErr_Print();
361
  }
362 363 364 365 366
}

/*
 * Config
 */
367
static void pythonboard_config(void){
368
  PyObject* result = NULL;
369 370 371 372
  result = PyObject_CallMethod(python_board_instance, "config", NULL);
  if( result != NULL){
    Py_DECREF(result);
  } else {
373
    PyErr_Print();
374
  }
375 376 377 378 379
}

/*
 * Repeat
 */
380
static void pythonboard_repeat (void){
381
  PyObject* result = NULL;
382 383 384 385
  result = PyObject_CallMethod(python_board_instance, "repeat", NULL);
  if( result != NULL){
    Py_DECREF(result);
  } else {
386
    PyErr_Print();
387
  }
388
}