gcompris.c 51.8 KB
Newer Older
Bruno Coudoin's avatar
Bruno Coudoin committed
1 2
/* gcompris - gcompris.c
 *
3
 * Copyright (C) 2000, 2008 Bruno Coudoin
Bruno Coudoin's avatar
Bruno Coudoin committed
4
 *
5 6 7 8
 *   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 3 of the License, or
 *   (at your option) any later version.
Bruno Coudoin's avatar
Bruno Coudoin committed
9
 *
10 11 12 13
 *   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.
Bruno Coudoin's avatar
Bruno Coudoin committed
14
 *
15 16
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, see <http://www.gnu.org/licenses/>.
Bruno Coudoin's avatar
Bruno Coudoin committed
17 18
 */

19 20
#include <signal.h>

21 22 23 24
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
25
#include <string.h>
26

27 28
#ifdef WIN32
// WIN32
29
#elif MAC_INTEGRATION
30
// MACOSX
31
#else
32 33 34 35
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <gdk/gdkx.h>
36
#endif
37

38 39 40 41 42
// Include Mac OS X menu synchronization on native OSX build
#ifdef  MAC_INTEGRATION
#include "ige-mac-menu.h"
#endif

43 44
#include <glib/gstdio.h>

Bruno Coudoin's avatar
Bruno Coudoin committed
45
#include "gcompris.h"
46
#include "gc_core.h"
47
#include "gcompris_config.h"
48
#include "about.h"
49
#include "bar.h"
50
#include "status.h"
51
#include <locale.h>
Bruno Coudoin's avatar
Bruno Coudoin committed
52

53 54
#include "binreloc.h"

55 56 57
/* get the default database name */
#define DEFAULT_DATABASE "gcompris_sqlite.db"

58 59
static double zoom_factor = 1.0;

60 61 62 63
/* Multiple instance check */
#define GC_LOCK_FILE "gcompris.lock"
#define GC_LOCK_LIMIT 30 /* seconds */

64
static GtkWidget *window;
65 66
static GtkWidget *workspace;
static GtkWidget *alignment;
67
static GtkWidget *canvas;
Yves Combe's avatar
Yves Combe committed
68 69
gchar * exec_prefix = NULL;

Bruno Coudoin's avatar
Bruno Coudoin committed
70 71
//static gint pause_board_cb (GtkWidget *widget, gpointer data);
static void quit_cb (GtkWidget *widget, gpointer data);
72
static void map_cb  (GtkWidget *widget, gpointer data);
73 74
static gboolean _realize_callback (GtkWidget *widget, GdkEventExpose *event,
				   gpointer data);
Bruno Coudoin's avatar
Bruno Coudoin committed
75 76 77
static gint board_widget_key_press_callback (GtkWidget   *widget,
					    GdkEventKey *event,
					    gpointer     client_data);
78
void gc_terminate(int signum);
79
static void single_instance_release();
Bruno Coudoin's avatar
Bruno Coudoin committed
80

81
/*
Bruno Coudoin's avatar
Bruno Coudoin committed
82
 * For the Activation dialog
83
 */
84
#ifdef ACTIVATION_CODE
85
int gc_activation_check(const char *code);
86 87 88
static void activation_enter_callback(GtkWidget *widget,
				      GtkWidget *entry );
static void activation_done();
89
static int display_activation_dialog();
90
static GooCanvasItem *activation_item;
91
static GtkWidget *widget_activation_entry;
92
#else
93
#define display_activation_dialog() FALSE
94 95 96
#endif


97 98
static GcomprisProperties *properties = NULL;
static gboolean		   is_mapped = FALSE;
Bruno Coudoin's avatar
Bruno Coudoin committed
99
static gboolean		   fullscreen;
100
static gboolean		   mute;
101
static guint		   gc_cursor_current;
Bruno Coudoin's avatar
Bruno Coudoin committed
102 103 104 105

/****************************************************************************/
/* Some constants.  */

106
static GooCanvasItem *backgroundimg = NULL;
Bruno Coudoin's avatar
Bruno Coudoin committed
107
static GooCanvasItem *backgroundsvgimg = NULL;
108 109 110
static gchar           *gc_locale = NULL;
static gchar           *gc_user_default_locale = NULL;
static gboolean		gc_debug = FALSE;
Bruno Coudoin's avatar
Bruno Coudoin committed
111

112 113 114
/****************************************************************************/
/* Command line params */

115
/*** gcompris-popttable */
116 117 118 119 120 121 122 123
static gint popt_fullscreen	   = FALSE;
static gint popt_window		   = FALSE;
static gint popt_sound		   = FALSE;
static gint popt_mute		   = FALSE;
static gint popt_cursor		   = FALSE;
static gint popt_version	   = FALSE;
static gint popt_difficulty_filter = FALSE;
static gint popt_debug		   = FALSE;
124
static gint popt_nolockcheck	   = FALSE;
125
static gchar *popt_root_menu       = NULL;
126
static gchar *popt_package_data_dir = NULL;
127
static gchar *popt_package_skin_dir = NULL;
128 129
static gchar *popt_plugin_dir      = NULL;
static gchar *popt_python_plugin_dir = NULL;
130
static gchar *popt_locale_dir      = NULL;
131
static gchar *popt_menu_dir        = NULL;
132 133 134 135 136 137
static gint popt_administration	   = FALSE;
static gchar *popt_database        = NULL;
static gint popt_create_db   	   = FALSE;
static gint popt_reread_menu   	   = FALSE;
static gchar *popt_profile	   = NULL;
static gint *popt_profile_list	   = FALSE;
138 139
static gchar *popt_config_dir	   = NULL;
static gchar *popt_user_dir	   = NULL;
140 141 142
static gint  popt_experimental     = FALSE;
static gint  popt_no_quit	   = FALSE;
static gint  popt_no_config        = FALSE;
143 144 145
static gchar *popt_server          = NULL;
static gint  *popt_web_only        = NULL;
static gchar *popt_cache_dir       = NULL;
146
static gchar *popt_drag_mode       = NULL;
147 148
static gchar *sugarBundleId        = NULL;
static gchar *sugarActivityId      = NULL;
149 150 151 152
static gint popt_sugar_look        = FALSE;
static gint popt_no_zoom           = FALSE;
static gdouble popt_timing_base    = 1.0;
static gdouble popt_timing_mult    = 1.0;
153 154 155

