gcompris.c 51.3 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 29 30
#include "gcompris.h"

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

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

45 46
#include <glib/gstdio.h>

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

54 55
#include "binreloc.h"

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

59 60
static double zoom_factor = 1.0;

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

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

Bruno Coudoin's avatar
Bruno Coudoin committed
71 72
//static gint pause_board_cb (GtkWidget *widget, gpointer data);
static void quit_cb (GtkWidget *widget, gpointer data);
73
static void map_cb  (GtkWidget *widget, gpointer data);
74
#ifdef WIN32
75
#elif MAC_INTEGRATION
76
#else
77 78
static gboolean _realize_callback (GtkWidget *widget, GdkEventExpose *event,
				   gpointer data);
79
#endif
Bruno Coudoin's avatar
Bruno Coudoin committed
80 81 82
static gint board_widget_key_press_callback (GtkWidget   *widget,
					    GdkEventKey *event,
					    gpointer     client_data);
83
void gc_terminate(int signum);
84
static void single_instance_release();
Bruno Coudoin's avatar
Bruno Coudoin committed
85

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


102 103
static GcomprisProperties *properties = NULL;
static gboolean		   is_mapped = FALSE;
Bruno Coudoin's avatar
Bruno Coudoin committed
104
static gboolean		   fullscreen;
105
static guint		   gc_cursor_current;
Bruno Coudoin's avatar
Bruno Coudoin committed
106 107 108 109

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

110
static GooCanvasItem *backgroundimg = NULL;
Bruno Coudoin's avatar
Bruno Coudoin committed
111
static GooCanvasItem *backgroundsvgimg = NULL;
112 113 114
static gchar           *gc_locale = NULL;
static gchar           *gc_user_default_locale = NULL;
static gboolean		gc_debug = FALSE;
Bruno Coudoin's avatar
Bruno Coudoin committed
115

116 117 118
/****************************************************************************/
/* Command line params */

119
/*** gcompris-popttable */
120 121 122 123 124 125 126 127
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;
128
static gint popt_nolockcheck	   = FALSE;
129
static gchar *popt_root_menu       = NULL;
130
static gchar *popt_package_data_dir = NULL;
131
static gchar *popt_package_skin_dir = NULL;
132 133
static gchar *popt_plugin_dir      = NULL;
static gchar *popt_python_plugin_dir = NULL;
134
static gchar *popt_locale_dir      = NULL;
135
static gchar *popt_menu_dir        = NULL;
136 137 138 139 140 141
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;
142 143
static gchar *popt_config_dir	   = NULL;
static gchar *popt_user_dir	   = NULL;
144 145 146
static gint  popt_experimental     = FALSE;
static gint  popt_no_quit	   = FALSE;
static gint  popt_no_config        = FALSE;
147 148 149
static gchar *popt_server          = NULL;
static gint  *popt_web_only        = NULL;
static gchar *popt_cache_dir       = NULL;
150
static gchar *popt_drag_mode       = NULL;
151 152
static gchar *sugarBundleId        = NULL;
static gchar *sugarActivityId      = NULL;
153 154 155 156
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;
157 158 159

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

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

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

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

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

174
  {"difficulty", 'd', 0, G_OPTION_ARG_INT, &popt_difficulty_filter,
175
   N_("display only activities with this difficulty level."), NULL},
176

177
  {"debug", 'D', 0, G_OPTION_ARG_NONE, &popt_debug,
178
   N_("display debug informations on the console."), NULL},
179

180
  {"version", 'v', 0, G_OPTION_ARG_NONE, &popt_version,
181
   N_("Print the version of " PACKAGE), NULL},
182

183
  {"root-menu", 'l', 0, G_OPTION_ARG_STRING, &popt_root_menu,
Bruno Coudoin's avatar
Bruno Coudoin committed
184 185 186
   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},
187

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

191 192 193
  {"package_skin_dir", 'S', 0, G_OPTION_ARG_STRING, &popt_package_skin_dir,
   N_("GCompris will find the skins in this directory"), NULL},