static GOptionEntry options[] = {
  {"fullscreen", 'f', 0, G_OPTION_ARG_NONE, &popt_fullscreen,
Bruno Coudoin's avatar
Bruno Coudoin committed
156
   N_("run GCompris in fullscreen mode."), NULL},
157

158
  {"window", 'w', 0, G_OPTION_ARG_NONE, &popt_window,
Bruno Coudoin's avatar
Bruno Coudoin committed
159
   N_("run GCompris in window mode."), NULL},
160

161
  {"sound", 's', 0, G_OPTION_ARG_NONE, &popt_sound,
Bruno Coudoin's avatar
Bruno Coudoin committed
162
   N_("run GCompris with sound enabled."), NULL},
163

164
  {"mute", 'm', 0, G_OPTION_ARG_NONE, &popt_mute,
Bruno Coudoin's avatar
Bruno Coudoin committed
165
   N_("run GCompris without sound."), NULL},
166

167
  {"cursor", 'c', 0, G_OPTION_ARG_NONE, &popt_cursor,
Bruno Coudoin's avatar
Bruno Coudoin committed
168
   N_("run GCompris with the default gnome cursor."), NULL},
169

170
  {"difficulty", 'd', 0, G_OPTION_ARG_INT, &popt_difficulty_filter,
171
   N_("display only activities with this difficulty level."), NULL},
172

173
  {"debug", 'D', 0, G_OPTION_ARG_NONE, &popt_debug,
174
   N_("display debug informations on the console."), NULL},
175

176
  {"version", 'v', 0, G_OPTION_ARG_NONE, &popt_version,
177
   N_("Print the version of " PACKAGE), NULL},
178

179
  {"root-menu", 'l', 0, G_OPTION_ARG_STRING, &popt_root_menu,
Bruno Coudoin's avatar
Bruno Coudoin committed
180 181 182
   N_("Run GCompris with local menu"
      " (e.g -l /reading will let you play only activities in the reading directory, -l /strategy/connect4 only the connect4 activity)."
      " Use '-l list' to list all the availaible activities and their descriptions."), NULL},
183

184 185 186
  {"package_data_dir", 'A', 0, G_OPTION_ARG_STRING, &popt_package_data_dir,
   N_("GCompris will find the data dir in this directory"), NULL},

187 188 189
  {"package_skin_dir", 'S', 0, G_OPTION_ARG_STRING, &popt_package_skin_dir,
   N_("GCompris will find the skins in this directory"), NULL},

190 191 192 193 194
  {"plugin_dir", 'L', 0, G_OPTION_ARG_STRING, &popt_plugin_dir,
   N_("GCompris will find the activity plugins in this directory"), NULL},

  {"python_plugin_dir", 'P', 0, G_OPTION_ARG_STRING, &popt_python_plugin_dir,
   N_("GCompris will find the python activity in this directory"), NULL},
195

196 197 198
  {"locale_dir", '\0', 0, G_OPTION_ARG_STRING, &popt_locale_dir,
   N_("GCompris will find the locale file (.mo translation) in this directory"), NULL},

199 200 201
  {"menu_dir", 'M', 0, G_OPTION_ARG_STRING, &popt_menu_dir,
   N_("GCompris will find the activities menu in this directory"), NULL},

202
  {"administration", 'a', 0, G_OPTION_ARG_NONE, &popt_administration,
203
   N_("Run GCompris in administration and user-management mode"), NULL},
204

205
  {"database", 'b', 0, G_OPTION_ARG_STRING, &popt_database,
206
   N_("Use alternate database for profiles [$HOME/.config/gcompris/gcompris_sqlite.db]"), NULL},
207

208
  {"create-db",'\0', 0, G_OPTION_ARG_NONE, &popt_create_db,
209
   N_("Create the alternate database for profiles"), NULL},
210

211
  {"reread-menu",'\0', 0, G_OPTION_ARG_NONE, &popt_reread_menu,
212
   N_("Re-read XML Menus and store them in the database"), NULL},
213

214
  {"profile",'p', 0, G_OPTION_ARG_STRING, &popt_profile,
215
   N_("Set the profile to use. Use 'gcompris -a' to create profiles"), NULL},
216

217
  {"profile-list",'\0', 0, G_OPTION_ARG_NONE, &popt_profile_list,
218
   N_("List all available profiles. Use 'gcompris -a' to create profiles"), NULL},
219

220
  {"config-dir",'\0', 0, G_OPTION_ARG_STRING, &popt_config_dir,
221
   N_("Config directory location: [$HOME/.config/gcompris]. Alternate is to set $XDG_CONFIG_HOME."), NULL},
222

223
  {"user-dir",'\0', 0, G_OPTION_ARG_STRING, &popt_user_dir,
224
   N_("The location of user directories: [$HOME/My GCompris]"), NULL},
225

226
  {"experimental",'\0', 0, G_OPTION_ARG_NONE, &popt_experimental,
227
   N_("Run the experimental activities"), NULL},
228

229
  {"disable-quit",'\0', 0, G_OPTION_ARG_NONE, &popt_no_quit,
Bruno Coudoin's avatar
Bruno Coudoin committed
230
   N_("Disable the quit button"), NULL},
231

232
  {"disable-config",'\0', 0, G_OPTION_ARG_NONE, &popt_no_config,
Bruno Coudoin's avatar
Bruno Coudoin committed
233
   N_("Disable the config button"), NULL},
234

235 236 237 238 239 240 241 242 243 244
  {"server", '\0', 0, G_OPTION_ARG_STRING, &popt_server,
   N_("GCompris will get images, sounds and activity data from this server if not found locally."), NULL},

  {"web-only", '\0', 0, G_OPTION_ARG_NONE, &popt_web_only,
   N_("Only when --server is provided, disable check for local resource first."
      " Data are always taken from the web server."), NULL},

  {"cache-dir", '\0', 0, G_OPTION_ARG_STRING, &popt_cache_dir,
   N_("In server mode, specify the cache directory used to avoid useless downloads."), NULL},

245
  {"drag-mode", 'g', 0, G_OPTION_ARG_STRING, &popt_drag_mode,
246
   N_("Global drag and drop mode: normal, 2clicks, both. Default mode is normal."), NULL},
247

248 249 250
  {"nolockcheck", '\0', 0, G_OPTION_ARG_NONE, &popt_nolockcheck,
   N_("Do not avoid the execution of multiple instances of GCompris."), NULL},

251 252 253 254 255 256
  {"sugarBundleId", '\0', 0, G_OPTION_ARG_STRING, &sugarBundleId,
   "Sugar Bundle Id", NULL},

  {"sugarActivityId", '\0', 0, G_OPTION_ARG_STRING, &sugarActivityId,
   "Sugar Activity Id", NULL},

257 258 259 260 261 262 263 264 265 266 267 268
  {"sugar",'\0', 0, G_OPTION_ARG_NONE, &popt_sugar_look,
   ("Use Sugar DE look&feel"), NULL},

  {"no-zoom",'\0', 0, G_OPTION_ARG_NONE, &popt_no_zoom,
   ("Disable maximization zoom"), NULL},

  {"timing-base",'\0', 0, G_OPTION_ARG_DOUBLE, &popt_timing_base,
   ("Increase activiites' timeout delays; useful values > 1.0; 1.0 to not change hardcoded value"), NULL},

  {"timing-mult",'\0', 0, G_OPTION_ARG_DOUBLE, &popt_timing_mult,
   ("How activiites' timeout delays are growing for several actors; useful values < 1.0; 1.0 to not change hardcoded value"), NULL},

269
  { NULL }
270 271
};

272
/* Remove any dialog box */
273
static void gc_close_all_dialog() {
274 275
  gc_dialog_close();
  gc_help_stop();
276
  gc_config_stop();
277 278 279
  gc_about_stop();
  gc_selector_file_stop();
  gc_selector_images_stop();
280 281
}

282 283 284 285 286 287 288 289
/* Return the zoom factor we are currently using for our window
 *
 */
double gc_zoom_factor_get()
{
  return zoom_factor;
}

290
static gint
291 292
_gc_size_allocate_event_callback (GtkWidget   *widget,
			      GtkAllocation *allocation,
293 294 295
			      gpointer     client_data)
{
  double xratio, yratio;
296
  double canvas_width, canvas_height;
297

298 299
  yratio=allocation->height/(float)(BOARDHEIGHT);
  xratio=allocation->width/(float)BOARDWIDTH;
300
  zoom_factor = MIN(xratio, yratio);
301
  g_message("The screen_width=%f screen_height=%f ratio=%f\n",
302
	    (double)allocation->width, (double)allocation->height, zoom_factor);
303

304 305 306 307 308
  if (!properties->zoom && zoom_factor > 1.)
      zoom_factor = 1.;

  canvas_width = BOARDWIDTH * zoom_factor;
  canvas_height = BOARDHEIGHT * zoom_factor;
309

310 311
  gtk_widget_set_size_request(canvas, canvas_width, canvas_height);
  goo_canvas_set_scale (GOO_CANVAS(canvas), zoom_factor);
312

313 314 315
  return FALSE;
}

Bruno Coudoin's avatar
Bruno Coudoin committed
316 317
static gint
board_widget_key_press_callback (GtkWidget   *widget,
318 319
				 GdkEventKey *event,
				 gpointer     client_data)
Bruno Coudoin's avatar
Bruno Coudoin committed
320
{
321
  int kv = event->keyval;
322

323 324
  if(event->state & GDK_CONTROL_MASK && ((event->keyval == GDK_r)
					 || (event->keyval == GDK_R))) {
325
    g_message("Refreshing the canvas\n");
326
    goo_canvas_update(GOO_CANVAS(canvas));
327 328
    return TRUE;
  }
Bruno Coudoin's avatar
Bruno Coudoin committed
329
  else if(event->state & GDK_CONTROL_MASK && ((event->keyval == GDK_q)
330
					 || (event->keyval == GDK_Q))) {
331
    gc_exit();
332 333
    return TRUE;
  }
334 335 336 337 338 339 340 341
  else if(event->state & GDK_CONTROL_MASK && ((event->keyval == GDK_w)
					 || (event->keyval == GDK_W))) {
    gc_close_all_dialog();

    if (gc_board_get_current()->previous_board != NULL)
      gc_board_stop();
    return TRUE;
  }
Bruno Coudoin's avatar
Bruno Coudoin committed
342 343 344 345 346 347 348 349 350
  else if(event->state & GDK_CONTROL_MASK && ((event->keyval == GDK_f)
					 || (event->keyval == GDK_F))) {
    /* Toggle fullscreen */
    if (fullscreen)
      gc_fullscreen_set(FALSE);
    else
      gc_fullscreen_set(TRUE);
    return TRUE;
  }
351 352 353 354 355 356 357 358 359 360
  else if(event->state & GDK_CONTROL_MASK && ((event->keyval == GDK_m)
					 || (event->keyval == GDK_M))) {
    /* Toggle Mute */
    if (mute)
	gc_sound_bg_resume();
    else
	gc_sound_bg_pause();
    mute = ! mute;
    return TRUE;
  }
361

Bruno Coudoin's avatar
Bruno Coudoin committed
362 363 364
  switch (event->keyval)
    {
    case GDK_Escape:
365
      gc_close_all_dialog();
366

367
      if (gc_board_get_current()->previous_board != NULL)
368
	gc_board_stop();
Bruno Coudoin's avatar
Bruno Coudoin committed
369
      return TRUE;
370
    case GDK_F5:
371
      g_message("Refreshing the canvas\n");
372
      goo_canvas_update(GOO_CANVAS(canvas));
373
      return TRUE;
374

375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
    case GDK_KP_Multiply:
      break;
    case GDK_KP_0:
    case GDK_KP_Insert:
      event->keyval=GDK_0;
      break;
    case GDK_KP_1:
    case GDK_KP_End:
      event->keyval=GDK_1;
      break;
    case GDK_KP_2:
    case GDK_KP_Down:
      event->keyval=GDK_2;
      break;
    case GDK_KP_3:
    case GDK_KP_Page_Down:
      event->keyval=GDK_3;
      break;
    case GDK_KP_4:
    case GDK_KP_Left:
      event->keyval=GDK_4;
      break;
    case GDK_KP_5:
    case GDK_KP_Begin:
      event->keyval=GDK_5;
      break;
    case GDK_KP_6:
    case GDK_KP_Right:
      event->keyval=GDK_6;
      break;
    case GDK_KP_7:
    case GDK_KP_Home:
      event->keyval=GDK_7;
      break;
    case GDK_KP_8:
    case GDK_KP_Up:
      event->keyval=GDK_8;
      break;
    case GDK_KP_9:
    case GDK_KP_Page_Up:
      event->keyval=GDK_9;
      break;
417
    default:
418 419 420 421
      break;
    }

  /* pass through the IM context */
422
  if (gc_board_get_current() && (!gc_board_get_current()->disable_im_context))
423 424
    {
      if (gtk_im_context_filter_keypress (properties->context, event))
Bruno Coudoin's avatar
Bruno Coudoin committed
425
	{
426
	  g_message("%d key is handled by context", kv);
427
	  return TRUE;
Bruno Coudoin's avatar
Bruno Coudoin committed
428 429 430
	}
    }

431
  g_message("%d key is NOT handled by context", kv);
432 433 434 435
  /* If the board needs to receive key pressed */
  /* NOTE: If a board receives key press, it must bind the ENTER Keys to OK
   *       whenever possible
   */
436
  if (gc_board_get_current_board_plugin()!=NULL
Bruno Coudoin's avatar
Bruno Coudoin committed
437
      && gc_board_get_current_board_plugin()->key_press)
438
    {
439
      return(gc_board_get_current_board_plugin()->key_press (event->keyval, NULL, NULL));
440
    }
441
  else if (gc_board_get_current_board_plugin()!=NULL
Bruno Coudoin's avatar
Bruno Coudoin committed
442
	   && gc_board_get_current_board_plugin()->ok &&
443 444 445
	   (event->keyval == GDK_KP_Enter ||
	    event->keyval == GDK_Return   ||
	    event->keyval == GDK_KP_Space))
446 447
    {
      /* Else we send the OK signal. */
448
      gc_board_get_current_board_plugin()->ok ();
449 450 451
      return TRUE;
    }

452
  /* Event not handled; try parent item */
Bruno Coudoin's avatar
Bruno Coudoin committed
453 454 455
  return FALSE;
};