194 195 196 197 198
  {"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},
199

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

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

206
  {"administration", 'a', 0, G_OPTION_ARG_NONE, &popt_administration,
207
   N_("Run GCompris in administration and user-management mode"), NULL},
208

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

212
  {"create-db",'\0', 0, G_OPTION_ARG_NONE, &popt_create_db,
213
   N_("Create the alternate database for profiles"), NULL},
214

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

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

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

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

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

230
  {"experimental",'\0', 0, G_OPTION_ARG_NONE, &popt_experimental,
231
   N_("Run the experimental activities"), NULL},
232

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

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

239 240 241 242 243 244 245 246 247 248
  {"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},

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

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

255 256 257 258 259 260
  {"sugarBundleId", '\0', 0, G_OPTION_ARG_STRING, &sugarBundleId,
   "Sugar Bundle Id", NULL},

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

261 262 263 264 265 266 267 268 269 270 271 272
  {"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},

273
  { NULL }
274 275
};

276
/* Remove any dialog box */
277
static void gc_close_all_dialog() {
278 279
  gc_dialog_close();
  gc_help_stop();
280
  gc_config_stop();
281 282 283
  gc_about_stop();
  gc_selector_file_stop();
  gc_selector_images_stop();
284 285
}

286 287 288 289 290 291 292 293
/* Return the zoom factor we are currently using for our window
 *
 */
double gc_zoom_factor_get()
{
  return zoom_factor;
}

294
static gint
295 296
_gc_size_allocate_event_callback (GtkWidget   *widget,
			      GtkAllocation *allocation,
297 298 299
			      gpointer     client_data)
{
  double xratio, yratio;
300
  double canvas_width, canvas_height;
301

302 303
  yratio=allocation->height/(float)(BOARDHEIGHT);
  xratio=allocation->width/(float)BOARDWIDTH;
304
  zoom_factor = MIN(xratio, yratio);
305
  g_message("The screen_width=%f screen_height=%f ratio=%f\n",
306
	    (double)allocation->width, (double)allocation->height, zoom_factor);
307

308 309 310 311 312
  if (!properties->zoom && zoom_factor > 1.)
      zoom_factor = 1.;

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

314 315
  gtk_widget_set_size_request(canvas, canvas_width, canvas_height);
  goo_canvas_set_scale (GOO_CANVAS(canvas), zoom_factor);
316

317 318 319
  return FALSE;
}

Bruno Coudoin's avatar
Bruno Coudoin committed
320 321
static gint
board_widget_key_press_callback (GtkWidget   *widget,
322 323
				 GdkEventKey *event,
				 gpointer     client_data)
Bruno Coudoin's avatar
Bruno Coudoin committed
324
{
325
  int kv = event->keyval;
326

327 328
  if(event->state & GDK_CONTROL_MASK && ((event->keyval == GDK_r)
					 || (event->keyval == GDK_R))) {
329
    g_message("Refreshing the canvas\n");
330
    goo_canvas_update(GOO_CANVAS(canvas));
331 332
    return TRUE;
  }
Bruno Coudoin's avatar
Bruno Coudoin committed
333
  else if(event->state & GDK_CONTROL_MASK && ((event->keyval == GDK_q)
334
					 || (event->keyval == GDK_Q))) {
335
    gc_exit();
336 337
    return TRUE;
  }
338 339 340 341 342 343 344 345
  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
346 347 348 349 350 351 352 353 354
  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;
  }
355

Bruno Coudoin's avatar
Bruno Coudoin committed
356 357 358
  switch (event->keyval)
    {
    case GDK_Escape:
359
      gc_close_all_dialog();
360

361
      if (gc_board_get_current()->previous_board != NULL)
362
	gc_board_stop();
Bruno Coudoin's avatar
Bruno Coudoin committed
363
      return TRUE;
364
    case GDK_F5:
365
      g_message("Refreshing the canvas\n");
366
      goo_canvas_update(GOO_CANVAS(canvas));
367
      return TRUE;
368

369 370 371 372 373 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
    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;
411
    default:
412 413 414 415
      break;
    }

  /* pass through the IM context */
416
  if (gc_board_get_current() && (!gc_board_get_current()->disable_im_context))
417 418
    {
      if (gtk_im_context_filter_keypress (properties->context, event))
Bruno Coudoin's avatar
Bruno Coudoin committed
419
	{
420
	  g_message("%d key is handled by context", kv);
421
	  return TRUE;
Bruno Coudoin's avatar
Bruno Coudoin committed
422 423 424
	}
    }

425
  g_message("%d key is NOT handled by context", kv);
426 427 428 429
  /* 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
   */
430
  if (gc_board_get_current_board_plugin()!=NULL
Bruno Coudoin's avatar
Bruno Coudoin committed
431
      && gc_board_get_current_board_plugin()->key_press)
432
    {
433
      return(gc_board_get_current_board_plugin()->key_press (event->keyval, NULL, NULL));
434
    }
435
  else if (gc_board_get_current_board_plugin()!=NULL
Bruno Coudoin's avatar
Bruno Coudoin committed
436
	   && gc_board_get_current_board_plugin()->ok &&
437 438 439
	   (event->keyval == GDK_KP_Enter ||
	    event->keyval == GDK_Return   ||
	    event->keyval == GDK_KP_Space))
440 441
    {
      /* Else we send the OK signal. */
442
      gc_board_get_current_board_plugin()->ok ();
443 444 445
      return TRUE;
    }

446
  /* Event not handled; try parent item */
Bruno Coudoin's avatar
Bruno Coudoin committed
447 448 449
  return FALSE;
};

450 451 452 453 454
guint gc_cursor_get()
{
  return gc_cursor_current;
}

455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
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 :
473
      cursor_pixbuf = gc_skin_pixmap_load("cursors/default.png");
474 475
      break;
    case GCOMPRIS_LINE_CURSOR :
476
      cursor_pixbuf = gc_skin_pixmap_load("cursors/line.png");
477 478
      break;
    case GCOMPRIS_RECT_CURSOR :
479
      cursor_pixbuf = gc_skin_pixmap_load("cursors/rect.png");
480 481
      break;
    case GCOMPRIS_FILLRECT_CURSOR :
482
      cursor_pixbuf = gc_skin_pixmap_load("cursors/fillrect.png");
483 484
      break;
    case GCOMPRIS_CIRCLE_CURSOR :
485
      cursor_pixbuf = gc_skin_pixmap_load("cursors/circle.png");
486 487
      break;
    case GCOMPRIS_FILLCIRCLE_CURSOR :
488
      cursor_pixbuf = gc_skin_pixmap_load("cursors/fillcircle.png");
489 490
      break;
    case GCOMPRIS_FILL_CURSOR :
491
      cursor_pixbuf = gc_skin_pixmap_load("cursors/fill.png");
492 493
      break;
    case GCOMPRIS_DEL_CURSOR :
494
      cursor_pixbuf = gc_skin_pixmap_load("cursors/del.png");
495 496
      break;
    case GCOMPRIS_SELECT_CURSOR :
497
      cursor_pixbuf = gc_skin_pixmap_load("cursors/select.png");
498 499 500 501 502 503 504 505
      break;
    default :
      return;
      break;
    }

    if(cursor_pixbuf)
      {
506 507
	cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
					    cursor_pixbuf, 0, 0);