456 457 458 459 460
guint gc_cursor_get()
{
  return gc_cursor_current;
}

461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
void gc_cursor_set(guint gdk_cursor_type)
{
  GdkCursor *cursor = NULL;

  // Little hack to force gcompris to use the default cursor
  if(gdk_cursor_type==GCOMPRIS_DEFAULT_CURSOR)
    gdk_cursor_type=properties->defaultcursor;

  // I suppose there is less than GCOMPRIS_FIRST_CUSTOM_CURSOR cursors defined in gdkcursors.h !
  if (gdk_cursor_type < GCOMPRIS_FIRST_CUSTOM_CURSOR) {
    cursor = gdk_cursor_new(gdk_cursor_type);
    gdk_window_set_cursor (window->window, cursor);
    gdk_cursor_destroy(cursor);
  } else { // we use a custom cursor
    GdkPixbuf *cursor_pixbuf = NULL;

    switch (gdk_cursor_type) {
    case GCOMPRIS_DEFAULT_CURSOR :
479
      cursor_pixbuf = gc_skin_pixmap_load("cursors/default.png");
480 481
      break;
    case GCOMPRIS_LINE_CURSOR :
482
      cursor_pixbuf = gc_skin_pixmap_load("cursors/line.png");
483 484
      break;
    case GCOMPRIS_RECT_CURSOR :
485
      cursor_pixbuf = gc_skin_pixmap_load("cursors/rect.png");
486 487
      break;
    case GCOMPRIS_FILLRECT_CURSOR :
488
      cursor_pixbuf = gc_skin_pixmap_load("cursors/fillrect.png");
489 490
      break;
    case GCOMPRIS_CIRCLE_CURSOR :
491
      cursor_pixbuf = gc_skin_pixmap_load("cursors/circle.png");
492 493
      break;
    case GCOMPRIS_FILLCIRCLE_CURSOR :
494
      cursor_pixbuf = gc_skin_pixmap_load("cursors/fillcircle.png");
495 496
      break;
    case GCOMPRIS_FILL_CURSOR :
497
      cursor_pixbuf = gc_skin_pixmap_load("cursors/fill.png");
498 499
      break;
    case GCOMPRIS_DEL_CURSOR :
500
      cursor_pixbuf = gc_skin_pixmap_load("cursors/del.png");
501 502
      break;
    case GCOMPRIS_SELECT_CURSOR :
503
      cursor_pixbuf = gc_skin_pixmap_load("cursors/select.png");
504 505 506 507 508 509 510 511
      break;
    default :
      return;
      break;
    }

    if(cursor_pixbuf)
      {
512 513
	cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
					    cursor_pixbuf, 0, 0);
514 515 516 517 518
	gdk_window_set_cursor(window->window, cursor);
	gdk_cursor_unref(cursor);
	gdk_pixbuf_unref(cursor_pixbuf);
      }
  }
519
  gc_cursor_current = gdk_cursor_type;
520 521
}

Bruno Coudoin's avatar
Bruno Coudoin committed
522 523 524
/**
 * Return the main canvas we run in
 */
525
GooCanvas *gc_get_canvas()
Bruno Coudoin's avatar
Bruno Coudoin committed
526
{
527
  return GOO_CANVAS (canvas);
Bruno Coudoin's avatar
Bruno Coudoin committed
528 529
}

530
GtkWidget *gc_get_window()
531 532 533 534
{
  return window;
}

Bruno Coudoin's avatar
Bruno Coudoin committed
535
static void
536
_set_svg_background(GooCanvasItem *parent, gchar *file, gchar *id)
Bruno Coudoin's avatar
Bruno Coudoin committed
537
{
Bruno Coudoin's avatar
Bruno Coudoin committed
538
  RsvgHandle *rsvg_handle;
Bruno Coudoin's avatar
Bruno Coudoin committed
539

540
  rsvg_handle = gc_rsvg_load (file);
Bruno Coudoin's avatar
Bruno Coudoin committed
541 542 543

  if(backgroundsvgimg)
    g_object_set(backgroundsvgimg,
544
		 "svg-handle", rsvg_handle,
545
		 "svg-id", id,
Bruno Coudoin's avatar
Bruno Coudoin committed
546 547
		 NULL);
  else
548
    backgroundsvgimg = goo_canvas_svg_new (parent,
Bruno Coudoin's avatar
Bruno Coudoin committed
549 550 551 552 553 554 555 556 557 558 559 560
					 rsvg_handle,
					 NULL);
  goo_canvas_item_lower(backgroundsvgimg, NULL);

  g_object_unref(rsvg_handle);
}

static void
_set_pixmap_background(GooCanvasItem *parent, gchar *file)
{
  GdkPixbuf *background_pixmap;

561
  background_pixmap = gc_pixmap_load (file);
Bruno Coudoin's avatar
Bruno Coudoin committed
562 563

  if(backgroundimg)
564 565 566
    g_object_set(backgroundimg,
		 "pixbuf", background_pixmap,
		 NULL);
567
  else
568 569 570 571 572 573 574 575
    backgroundimg = goo_canvas_image_new (parent,
					  background_pixmap,
					  0.0,
					  0.0,
					  "width", (gdouble) BOARDWIDTH,
					  "height", (gdouble) BOARDHEIGHT,
					  NULL);
  goo_canvas_item_lower(backgroundimg, NULL);
Bruno Coudoin's avatar
Bruno Coudoin committed
576 577 578

  gdk_pixbuf_unref(background_pixmap);

Bruno Coudoin's avatar
Bruno Coudoin committed
579 580
}

581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
void _clear_svg_background()
{
  if(backgroundsvgimg)
    goo_canvas_item_remove(backgroundsvgimg);

  backgroundsvgimg = NULL;
}

void _clear_pixmap_background()
{
  if(backgroundimg)
    goo_canvas_item_remove(backgroundimg);

  backgroundimg = NULL;
}

Bruno Coudoin's avatar
Bruno Coudoin committed
597 598 599 600 601 602 603 604 605 606 607
void
gc_set_background(GooCanvasItem *parent, gchar *file)
{
  g_assert(parent);
  g_assert(file);

  if(g_str_has_suffix(file, ".svg") ||
     g_str_has_suffix(file, ".svgz"))
    {
      if(backgroundimg)
	goo_canvas_item_remove(backgroundimg);
608 609

      backgroundimg = NULL;
610
      _set_svg_background(parent, file, NULL);
Bruno Coudoin's avatar
Bruno Coudoin committed
611 612 613
    }
  else
    {
614
      _clear_svg_background();
Bruno Coudoin's avatar
Bruno Coudoin committed
615 616
      _set_pixmap_background(parent, file);
    }
Bruno Coudoin's avatar
Bruno Coudoin committed
617 618
}

619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
void
gc_set_background_by_id(GooCanvasItem *parent, RsvgHandle *rsvg_handle,
			gchar *id)
{
  g_assert(parent);
  g_assert(rsvg_handle);

  _clear_pixmap_background();

  if(backgroundsvgimg)
    g_object_set(backgroundsvgimg,
		 "svg-handle", rsvg_handle,
		 "svg-id", id,
		 NULL);
  else
    backgroundsvgimg = goo_canvas_svg_new (parent,
					   rsvg_handle,
					   "svg-id", id,
					   NULL);

  goo_canvas_item_lower(backgroundsvgimg, NULL);
}

642 643 644 645 646 647 648 649
void
gc_set_default_background(GooCanvasItem *parent)
{
  gc_set_background_by_id(parent,
			  gc_skin_rsvg_get(),
			  "#BACKGROUND");
}

650 651 652
static gboolean
_realize_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
653
#ifdef USE_SUGAR
654
  Window xwindow = GDK_WINDOW_XWINDOW(window->window);
655 656 657
  /*
   * Sugar requires properties to be set before the windows is realized
   */
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
  if (sugarBundleId)
    XChangeProperty(GDK_DISPLAY(),
		    xwindow,
		    XInternAtom(GDK_DISPLAY(), "_SUGAR_BUNDLE_ID", 0),
		    XInternAtom(GDK_DISPLAY(), "STRING", 0), 8,
		    PropModeReplace,
		    (unsigned char *) sugarBundleId, strlen(sugarBundleId));

  if (sugarActivityId)
    XChangeProperty(GDK_DISPLAY(),
		    xwindow,
		    XInternAtom(GDK_DISPLAY(), "_SUGAR_ACTIVITY_ID", 0),
		    XInternAtom(GDK_DISPLAY(), "STRING", 0), 8,
		    PropModeReplace,
		    (unsigned char *) sugarActivityId, strlen(sugarActivityId));
673
#endif
674 675 676 677

  return FALSE;
}

678
static void
679
init_workspace()
Bruno Coudoin's avatar
Bruno Coudoin committed
680
{
681 682
  workspace = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), workspace);
683

684 685 686 687
  GtkWidget *background = gtk_event_box_new();
  GdkColor black = {0, 0, 0, 0};
  gtk_widget_modify_bg(background, GTK_STATE_NORMAL, &black);
  gtk_box_pack_end(GTK_BOX(workspace), background, TRUE, TRUE, 0);
688

689 690 691 692
  alignment = gtk_alignment_new(.5, .5, 0., 0.);
  g_signal_connect (GTK_OBJECT (alignment), "size-allocate",
		      G_CALLBACK (_gc_size_allocate_event_callback), NULL);
  gtk_container_add(GTK_CONTAINER(background), alignment);
693

694 695
  gtk_container_add(GTK_CONTAINER(alignment), canvas);
  gtk_widget_set_size_request (GTK_WIDGET(canvas), BOARDWIDTH, BOARDHEIGHT);
696 697 698 699
  goo_canvas_set_bounds (GOO_CANVAS(canvas),
			 0, 0,
			 BOARDWIDTH,
			 BOARDHEIGHT);
700
  g_object_set (G_OBJECT(canvas), "background-color", "#000", NULL);
701 702 703 704 705 706 707 708 709 710 711

#ifdef MAC_INTEGRATION
  GtkWidget *quit_item;
  quit_item = gtk_menu_item_new();
  ige_mac_menu_set_quit_menu_item(GTK_MENU_ITEM (quit_item));
  gtk_signal_connect(GTK_OBJECT (quit_item),
		     "activate", GTK_SIGNAL_FUNC (quit_cb), NULL);
  gtk_widget_show (quit_item);

#endif

712
}
Bruno Coudoin's avatar
Bruno Coudoin committed
713

714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
static GcomprisBoard *get_board_to_start()
{
  GcomprisBoard *board_to_start;

  /* By default, the menu will be started */
  board_to_start = properties->menu_board;

  /* Get and Run the root menu */
  if(properties->administration)
    {
      board_to_start = gc_menu_section_get("/administration/administration");
    }
  else
    {
      /* If we have a profile defined, run the login screen
       * (the login screen is a board that uppon login completion
       * starts the menu)
       */
      if(properties->profile && properties->profile->group_ids)
	{
	  gboolean found = FALSE;

	  GList *group_id;

	  for (group_id = properties->profile->group_ids; group_id != NULL; group_id = group_id->next)
	    if (g_list_length(gc_db_users_from_group_get( *((int *) group_id->data))) > 0){
	      found = TRUE;
	      break;
	    }

	  /* No profile start normally */
	  if (found)
	    board_to_start = gc_menu_section_get("/login/login");
	  else {
	    board_to_start = gc_menu_section_get(properties->root_menu);
	    /* this will set user information to system one */
	    gc_profile_set_current_user(NULL);
	  }
	}
      else
	/* this will set user information to system one */
	gc_profile_set_current_user(NULL);
    }

  return board_to_start;
}