508 509 510 511 512
	gdk_window_set_cursor(window->window, cursor);
	gdk_cursor_unref(cursor);
	gdk_pixbuf_unref(cursor_pixbuf);
      }
  }
513
  gc_cursor_current = gdk_cursor_type;
514 515
}

Bruno Coudoin's avatar
Bruno Coudoin committed
516 517 518
/**
 * Return the main canvas we run in
 */
519
GooCanvas *gc_get_canvas()
Bruno Coudoin's avatar
Bruno Coudoin committed
520
{
521
  return GOO_CANVAS (canvas);
Bruno Coudoin's avatar
Bruno Coudoin committed
522 523
}

524
GtkWidget *gc_get_window()
525 526 527 528
{
  return window;
}

Bruno Coudoin's avatar
Bruno Coudoin committed
529
static void
530
_set_svg_background(GooCanvasItem *parent, gchar *file, gchar *id)
Bruno Coudoin's avatar
Bruno Coudoin committed
531
{
Bruno Coudoin's avatar
Bruno Coudoin committed
532
  RsvgHandle *rsvg_handle;
Bruno Coudoin's avatar
Bruno Coudoin committed
533

534
  rsvg_handle = gc_rsvg_load (file);
Bruno Coudoin's avatar
Bruno Coudoin committed
535 536 537

  if(backgroundsvgimg)
    g_object_set(backgroundsvgimg,
538
		 "svg-handle", rsvg_handle,
539
		 "svg-id", id,
Bruno Coudoin's avatar
Bruno Coudoin committed
540 541
		 NULL);
  else
542
    backgroundsvgimg = goo_canvas_svg_new (parent,
Bruno Coudoin's avatar
Bruno Coudoin committed
543 544 545 546 547 548 549 550 551 552 553 554
					 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;

555
  background_pixmap = gc_pixmap_load (file);
Bruno Coudoin's avatar
Bruno Coudoin committed
556 557

  if(backgroundimg)
558 559 560
    g_object_set(backgroundimg,
		 "pixbuf", background_pixmap,
		 NULL);
561
  else
562 563 564 565 566 567 568 569
    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
570 571 572

  gdk_pixbuf_unref(background_pixmap);

Bruno Coudoin's avatar
Bruno Coudoin committed
573 574
}

575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
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
591 592 593 594 595 596 597 598 599 600 601
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);
602 603

      backgroundimg = NULL;
604
      _set_svg_background(parent, file, NULL);
Bruno Coudoin's avatar
Bruno Coudoin committed
605 606 607
    }
  else
    {
608
      _clear_svg_background();
Bruno Coudoin's avatar
Bruno Coudoin committed
609 610
      _set_pixmap_background(parent, file);
    }
Bruno Coudoin's avatar
Bruno Coudoin committed
611 612
}

613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
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);
}

636 637 638 639 640 641 642 643
void
gc_set_default_background(GooCanvasItem *parent)
{
  gc_set_background_by_id(parent,
			  gc_skin_rsvg_get(),
			  "#BACKGROUND");
}

644 645 646
/*
 * Sugar requires properties to be set before the windows is realized
 */
647
#ifdef WIN32
648
#elif MAC_INTEGRATION
649
#else
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
static gboolean
_realize_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
  Window xwindow = GDK_WINDOW_XWINDOW(window->window);

  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));

  return FALSE;
}
673
#endif
674

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

681 682 683 684
  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);
685

686 687 688 689
  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);
690

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

#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

709
}
Bruno Coudoin's avatar
Bruno Coudoin committed
710

711 712 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
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;
}

758 759
static void setup_window ()
{
760
  GcomprisBoard *board_to_start;
761 762

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Bruno Coudoin's avatar
Bruno Coudoin committed
763

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

787
  }
788

789
  gtk_window_set_title(GTK_WINDOW (window), "GCompris");
790

791
  GdkGeometry hints;
792 793 794 795
  hints.base_width = 615;
  hints.base_height = 400;
  hints.min_width = hints.base_width;
  hints.min_height = hints.base_height;
796 797
  hints.width_inc = 1;
  hints.height_inc = 1;
798
  hints.min_aspect = (float)BOARDWIDTH/BOARDHEIGHT;
799
  hints.max_aspect = (float)BOARDWIDTH/BOARDHEIGHT;
800 801 802 803 804
  gint geom_mask = GDK_HINT_RESIZE_INC |
                   GDK_HINT_MIN_SIZE |
                   GDK_HINT_BASE_SIZE;
  if (!popt_sugar_look)
      geom_mask |= GDK_HINT_ASPECT;
805
  gtk_window_set_geometry_hints (GTK_WINDOW (window), NULL, &hints, geom_mask);
806

807 808 809 810
  /*
   * Set the main window
   * -------------------
   */
811

812
  gtk_window_set_default_size(GTK_WINDOW(window), BOARDWIDTH, BOARDHEIGHT);
813
  gtk_window_set_wmclass(GTK_WINDOW(window), "gcompris", "GCompris");
814
#ifdef WIN32
815
#elif MAC_INTEGRATION
816
#else
817 818
  g_signal_connect (GTK_OBJECT (window), "realize",
		    G_CALLBACK (_realize_callback), NULL);
819
#endif
Bruno Coudoin's avatar
Bruno Coudoin committed
820
  gtk_widget_realize (window);
Bruno Coudoin's avatar
Bruno Coudoin committed
821