761 762
static void setup_window ()
{
763
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Bruno Coudoin's avatar
Bruno Coudoin committed
764

765 766 767 768
  /*
   * Set an icon for gcompris
   * ------------------------
   */
769 770 771 772 773 774 775
  {
    GdkPixbuf *icon_pixbuf = NULL;
    gchar *iconfile = gc_file_find_absolute("%s/%s",
					    properties->system_icon_dir, "gcompris.png",
					    NULL);
    if(iconfile)
      {
776
	icon_pixbuf = gdk_pixbuf_new_from_file(iconfile, NULL);
777 778 779 780 781 782 783 784 785 786
	g_free(iconfile);

	if (icon_pixbuf)
	  {
	    gtk_window_set_icon (GTK_WINDOW (window), icon_pixbuf);
	    gdk_pixbuf_unref (icon_pixbuf);
	  }
      }
    else
      g_message ("Failed to find icon file: 'gcompris.png'");
787

788
  }
789

790
  gtk_window_set_title(GTK_WINDOW (window), "GCompris");
791 792 793 794 795

  /*
   * Set the main window
   * -------------------
   */
796

797
  gtk_window_set_default_size(GTK_WINDOW(window), BOARDWIDTH, BOARDHEIGHT);
798
  gtk_window_set_wmclass(GTK_WINDOW(window), "gcompris", "GCompris");
799 800
  g_signal_connect (GTK_OBJECT (window), "realize",
		    G_CALLBACK (_realize_callback), NULL);
Bruno Coudoin's avatar
Bruno Coudoin committed
801
  gtk_widget_realize (window);
Bruno Coudoin's avatar
Bruno Coudoin committed
802

Bruno Coudoin's avatar
Bruno Coudoin committed
803 804 805
  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
		      GTK_SIGNAL_FUNC (quit_cb), NULL);

806 807
  gtk_signal_connect (GTK_OBJECT (window), "map_event",
		      GTK_SIGNAL_FUNC (map_cb), NULL);
Bruno Coudoin's avatar
Bruno Coudoin committed
808

809
  // Set the cursor
810
  gc_cursor_set(GCOMPRIS_DEFAULT_CURSOR);
811

812
  canvas     = goo_canvas_new();
Bruno Coudoin's avatar
Bruno Coudoin committed
813

814 815 816 817
  g_object_set (canvas,
		"has-tooltip", TRUE,
		NULL);

818 819 820 821
  g_object_set (G_OBJECT(goo_canvas_get_root_item(GOO_CANVAS(canvas))),
		"can-focus", TRUE,
		NULL);

Bruno Coudoin's avatar
Bruno Coudoin committed
822

823 824
  gtk_signal_connect_after (GTK_OBJECT (window), "key_press_event",
			    GTK_SIGNAL_FUNC (board_widget_key_press_callback), 0);
Bruno Coudoin's avatar
Bruno Coudoin committed
825 826 827 828
  g_signal_connect_after (canvas,
			  "key_press_event",
			  GTK_SIGNAL_FUNC (board_widget_key_press_callback), 0);

829
  gc_im_init(window);
830

831 832 833 834
  init_workspace();

  GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_FOCUS);
  gtk_widget_grab_focus (canvas);
835

836 837
}

838
#ifdef ACTIVATION_CODE
839 840
/** Display the activation dialog for the windows version
 *
841
 * return TRUE is the dialog is display, FALSE instead.
842
 */
843
int
844 845
display_activation_dialog()
{
846
  int board_count = 0;
847
  int gc_board_number_in_demo = 0;
848
  GList *list;
849
  gint  key_is_valid = 0;
850

Bruno Coudoin's avatar
Bruno Coudoin committed
851
  key_is_valid = gc_activation_check(properties->key);
852

Bruno Coudoin's avatar
Bruno Coudoin committed
853
  if(key_is_valid == 1)
854
    return FALSE;
855 856 857 858 859 860
  else if(key_is_valid == 2)
    {
      g_free ( gc_prop_get()->key );
      gc_prop_get()->key = strdup("");
      gc_prop_save(properties);
    }
861 862 863 864 865
  /* Count non menu boards */
  for (list = gc_menu_get_boards(); list != NULL; list = list->next)
    {
      GcomprisBoard *board = list->data;
      if (strcmp(board->type, "menu") != 0 &&
866 867 868
	  strncmp(board->section, "/experimental", 13) != 0)
	{
	  board_count++;
869
	  if(board->demo)
870 871
	      gc_board_number_in_demo++;
	}
872 873
    }

874
  /* Entry area */
875 876
  widget_activation_entry = gtk_entry_new();
  gtk_entry_set_max_length(GTK_ENTRY(widget_activation_entry), 6);
877
  activation_item = \
878 879 880
    goo_canvas_widget_new (goo_canvas_get_root_item(GOO_CANVAS(canvas)),
			   GTK_WIDGET(widget_activation_entry),
			   BOARDWIDTH / 2 - 50,
881
			   BOARDHEIGHT - 90,
882 883
			   100.0,
			   30.0,
884 885 886 887 888
			   NULL);
  gtk_signal_connect(GTK_OBJECT(widget_activation_entry), "activate",
		     GTK_SIGNAL_FUNC(activation_enter_callback),
		     NULL);

889 890
  char *msg = g_strdup_printf( \
      _("GCompris is free software released under the GPL License. "
891
	"In order to support its development, this version "
892 893 894 895 896 897 898
	"provides only %d of the %d activities. You can get the "
	"full version for a small fee at\n<http://gcompris.net>\n"
	"The GNU/Linux version does not have this restriction. "
	"If you also believe that we should teach freedom to children, "
	"please consider using GNU/Linux. Get more information at "
	"FSF:\n<http://www.fsf.org/philosophy>"),
      gc_board_number_in_demo, board_count);
899 900
  gc_dialog(msg, activation_done);
  g_free(msg);
901

902 903 904
  gtk_widget_show(GTK_WIDGET(widget_activation_entry));
  gtk_entry_set_text(GTK_ENTRY(widget_activation_entry), "CODE");
  gtk_widget_grab_focus(GTK_WIDGET(widget_activation_entry));
905
  return TRUE;
Bruno Coudoin's avatar
Bruno Coudoin committed
906 907
}

908 909 910 911
/**
 * Return -1 if the code is not valid
 *        0  if the code is valid but out of date
 *        1  if the code is valid and under 2 years
912
 *        2  for the demo code
913
 */