Bruno Coudoin's avatar
Bruno Coudoin committed
822 823 824
  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
		      GTK_SIGNAL_FUNC (quit_cb), NULL);

825 826
  gtk_signal_connect (GTK_OBJECT (window), "map_event",
		      GTK_SIGNAL_FUNC (map_cb), NULL);
Bruno Coudoin's avatar
Bruno Coudoin committed
827

828
  // Set the cursor
829
  gc_cursor_set(GCOMPRIS_DEFAULT_CURSOR);
830

831
  canvas     = goo_canvas_new();
Bruno Coudoin's avatar
Bruno Coudoin committed
832

833 834 835 836
  g_object_set (canvas,
		"has-tooltip", TRUE,
		NULL);

837 838 839 840
  g_object_set (G_OBJECT(goo_canvas_get_root_item(GOO_CANVAS(canvas))),
		"can-focus", TRUE,
		NULL);

Bruno Coudoin's avatar
Bruno Coudoin committed
841

842 843
  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
844 845 846 847
  g_signal_connect_after (canvas,
			  "key_press_event",
			  GTK_SIGNAL_FUNC (board_widget_key_press_callback), 0);

848
  gc_im_init(window);
849

850
  gc_board_init();
851

852
  /* Load all the menu once */
853
  gc_menu_load();
854

855
  /* Save the root_menu */
856
  properties->menu_board = gc_menu_section_get(properties->root_menu);
857

858 859 860 861
  init_workspace();

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

863 864
  /* Run the bar */
  gc_bar_start(GTK_CONTAINER(workspace), GOO_CANVAS(canvas));
865

866 867
  board_to_start = get_board_to_start();

868
  if(!board_to_start) {
869 870 871
    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);
872
  } else if(!gc_board_check_file(board_to_start)) {
873 874 875
    gchar *tmpstr= g_strdup_printf("Couldn't find the board menu, or plugin execution error");
    gc_dialog(tmpstr, NULL);
    g_free(tmpstr);
876
  } else {
877
    g_message("Fine, we got the gcomprisBoardMenu, xml boards parsing went fine");
878 879
    if(!display_activation_dialog())
      gc_board_play(board_to_start);
880
  }
881

882 883 884

}

885
#ifdef STATIC_MODULE
886 887
/** Display the activation dialog for the windows version
 *
888
 * return TRUE is the dialog is display, FALSE instead.
889
 */
890
int
891 892
display_activation_dialog()
{
893
  int board_count = 0;
894
  int gc_board_number_in_demo = 0;
895
  GList *list;
896
  gint  key_is_valid = 0;
897

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

Bruno Coudoin's avatar
Bruno Coudoin committed
900
  if(key_is_valid == 1)
901
    return FALSE;
902 903 904 905 906 907
  else if(key_is_valid == 2)
    {
      g_free ( gc_prop_get()->key );
      gc_prop_get()->key = strdup("");
      gc_prop_save(properties);
    }
908 909 910 911 912
  /* 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 &&
913 914 915 916 917 918 919
	  strncmp(board->section, "/experimental", 13) != 0)
	{
	  board_count++;
	  gc_board_check_file(board);
	  if(board->plugin)
	      gc_board_number_in_demo++;
	}
920 921
    }

922
  /* Entry area */
923 924
  widget_activation_entry = gtk_entry_new();
  gtk_entry_set_max_length(GTK_ENTRY(widget_activation_entry), 6);
925
  activation_item = \
926 927 928
    goo_canvas_widget_new (goo_canvas_get_root_item(GOO_CANVAS(canvas)),
			   GTK_WIDGET(widget_activation_entry),
			   BOARDWIDTH / 2 - 50,
929
			   BOARDHEIGHT - 90,
930 931
			   100.0,
			   30.0,
932 933 934 935 936
			   NULL);
  gtk_signal_connect(GTK_OBJECT(widget_activation_entry), "activate",
		     GTK_SIGNAL_FUNC(activation_enter_callback),
		     NULL);

937 938 939 940 941 942 943 944 945 946
  char *msg = g_strdup_printf( \
      _("GCompris is free software released under the GPL License. "
	"In order to support its development, the Windows version "
	"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);
947 948
  gc_dialog(msg, activation_done);
  g_free(msg);
949

950 951 952
  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));
953
  return TRUE;
Bruno Coudoin's avatar
Bruno Coudoin committed
954 955
}