914
gint gc_activation_check(const char *code)
915
{
Bruno Coudoin's avatar
Bruno Coudoin committed
916
#ifdef  DISABLE_ACTIVATION_CODE
Bruno Coudoin's avatar
Bruno Coudoin committed
917
  return 1;
Bruno Coudoin's avatar
Bruno Coudoin committed
918
#else
919 920 921 922
  int value = 0;
  int i;
  char crc1 = 0;
  char crc2 = 0;
923
  char codeddate[5];
924

925 926 927
  if (properties->administration)
    return 1;

928 929 930
  if(strlen(code) != 6)
    return -1;

931 932 933 934 935 936 937
  // A special code to test the full version without
  // saving the activation
  if (strncmp(code, "123321", 6) == 0)
    {
      return 2;
    }

938 939 940 941
  for(i=3; i>=0; i--)
    {
      value |= code[i] & 0x07;
      value = value << 3;
Bruno Coudoin's avatar
Bruno Coudoin committed
942
      crc1 = (crc1 ^ code[i]) & 0x07;
943 944 945 946
    }
  value = value >> 3;
  crc1 = 0x30 | crc1;
  crc2 = 0x30 | (code[2] ^ code[3]);
947

Bruno Coudoin's avatar
Bruno Coudoin committed
948 949 950 951 952
  if(crc1 != code[4])
    return(-1);

  if(crc2 != code[5])
    return(-1);
953

Bruno Coudoin's avatar
Bruno Coudoin committed
954
  codeddate[3] = 0x30 | (value & 0x000F);
955
  value = value >> 4;
956

Bruno Coudoin's avatar
Bruno Coudoin committed
957
  codeddate[2] = 0x30 | (value & 0x0001);
958
  value = value >> 1;
959

Bruno Coudoin's avatar
Bruno Coudoin committed
960
  codeddate[1] = 0x30 | (value & 0x000F);
961
  value = value >> 4;
962

Bruno Coudoin's avatar
Bruno Coudoin committed
963
  codeddate[0] = 0x30 | (value & 0x0003);
964 965 966 967 968 969
  codeddate[4] = '\0';

  if(atoi(codeddate) + 200 >= atoi(BUILD_DATE))
    return(1);
  else
    return(0);
Bruno Coudoin's avatar
Bruno Coudoin committed
970
#endif
971 972
}

973 974 975 976
/* Check the activation code
 *
 */
static void
977 978
activation_enter_callback( GtkWidget *entry,
			   GtkWidget *notused )
979
{
980 981 982
  const char *code = gtk_entry_get_text(GTK_ENTRY(entry));

  switch(gc_activation_check(code))
983
    {
984
    case 1:
985
    case 2:
Bruno Coudoin's avatar
Bruno Coudoin committed
986 987
      gc_prop_get()->key = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
      gc_prop_save(properties);
988 989 990 991 992 993 994 995
      gtk_entry_set_text(GTK_ENTRY(entry), "GOOD");
      break;
    case 0:
      gtk_entry_set_text(GTK_ENTRY(entry), "EXPIRE");
      break;
    case -1:
      gtk_entry_set_text(GTK_ENTRY(entry), "WRONG");
      break;
996 997 998 999 1000 1001 1002 1003 1004
    }
}

/* Callback for the activation dialog
 *
 */
static void
activation_done()
{
1005 1006 1007 1008
  if ((strcmp((char *)gtk_entry_get_text(GTK_ENTRY(widget_activation_entry)), "CODE") != 0) &&
      (strcmp((char *)gtk_entry_get_text(GTK_ENTRY(widget_activation_entry)), "GOOD") != 0) &&
      (strcmp((char *)gtk_entry_get_text(GTK_ENTRY(widget_activation_entry)), "WRONG") != 0))
    {
1009
      activation_enter_callback(GTK_WIDGET(widget_activation_entry), NULL);
1010
    }
1011

1012
  gc_board_play( get_board_to_start());
1013
  goo_canvas_item_remove (activation_item);
1014 1015 1016 1017 1018 1019
}
#endif

/** Call me to end an activity
 *
 */
1020
void gc_board_end()
Bruno Coudoin's avatar
Bruno Coudoin committed
1021
{
1022
  if (gc_board_get_current()->previous_board) {
1023
    /* Run the previous board */
1024
    gc_board_play(gc_board_get_current()->previous_board);
1025
  }
Bruno Coudoin's avatar
Bruno Coudoin committed
1026 1027
}

1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
void _set_geometry_hints(gboolean state)
{
  GdkGeometry hints;
  hints.base_width = 615;
  hints.base_height = 400;
  hints.min_width = hints.base_width;
  hints.min_height = hints.base_height;
  hints.width_inc = 1;
  hints.height_inc = 1;
  hints.min_aspect = (float)BOARDWIDTH/BOARDHEIGHT;
  if (state)
    /* Warning: this is a workaround for GTK-OSX */
    hints.max_aspect = (float)10; /* Fullscreen case */
  else
    hints.max_aspect = (float)BOARDWIDTH/BOARDHEIGHT;
  gint geom_mask = GDK_HINT_RESIZE_INC |
                   GDK_HINT_MIN_SIZE |
                   GDK_HINT_BASE_SIZE;
  if (!popt_sugar_look)
      geom_mask |= GDK_HINT_ASPECT;
  gtk_window_set_geometry_hints (GTK_WINDOW (window), NULL, &hints, geom_mask);
}

1051 1052 1053 1054
/** \brief toggle full screen mode
 *
 *
 */
1055
void gc_fullscreen_set(gboolean state)
1056
{
1057 1058 1059 1060 1061
  static gint window_x = 0;
  static gint window_y = 0;
  static gint window_w = BOARDWIDTH;
  static gint window_h = BOARDHEIGHT;

Bruno Coudoin's avatar
Bruno Coudoin committed
1062
  fullscreen = state;
1063
  _set_geometry_hints(state);
1064 1065
  if(state)
    {
1066 1067
      gtk_window_get_position ( (GtkWindow*)( window ), &window_x, &window_y );
      gtk_window_get_size ( GTK_WINDOW ( window ), &window_w, &window_h );
1068
#ifdef WIN32
1069 1070 1071
      // WARNING: Doing this is required on Windows
      //          but keep the window hidden on GNU/Linux
      gtk_widget_hide ( window );
1072 1073
#elif MAC_INTEGRATION
      // WARNING: Doing this is required on MacOSX
1074
      //          but keep the window hidden on GNU/Linux
1075
      gtk_widget_hide ( window );
1076 1077
#else
#endif
1078 1079 1080
      gtk_window_set_decorated ( GTK_WINDOW ( window ), FALSE );
      gtk_window_set_type_hint ( GTK_WINDOW ( window ),
				 GDK_WINDOW_TYPE_HINT_DESKTOP );
1081
      if (popt_sugar_look)
1082
	gtk_window_maximize ( GTK_WINDOW( window ) );
1083
      else
1084 1085 1086 1087 1088 1089 1090 1091
        gtk_window_fullscreen ( GTK_WINDOW ( window ) );

      gtk_window_move ( GTK_WINDOW ( window ), 0, 0 );

      GdkScreen *screen = gtk_window_get_screen ( GTK_WINDOW ( window ) );
      gtk_window_resize ( GTK_WINDOW ( window ),
			  gdk_screen_get_width (screen),
			  gdk_screen_get_height (screen) );
1092 1093
    }
  else
1094
    {
1095 1096 1097 1098 1099 1100 1101
      gtk_widget_hide ( window );
      gtk_window_set_type_hint ( GTK_WINDOW ( window ),
				 GDK_WINDOW_TYPE_HINT_NORMAL );
      gtk_window_unfullscreen ( GTK_WINDOW ( window ) );
      gtk_window_set_decorated ( GTK_WINDOW ( window ), TRUE );
      gtk_window_move ( GTK_WINDOW ( window ), window_x, window_y );
      gtk_window_resize ( GTK_WINDOW ( window ), window_w, window_h );
1102
    }
1103
  gtk_window_present ( GTK_WINDOW ( window ) );
1104 1105 1106

}