956 957 958 959
/**
 * 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
960
 *        2  for the demo code
961
 */
962
gint gc_activation_check(const char *code)
963
{
Bruno Coudoin's avatar
Bruno Coudoin committed
964
#ifdef  DISABLE_ACTIVATION_CODE
Bruno Coudoin's avatar
Bruno Coudoin committed
965
  return 1;
Bruno Coudoin's avatar
Bruno Coudoin committed
966
#else
967 968 969 970
  int value = 0;
  int i;
  char crc1 = 0;
  char crc2 = 0;
971
  char codeddate[5];
972

973 974 975
  if (properties->administration)
    return 1;

976 977 978
  if(strlen(code) != 6)
    return -1;

979 980 981 982 983 984 985
  // A special code to test the full version without
  // saving the activation
  if (strncmp(code, "123321", 6) == 0)
    {
      return 2;
    }

986 987 988 989
  for(i=3; i>=0; i--)
    {
      value |= code[i] & 0x07;
      value = value << 3;
Bruno Coudoin's avatar
Bruno Coudoin committed
990
      crc1 = (crc1 ^ code[i]) & 0x07;
991 992 993 994
    }
  value = value >> 3;
  crc1 = 0x30 | crc1;
  crc2 = 0x30 | (code[2] ^ code[3]);
995

Bruno Coudoin's avatar
Bruno Coudoin committed
996 997 998 999 1000
  if(crc1 != code[4])
    return(-1);

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

Bruno Coudoin's avatar
Bruno Coudoin committed
1002
  codeddate[3] = 0x30 | (value & 0x000F);
1003
  value = value >> 4;
1004

Bruno Coudoin's avatar
Bruno Coudoin committed
1005
  codeddate[2] = 0x30 | (value & 0x0001);
1006
  value = value >> 1;
1007

Bruno Coudoin's avatar
Bruno Coudoin committed
1008
  codeddate[1] = 0x30 | (value & 0x000F);
1009
  value = value >> 4;
1010

Bruno Coudoin's avatar
Bruno Coudoin committed
1011
  codeddate[0] = 0x30 | (value & 0x0003);
1012 1013 1014 1015 1016 1017
  codeddate[4] = '\0';

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

1021 1022 1023 1024
/* Check the activation code
 *
 */
static void
1025 1026
activation_enter_callback( GtkWidget *entry,
			   GtkWidget *notused )
1027
{
1028 1029 1030
  const char *code = gtk_entry_get_text(GTK_ENTRY(entry));

  switch(gc_activation_check(code))
1031
    {
1032
    case 1:
1033
    case 2:
Bruno Coudoin's avatar
Bruno Coudoin committed
1034 1035
      gc_prop_get()->key = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
      gc_prop_save(properties);
1036 1037 1038 1039 1040 1041 1042 1043
      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;
1044 1045 1046 1047 1048 1049 1050 1051 1052
    }
}

/* Callback for the activation dialog
 *
 */
static void
activation_done()
{
1053 1054 1055 1056
  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))
    {
1057
      activation_enter_callback(GTK_WIDGET(widget_activation_entry), NULL);
1058
    }
1059

1060
  gc_board_play( get_board_to_start());
1061
  goo_canvas_item_remove (activation_item);
1062 1063 1064 1065 1066 1067
}
#endif

/** Call me to end an activity
 *
 */
1068
void gc_board_end()
Bruno Coudoin's avatar
Bruno Coudoin committed
1069
{
1070
  if (gc_board_get_current()->previous_board) {
1071
    /* Run the previous board */
1072
    gc_board_play(gc_board_get_current()->previous_board);
1073
  }
Bruno Coudoin's avatar
Bruno Coudoin committed
1074 1075
}

1076 1077 1078 1079
/** \brief toggle full screen mode
 *
 *
 */