1107
/* Use these instead of the goo_canvas ones for proper fullscreen mousegrab
1108
   handling. */
1109 1110
int gc_canvas_item_grab (GooCanvasItem *item, unsigned int event_mask,
			 GdkCursor *cursor, guint32 etime)
1111 1112
{
  int retval;
1113

1114 1115
  retval = goo_canvas_pointer_grab(goo_canvas_item_get_canvas(item), item,
				   event_mask, cursor, etime);
1116 1117
  if (retval != GDK_GRAB_SUCCESS)
    return retval;
1118

1119 1120 1121
  return retval;
}

1122
void gc_canvas_item_ungrab (GooCanvasItem *item, guint32 etime)
1123
{
1124
  goo_canvas_pointer_ungrab(goo_canvas_item_get_canvas(item), item, etime);
1125 1126
}

1127
static void cleanup()
Bruno Coudoin's avatar
Bruno Coudoin committed
1128
{
1129 1130 1131 1132
  /* Do not loopback in exit */
  signal(SIGINT,  NULL);
  signal(SIGSEGV, NULL);

1133
  single_instance_release(); /* Must be done before property destroy */
1134
  gc_board_stop();
1135
  gc_db_exit();
1136
  gc_fullscreen_set(FALSE);
1137
  gc_menu_destroy();
1138 1139
  gc_net_destroy();
  gc_cache_destroy();
1140
  gc_prop_destroy(gc_prop_get());
1141
}
1142

1143
void gc_exit()
1144 1145
{
  g_signal_emit_by_name(G_OBJECT(window), "delete_event");
1146
}
Bruno Coudoin's avatar
Bruno Coudoin committed
1147

1148 1149
static void quit_cb (GtkWidget *widget, gpointer data)
{
1150 1151 1152 1153

#ifdef DMALLOC
  dmalloc_shutdown();
#endif
1154 1155
  cleanup();
  gtk_main_quit();
1156

1157 1158 1159 1160 1161
  /*
   * Very important or GCompris crashes on exit when closed from the dialog
   * It's like if code in the dialog callback continue after the gtk_main_quit is done
   */
  exit(0);
Bruno Coudoin's avatar
Bruno Coudoin committed
1162 1163
}

1164 1165 1166 1167 1168 1169 1170 1171
/*
 * We want GCompris to be set as fullscreen the later possible
 *
 */
static void map_cb (GtkWidget *widget, gpointer data)
{
  if(is_mapped == FALSE)
    {
Bruno Coudoin's avatar
Bruno Coudoin committed
1172
      is_mapped = TRUE;
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
      GcomprisBoard *board_to_start;

      gc_set_default_background (goo_canvas_get_root_item (GOO_CANVAS(canvas)));

      gc_fullscreen_set(properties->fullscreen);

      gc_status_init("");
      gc_board_init();
      /* Load all the menu once */
      gc_menu_load();
      /* Save the root_menu */
      properties->menu_board = gc_menu_section_get(properties->root_menu);

      gc_bar_start(GTK_CONTAINER(workspace), GOO_CANVAS(canvas));

      gc_status_close();

      board_to_start = get_board_to_start();

      if(!board_to_start) {
	gchar *tmpstr= g_strdup_printf("Couldn't find the board menu %s, or plugin execution error", properties->root_menu);
	gc_dialog(tmpstr, NULL);
	g_free(tmpstr);
      } else if(!gc_board_check_file(board_to_start)) {
	gchar *tmpstr= g_strdup_printf("Couldn't find the board menu, or plugin execution error");
	gc_dialog(tmpstr, NULL);
	g_free(tmpstr);
      } else {
	g_message("Fine, we got the gcomprisBoardMenu, xml boards parsing went fine");
	if(!display_activation_dialog())
	  gc_board_play(board_to_start);
      }

1206
    }
1207
  g_message("gcompris window is now mapped");
1208 1209
}

1210
/*
1211
 * Process the cleanup of the child (no zombies)
1212 1213
 * ---------------------------------------------
 */
1214
void gc_terminate(int signum)
1215 1216
{

1217
  g_message("GCompris got the %d signal, starting exit procedure", signum);
1218

1219
  gc_exit();
1220

1221 1222
}

Bruno Coudoin's avatar
Bruno Coudoin committed
1223 1224
static void load_properties ()
{
1225
  GError *error = NULL;
1226
  properties = gc_prop_new ();
1227 1228 1229 1230

  /* Initialize the binary relocation API
   *  http://autopackage.org/docs/binreloc/
   */
1231
  if(gbr_init (&error))
1232
    g_message("Binary relocation enabled");
1233
  else
1234
    {
1235 1236 1237 1238
      if (error->code == GBR_INIT_ERROR_DISABLED)
	g_message("Binary relocation disabled");
      else
	g_message("Binary relocation start failed with error %d", error->code);
1239 1240
      g_error_free (error);
    }
1241

Bruno Coudoin's avatar
Bruno Coudoin committed
1242 1243
  exec_prefix = gbr_find_exe_dir(NULL);
  g_warning("exec_prefix %s\n", (exec_prefix==NULL ? "NONE" : exec_prefix));
1244

1245 1246 1247 1248 1249
  {
    gchar *pkg_data_dir = gbr_find_data_dir(PACKAGE_DATA_DIR);
    gchar *pkg_clib_dir = gbr_find_lib_dir(PACKAGE_CLIB_DIR);

    properties->package_data_dir = g_strconcat(pkg_data_dir, "/gcompris/boards", NULL);
1250
    properties->package_skin_dir = g_strconcat(pkg_data_dir, "/gcompris/boards/skins", NULL);
1251 1252 1253 1254 1255 1256 1257 1258 1259
    properties->package_locale_dir = gbr_find_locale_dir(PACKAGE_LOCALE_DIR);
    properties->package_plugin_dir = g_strconcat(pkg_clib_dir, "/gcompris", NULL);
    properties->package_python_plugin_dir = g_strconcat(pkg_data_dir, "/gcompris/python",
							NULL);
    properties->system_icon_dir = g_strconcat(pkg_data_dir, "/pixmaps", NULL);
    properties->menu_dir = g_strdup(properties->package_data_dir);
    g_free(pkg_data_dir);
    g_free(pkg_clib_dir);
  }
1260

1261
  /* Display the directory value we have */