1080
void gc_fullscreen_set(gboolean state)
1081
{
1082 1083 1084 1085 1086
  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
1087
  fullscreen = state;
1088 1089
  if(state)
    {
1090 1091
      gtk_window_get_position ( (GtkWindow*)( window ), &window_x, &window_y );
      gtk_window_get_size ( GTK_WINDOW ( window ), &window_w, &window_h );
1092
#ifdef WIN32
1093 1094 1095
      // WARNING: Doing this is required on Windows
      //          but keep the window hidden on GNU/Linux
      gtk_widget_hide ( window );
1096 1097
#elif MAC_INTEGRATION
      // WARNING: Doing this is required on MacOSX
1098
      //          but keep the window hidden on GNU/Linux
1099
      gtk_widget_hide ( window );
1100 1101
#else
#endif
1102 1103 1104
      gtk_window_set_decorated ( GTK_WINDOW ( window ), FALSE );
      gtk_window_set_type_hint ( GTK_WINDOW ( window ),
				 GDK_WINDOW_TYPE_HINT_DESKTOP );
1105
      if (popt_sugar_look)
1106
	gtk_window_maximize ( GTK_WINDOW( window ) );
1107
      else
1108 1109 1110 1111 1112 1113 1114 1115
        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) );
1116 1117
    }
  else
1118
    {
1119 1120 1121 1122 1123 1124 1125
      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 );
1126
    }
1127
  gtk_window_present ( GTK_WINDOW ( window ) );
1128 1129 1130

}

1131
/* Use these instead of the goo_canvas ones for proper fullscreen mousegrab
1132
   handling. */
1133 1134
int gc_canvas_item_grab (GooCanvasItem *item, unsigned int event_mask,
			 GdkCursor *cursor, guint32 etime)
1135 1136
{
  int retval;
1137

1138 1139
  retval = goo_canvas_pointer_grab(goo_canvas_item_get_canvas(item), item,
				   event_mask, cursor, etime);
1140 1141
  if (retval != GDK_GRAB_SUCCESS)
    return retval;
1142

1143 1144 1145
  return retval;
}

1146
void gc_canvas_item_ungrab (GooCanvasItem *item, guint32 etime)
1147
{
1148
  goo_canvas_pointer_ungrab(goo_canvas_item_get_canvas(item), item, etime);
1149 1150
}

1151
static void cleanup()
Bruno Coudoin's avatar
Bruno Coudoin committed
1152
{
1153 1154 1155 1156
  /* Do not loopback in exit */
  signal(SIGINT,  NULL);
  signal(SIGSEGV, NULL);

1157
  single_instance_release(); /* Must be done before property destroy */
1158
  gc_board_stop();
1159
  gc_db_exit();
1160
  gc_fullscreen_set(FALSE);
1161
  gc_menu_destroy();
1162 1163
  gc_net_destroy();
  gc_cache_destroy();
1164
  gc_prop_destroy(gc_prop_get());
1165
}
1166

1167
void gc_exit()
1168 1169
{
  g_signal_emit_by_name(G_OBJECT(window), "delete_event");
1170
}
Bruno Coudoin's avatar
Bruno Coudoin committed
1171

1172 1173
static void quit_cb (GtkWidget *widget, gpointer data)
{
1174 1175 1176 1177

#ifdef DMALLOC
  dmalloc_shutdown();
#endif
1178 1179
  cleanup();
  gtk_main_quit();
1180

1181 1182 1183 1184 1185
  /*
   * 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
1186 1187
}

1188 1189 1190 1191 1192 1193 1194 1195
/*
 * We want GCompris to be set as fullscreen the later possible
 *
 */
static void map_cb (GtkWidget *widget, gpointer data)
{
  if(is_mapped == FALSE)
    {
1196
      gc_fullscreen_set(properties->fullscreen);
Bruno Coudoin's avatar
Bruno Coudoin committed
1197
      is_mapped = TRUE;
1198
    }
1199
  g_message("gcompris window is now mapped");
1200 1201
}

1202
/*
1203
 * Process the cleanup of the child (no zombies)
1204 1205
 * ---------------------------------------------
 */
1206
void gc_terminate(int signum)
1207 1208
{

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

1211
  gc_exit();
1212

1213 1214
}

Bruno Coudoin's avatar
Bruno Coudoin committed
1215 1216
static void load_properties ()
{
1217
  GError *error = NULL;
1218
  properties = gc_prop_new ();