Back to index

gcompris  8.2.2
gcompris.c
Go to the documentation of this file.
00001 /* gcompris - gcompris.c
00002  *
00003  * Copyright (C) 2000-2003 Bruno Coudoin
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018  */
00019 
00020 #include <signal.h>
00021 #include <popt.h>
00022 
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <unistd.h>
00026 #include <time.h>
00027 #include <string.h>
00028 
00029 #include "gcompris.h"
00030 #include "gc_core.h"
00031 #include "gcompris_config.h"
00032 #include "about.h"
00033 #include <locale.h>
00034 
00035 #include "cursor.h"
00036 
00037 #include "binreloc.h"
00038 
00039 /* For XF86_VIDMODE Support */
00040 #ifdef XF86_VIDMODE
00041 #include <gdk/gdkx.h>
00042 #include <X11/Xlib.h>
00043 #include <X11/Xutil.h>
00044 #include <X11/extensions/xf86vmode.h>
00045 #endif
00046 
00047 static GtkWidget *window;
00048 static GnomeCanvas *canvas;
00049 static GnomeCanvas *canvas_bar;
00050 static GnomeCanvas *canvas_bg;
00051 
00052 //static gint pause_board_cb (GtkWidget *widget, gpointer data);
00053 static void quit_cb (GtkWidget *widget, gpointer data);
00054 static void map_cb  (GtkWidget *widget, gpointer data);
00055 static gint board_widget_key_press_callback (GtkWidget   *widget,
00056                                        GdkEventKey *event,
00057                                        gpointer     client_data);
00058 void gc_terminate(int signum);
00059 
00060 /*
00061  * For the Activation dialog
00062  */
00063 #ifdef WIN32
00064 int gc_activation_check(char *code);
00065 static void activation_enter_callback(GtkWidget *widget,
00066                                   GtkWidget *entry );
00067 static void activation_done();
00068 static void display_activation_dialog();
00069 static GnomeCanvasItem *activation_item;
00070 static GtkEntry *widget_activation_entry;
00071 #else
00072 #define display_activation_dialog()
00073 #endif
00074 
00075 
00076 static GcomprisProperties *properties = NULL;
00077 static gboolean                antialiased = FALSE;
00078 static gboolean                is_mapped = FALSE;
00079 
00080 /****************************************************************************/
00081 /* Some constants.  */
00082 
00083 static GnomeCanvasItem *backgroundimg = NULL;
00084 static gchar           *gc_locale = NULL;
00085 static gchar           *gc_user_default_locale = NULL;
00086 static gboolean             gc_debug = FALSE;
00087 
00088 /****************************************************************************/
00089 /* Command line params */
00090 
00091 /*** gcompris-popttable */
00092 static int popt_fullscreen     = FALSE;
00093 static int popt_window                = FALSE;
00094 static int popt_sound                 = FALSE;
00095 static int popt_mute           = FALSE;
00096 static int popt_cursor                = FALSE;
00097 static int popt_version               = FALSE;
00098 static int popt_aalias                = FALSE;
00099 static int popt_difficulty_filter  = FALSE;
00100 static int popt_debug                 = FALSE;
00101 static int popt_noxf86vm       = FALSE;
00102 static char *popt_root_menu        = NULL;
00103 static char *popt_local_activity   = NULL;
00104 static int popt_administration        = FALSE;
00105 static char *popt_database         = NULL;
00106 static char *popt_logs_database    = NULL;
00107 static int popt_create_db             = FALSE;
00108 static int popt_reread_menu           = FALSE;
00109 static char *popt_profile      = NULL;
00110 static int *popt_profile_list         = FALSE;
00111 static char *popt_shared_dir          = NULL;
00112 static char *popt_users_dir    = NULL;
00113 static int  popt_experimental      = FALSE;
00114 static int  popt_no_quit       = FALSE;
00115 static int  popt_no_config         = FALSE;
00116 static int  popt_display_resource  = FALSE;
00117 static char *popt_server            = NULL;
00118 static int  *popt_web_only          = NULL;
00119 static char *popt_cache_dir         = NULL;
00120 
00121 static struct poptOption options[] = {
00122   {"fullscreen", 'f', POPT_ARG_NONE, &popt_fullscreen, 0,
00123    N_("run gcompris in fullscreen mode."), NULL},
00124 
00125   {"window", 'w', POPT_ARG_NONE, &popt_window, 0,
00126    N_("run gcompris in window mode."), NULL},
00127 
00128   {"sound", 's', POPT_ARG_NONE, &popt_sound, 0,
00129    N_("run gcompris with sound enabled."), NULL},
00130 
00131   {"mute", 'm', POPT_ARG_NONE, &popt_mute, 0,
00132    N_("run gcompris without sound."), NULL},
00133 
00134   {"cursor", 'c', POPT_ARG_NONE, &popt_cursor, 0,
00135    N_("run gcompris with the default gnome cursor."), NULL},
00136 
00137   {"difficulty", 'd', POPT_ARG_INT, &popt_difficulty_filter, 0,
00138    N_("display only activities with this difficulty level."), NULL},
00139 
00140   {"debug", 'D', POPT_ARG_NONE, &popt_debug, 0,
00141    N_("display debug informations on the console."), NULL},
00142 
00143   {"version", 'v', POPT_ARG_NONE, &popt_version, 0,
00144    N_("Print the version of " PACKAGE), NULL},
00145 
00146   {"antialiased", '\0', POPT_ARG_NONE, &popt_aalias, 0,
00147    N_("Use the antialiased canvas (slower)."), NULL},
00148 
00149   {"noxf86vm", 'x', POPT_ARG_NONE, &popt_noxf86vm, 0,
00150    N_("Disable XF86VidMode (No screen resolution change)."), NULL},
00151 
00152   {"root-menu", 'l', POPT_ARG_STRING, &popt_root_menu, 0,
00153    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)"), NULL},
00154 
00155   {"local-activity", 'L', POPT_ARG_STRING, &popt_local_activity, 0,
00156    N_("Run GCompris with local activity directory added to menu"), NULL},
00157 
00158   {"administration", 'a', POPT_ARG_NONE, &popt_administration, 0,
00159    N_("Run GCompris in administration and user-management mode"), NULL},
00160 
00161   {"database", 'b', POPT_ARG_STRING, &popt_database, 0,
00162    N_("Use alternate database for profiles"), NULL},
00163 
00164   {"logs", 'j', POPT_ARG_STRING, &popt_logs_database, 0,
00165    N_("Use alternate database for logs"), NULL},
00166 
00167   {"create-db",'\0', POPT_ARG_NONE, &popt_create_db, 0,
00168    N_("Create the alternate database for profiles"), NULL},
00169 
00170   {"reread-menu",'\0', POPT_ARG_NONE, &popt_reread_menu, 0,
00171    N_("Re-read XML Menus and store them in the database"), NULL},
00172 
00173   {"profile",'p', POPT_ARG_STRING, &popt_profile, 0,
00174    N_("Set the profile to use. Use 'gcompris -a' to create profiles"), NULL},
00175 
00176   {"profile-list",'\0', POPT_ARG_NONE, &popt_profile_list, 0,
00177    N_("List all available profiles. Use 'gcompris -a' to create profiles"), NULL},
00178 
00179   {"shared-dir",'\0', POPT_ARG_STRING, &popt_shared_dir, 0,
00180    N_("Shared directory location, for profiles and board-configuration data: [$HOME/.gcompris/shared]"), NULL},
00181 
00182   {"users-dir",'\0', POPT_ARG_STRING, &popt_users_dir, 0,
00183    N_("The location of user directories: [$HOME/.gcompris/users]"), NULL},
00184 
00185   {"experimental",'\0', POPT_ARG_NONE, &popt_experimental, 0,
00186    N_("Run the experimental activities"), NULL},
00187 
00188   {"disable-quit",'\0', POPT_ARG_NONE, &popt_no_quit, 0,
00189    N_("Disable the quit button"), NULL},
00190 
00191   {"disable-config",'\0', POPT_ARG_NONE, &popt_no_config, 0,
00192    N_("Disable the config button"), NULL},
00193 
00194   {"display-resource",'\0', POPT_ARG_NONE, &popt_display_resource, 0,
00195    N_("Display the resources on stdout based on the selected activities"), NULL},
00196 
00197   {"server", '\0', POPT_ARG_STRING, &popt_server, 0,
00198    N_("GCompris will get images, sounds and activity data from this server if not found locally."), NULL},
00199 
00200   {"web-only", '\0', POPT_ARG_NONE, &popt_web_only, 0,
00201    N_("Only when --server is provided, disable check for local resource first."
00202       " Data are always taken from the web server."), NULL},
00203 
00204   {"cache-dir", '\0', POPT_ARG_STRING, &popt_cache_dir, 0,
00205    N_("In server mode, specify the cache directory used to avoid useless downloads."), NULL},
00206 
00207 #ifndef WIN32 /* Not supported on windows */
00208   POPT_AUTOHELP
00209 #endif
00210   {
00211     NULL,
00212     '\0',
00213     0,
00214     NULL,
00215     0,
00216     NULL,
00217     NULL
00218   }
00219 };
00220 
00221 /* Fullscreen Stuff */
00222 #ifdef XF86_VIDMODE
00223 static struct
00224 {
00225   XF86VidModeModeInfo fs_mode;
00226   XF86VidModeModeInfo orig_mode;
00227   int orig_viewport_x;
00228   int orig_viewport_y;
00229   int window_x;
00230   int window_y;
00231   gboolean fullscreen_active;
00232   int ignore_focus_out;
00233 } XF86VidModeData = { { 0 }, { 0 }, 0, 0, 0, 0, FALSE, 0 };
00234 
00235 static void xf86_vidmode_init( void );
00236 static void xf86_vidmode_set_fullscreen( int state );
00237 static gint xf86_window_configured(GtkWindow *window,
00238   GdkEventConfigure *event, gpointer param);
00239 static gint xf86_focus_changed(GtkWindow *window,
00240   GdkEventFocus *event, gpointer param);
00241 #endif
00242 
00243 /****************************************************************************/
00244 
00245 /* Remove any dialog box */
00246 static void gc_close_all_dialog() {
00247   gc_dialog_close();
00248   gc_help_stop();
00249   gc_config_stop();
00250   gc_about_stop();
00251   gc_selector_file_stop();
00252   gc_selector_images_stop();
00253 }
00254 
00255 static gint
00256 board_widget_key_press_callback (GtkWidget   *widget,
00257                              GdkEventKey *event,
00258                              gpointer     client_data)
00259 {
00260   int kv = event->keyval;
00261 
00262   if(event->state & GDK_CONTROL_MASK && ((event->keyval == GDK_r)
00263                                     || (event->keyval == GDK_R))) {
00264     g_message("Refreshing the canvas\n");
00265     gnome_canvas_update_now(canvas);
00266     return TRUE;
00267   }
00268 
00269   if(event->state & GDK_CONTROL_MASK && ((event->keyval == GDK_q)
00270                                     || (event->keyval == GDK_Q))) {
00271     gc_exit();
00272     return TRUE;
00273   }
00274 
00275   switch (event->keyval)
00276     {
00277     case GDK_Escape:
00278       gc_close_all_dialog();
00279 
00280       if (gc_board_get_current()->previous_board != NULL)
00281        gc_board_stop();
00282       return TRUE;
00283     case GDK_F5:
00284       g_message("Refreshing the canvas\n");
00285       gnome_canvas_update_now(canvas);
00286       return TRUE;
00287 
00288     case GDK_KP_Multiply:
00289       break;
00290     case GDK_KP_0:
00291     case GDK_KP_Insert:
00292       event->keyval=GDK_0;
00293       break;
00294     case GDK_KP_1:
00295     case GDK_KP_End:
00296       event->keyval=GDK_1;
00297       break;
00298     case GDK_KP_2:
00299     case GDK_KP_Down:
00300       event->keyval=GDK_2;
00301       break;
00302     case GDK_KP_3:
00303     case GDK_KP_Page_Down:
00304       event->keyval=GDK_3;
00305       break;
00306     case GDK_KP_4:
00307     case GDK_KP_Left:
00308       event->keyval=GDK_4;
00309       break;
00310     case GDK_KP_5:
00311     case GDK_KP_Begin:
00312       event->keyval=GDK_5;
00313       break;
00314     case GDK_KP_6:
00315     case GDK_KP_Right:
00316       event->keyval=GDK_6;
00317       break;
00318     case GDK_KP_7:
00319     case GDK_KP_Home:
00320       event->keyval=GDK_7;
00321       break;
00322     case GDK_KP_8:
00323     case GDK_KP_Up:
00324       event->keyval=GDK_8;
00325       break;
00326     case GDK_KP_9:
00327     case GDK_KP_Page_Up:
00328       event->keyval=GDK_9;
00329       break;
00330     default:
00331       break;
00332     }
00333 
00334   /* pass through the IM context */
00335   if (gc_board_get_current() && (!gc_board_get_current()->disable_im_context))
00336     {
00337       if (gtk_im_context_filter_keypress (properties->context, event))
00338        {
00339          g_warning("%d key is handled by context", kv);
00340          return TRUE;
00341        }
00342     }
00343 
00344   g_warning("%d key is NOT handled by context", kv);
00345   /* If the board needs to receive key pressed */
00346   /* NOTE: If a board receives key press, it must bind the ENTER Keys to OK
00347    *       whenever possible
00348    */
00349   if (gc_board_get_current_board_plugin()!=NULL && gc_board_get_current_board_plugin()->key_press)
00350     {
00351       return(gc_board_get_current_board_plugin()->key_press (event->keyval, NULL, NULL));
00352     }
00353   else if (gc_board_get_current_board_plugin()!=NULL && gc_board_get_current_board_plugin()->ok &&
00354           (event->keyval == GDK_KP_Enter ||
00355            event->keyval == GDK_Return   ||
00356            event->keyval == GDK_KP_Space))
00357     {
00358       /* Else we send the OK signal. */
00359       gc_board_get_current_board_plugin()->ok ();
00360       return TRUE;
00361     }
00362 
00363   /* Event not handled; try parent item */
00364   return FALSE;
00365 };
00366 
00370 GnomeCanvas *gc_get_canvas()
00371 {
00372   return canvas;
00373 }
00374 
00375 GtkWidget *gc_get_window()
00376 {
00377   return window;
00378 }
00379 
00380 void gc_ignore_next_focus_out()
00381 {
00382 #ifdef XF86_VIDMODE
00383   XF86VidModeData.ignore_focus_out++;
00384 #endif
00385 }
00386 
00387 GnomeCanvasItem *gc_set_background(GnomeCanvasGroup *parent, gchar *file)
00388 {
00389   GdkPixbuf *background_pixmap = NULL;
00390 
00391   background_pixmap = gc_pixmap_load (file);
00392 
00393   if(backgroundimg)
00394       gnome_canvas_item_set (backgroundimg,
00395                           "pixbuf", background_pixmap,
00396                           NULL);
00397   else
00398     backgroundimg=gnome_canvas_item_new (parent,
00399                                     gnome_canvas_pixbuf_get_type (),
00400                                     "pixbuf", background_pixmap,
00401                                     "x", 0.0,
00402                                     "y", 0.0,
00403                                     "width", (double) BOARDWIDTH,
00404                                     "height", (double) BOARDHEIGHT,
00405                                     NULL);
00406   gnome_canvas_item_lower_to_bottom(backgroundimg);
00407 
00408   gdk_pixbuf_unref(background_pixmap);
00409 
00410   return (backgroundimg);
00411 }
00412 
00413 static void init_background()
00414 {
00415   double xratio, yratio, max;
00416   gint screen_height, screen_width;
00417   GtkWidget *vbox;
00418 
00419 #ifdef XF86_VIDMODE
00420   xf86_vidmode_init();
00421 
00422   if(properties->fullscreen && !properties->noxf86vm) {
00423     screen_height = XF86VidModeData.fs_mode.vdisplay;
00424     screen_width  = XF86VidModeData.fs_mode.hdisplay;
00425   }
00426   else
00427 #endif
00428   {
00429     screen_height = gdk_screen_height();
00430     screen_width  = gdk_screen_width();
00431   }
00432 
00433   yratio=screen_height/(float)(BOARDHEIGHT+BARHEIGHT);
00434   xratio=screen_width/(float)BOARDWIDTH;
00435   g_message("The screen_width=%f screen_height=%f\n",
00436            (double)screen_width, (double)screen_height);
00437   g_message("The xratio=%f yratio=%f\n", xratio, yratio);
00438 
00439   yratio=xratio=MIN(xratio, yratio);
00440 
00441   /* Depending on user preference, set the max ratio */
00442   switch(properties->screensize)
00443     {
00444     case 0: max = 0.8;
00445       break;
00446     case 1: max = 1;
00447       break;
00448     case 2: max = 1.28;
00449       break;
00450     default: max = 1;
00451       break;
00452     }
00453   xratio=MIN(max, xratio);
00454 
00455   g_message("Calculated x ratio xratio=%f\n", xratio);
00456 
00457 
00458   /* Background area if ratio above 1 */
00459   if(properties->fullscreen)
00460     {
00461 
00462       /* WARNING : I add 30 here for windows. don't know why it's needed. Doesn't hurt the Linux version */
00463       gnome_canvas_set_scroll_region (canvas_bg,
00464                                   0, 0,
00465                                   screen_width,
00466                                   screen_height + 30);
00467 
00468       gtk_widget_set_usize (GTK_WIDGET(canvas_bg), screen_width, screen_height);
00469 
00470       /* Create a black box for the background */
00471       gnome_canvas_item_new (gnome_canvas_root(canvas_bg),
00472                           gnome_canvas_rect_get_type (),
00473                           "x1", (double) 0,
00474                           "y1", (double) 0,
00475                           "x2", (double) screen_width,
00476                           "y2", (double) screen_height + 30,
00477                           "fill_color", "black",
00478                           "outline_color", "black",
00479                           "width_units", (double)0,
00480                           NULL);
00481 
00482     }
00483 
00484   /* Create a vertical box in which I put first the play board area, then the button bar */
00485   vbox = gtk_vbox_new (FALSE, 0);
00486   if(!properties->fullscreen)
00487     gtk_container_add (GTK_CONTAINER(window), GTK_WIDGET(vbox));
00488 
00489   gtk_widget_show (GTK_WIDGET(vbox));
00490   gtk_widget_show (GTK_WIDGET(canvas));
00491   gtk_widget_show (GTK_WIDGET(canvas_bar));
00492 
00493   gtk_box_pack_start (GTK_BOX(vbox), GTK_WIDGET(canvas), TRUE, TRUE, 0);
00494   gtk_box_pack_start (GTK_BOX(vbox), GTK_WIDGET(canvas_bar), TRUE, TRUE, 0);
00495 
00496   if(properties->fullscreen)
00497     {
00498       gnome_canvas_item_new (gnome_canvas_root(canvas_bg),
00499                           gnome_canvas_widget_get_type (),
00500                           "widget", vbox,
00501                           "x", (double) (screen_width-
00502                                        BOARDWIDTH*xratio)/2,
00503                           "y", (double) (screen_height-
00504                                        BOARDHEIGHT*xratio-BARHEIGHT*xratio)/2,
00505                           "width",  (double)BOARDWIDTH*xratio,
00506                           "height", (double)BOARDHEIGHT*xratio+BARHEIGHT*xratio,
00507                           "size_pixels", TRUE,
00508                           NULL);
00509     }
00510 
00511   /* Create the drawing area */
00512   gnome_canvas_set_pixels_per_unit (canvas, xratio);
00513 
00514   gnome_canvas_set_scroll_region (canvas,
00515                               0, 0,
00516                               BOARDWIDTH,
00517                               BOARDHEIGHT);
00518 
00519   gtk_widget_set_usize (GTK_WIDGET(canvas), BOARDWIDTH*xratio, BOARDHEIGHT*xratio);
00520 
00521   /* Create the spot for the bar */
00522   gnome_canvas_set_pixels_per_unit (canvas_bar, xratio);
00523   gnome_canvas_set_scroll_region (canvas_bar,
00524                               0, 0,
00525                               BOARDWIDTH,
00526                               BARHEIGHT);
00527   gtk_widget_set_usize (GTK_WIDGET(canvas_bar),  BOARDWIDTH*xratio,  BARHEIGHT*xratio);
00528 
00529 }
00530 
00531 void gc_cursor_set(guint gdk_cursor_type)
00532 {
00533   GdkCursor *cursor;
00534 
00535   // Little hack to force gcompris to use the default cursor
00536   if(gdk_cursor_type==GCOMPRIS_DEFAULT_CURSOR)
00537     gdk_cursor_type=properties->defaultcursor;
00538 
00539   // I suppose there is less than GCOMPRIS_FIRST_CUSTOM_CURSOR cursors defined in gdkcursors.h !
00540   if (gdk_cursor_type < GCOMPRIS_FIRST_CUSTOM_CURSOR) {
00541     cursor = gdk_cursor_new(gdk_cursor_type);
00542     gdk_window_set_cursor (window->window, cursor);
00543     gdk_cursor_destroy(cursor);
00544   } else { // we use a custom cursor
00545     GdkColor fg, bg;
00546     //    static const gchar * cursor;
00547     static const gchar ** bits;
00548 
00549     gdk_color_parse("rgb:FFFF/FFFF/FFFF",&fg);
00550     gdk_color_parse("rgb:FFFF/3FFF/0000",&bg);
00551 
00552     gdk_color_parse("black",&fg);
00553     gdk_color_parse("red",&bg);
00554 
00555     switch (gdk_cursor_type) {
00556     case GCOMPRIS_BIG_RED_ARROW_CURSOR :
00557       bits = big_red_arrow_cursor_bits;
00558       break;
00559     case GCOMPRIS_BIRD_CURSOR :
00560       bits = bird_cursor_bits;
00561       break;
00562     case GCOMPRIS_LINE_CURSOR :
00563       bits = big_red_line_cursor_bits;
00564       break;
00565     case GCOMPRIS_RECT_CURSOR :
00566       bits = big_red_rectangle_cursor_bits;
00567       break;
00568     case GCOMPRIS_FILLRECT_CURSOR :
00569       bits = big_red_filledrectangle_cursor_bits;
00570       break;
00571     case GCOMPRIS_CIRCLE_CURSOR :
00572       bits = big_red_circle_cursor_bits;
00573       break;
00574     case GCOMPRIS_FILLCIRCLE_CURSOR :
00575       bits = big_red_filledcircle_cursor_bits;
00576       break;
00577     case GCOMPRIS_FILL_CURSOR :
00578       bits = big_red_fill_cursor_bits;
00579       break;
00580     case GCOMPRIS_DEL_CURSOR :
00581       bits = big_red_del_cursor_bits;
00582       break;
00583     case GCOMPRIS_SELECT_CURSOR :
00584       bits = big_red_select_cursor_bits;
00585       break;
00586     default : bits = big_red_arrow_cursor_bits;
00587     }
00588 
00589     cursor = gdk_cursor_new_from_data(bits, 40 , 40, &fg, &bg, 0, 0);
00590     if(cursor)
00591       {
00592        gdk_window_set_cursor(window->window, cursor);
00593        gdk_cursor_unref(cursor);
00594       }
00595   }
00596 }
00597 
00598 static void setup_window ()
00599 {
00600   GcomprisBoard *board_to_start;
00601   GdkPixbuf     *icon_pixbuf;
00602   gchar         *icon_file;
00603 
00604   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
00605 
00606   /*
00607    * Set an icon for gcompris
00608    * ------------------------
00609    */
00610   icon_file = g_strconcat(properties->system_icon_dir, "/gcompris.png", NULL);
00611   if (!g_file_test (icon_file, G_FILE_TEST_EXISTS)) {
00612       /* Now check if this file is on the net */
00613       icon_file = gc_net_get_url_from_file("gcompris.png", NULL);
00614   }
00615 
00616   if(!icon_file)
00617       g_warning ("Couldn't find file %s !", icon_file);
00618 
00619   icon_pixbuf = gc_net_load_pixmap(icon_file);
00620   if (!icon_pixbuf)
00621     {
00622       g_warning ("Failed to load pixbuf file: %s\n",
00623                icon_file);
00624     }
00625   g_free(icon_file);
00626 
00627   if (icon_pixbuf)
00628     {
00629       gtk_window_set_icon (GTK_WINDOW (window), icon_pixbuf);
00630       gdk_pixbuf_unref (icon_pixbuf);
00631     }
00632   gtk_window_set_title(GTK_WINDOW (window), "GCompris");
00633 
00634   /*
00635    * Set the main window
00636    * -------------------
00637    */
00638 
00639   gtk_window_set_policy (GTK_WINDOW (window), FALSE, FALSE, TRUE);
00640   gtk_window_set_default_size(GTK_WINDOW(window), 250, 350);
00641   gtk_window_set_wmclass(GTK_WINDOW(window), "gcompris", "GCompris");
00642 
00643   gtk_widget_realize (window);
00644 
00645   gtk_signal_connect (GTK_OBJECT (window), "delete_event",
00646                     GTK_SIGNAL_FUNC (quit_cb), NULL);
00647 
00648   gtk_signal_connect (GTK_OBJECT (window), "map_event",
00649                     GTK_SIGNAL_FUNC (map_cb), NULL);
00650 
00651 #ifdef XF86_VIDMODE
00652   /* The Xf86VidMode code needs to accuratly now the window position,
00653      this is the only way to get it, and it needs to track the focus to
00654      enable/disable fullscreen on alt-tab */
00655   gtk_widget_add_events(GTK_WIDGET(window),
00656     GDK_STRUCTURE_MASK|GDK_FOCUS_CHANGE_MASK);
00657   gtk_signal_connect (GTK_OBJECT (window), "configure_event",
00658     GTK_SIGNAL_FUNC (xf86_window_configured), 0);
00659   gtk_signal_connect (GTK_OBJECT (window), "focus_in_event",
00660     GTK_SIGNAL_FUNC (xf86_focus_changed), 0);
00661   gtk_signal_connect (GTK_OBJECT (window), "focus_out_event",
00662     GTK_SIGNAL_FUNC (xf86_focus_changed), 0);
00663 #endif
00664 
00665   /* For non anti alias canvas */
00666   gtk_widget_push_visual (gdk_rgb_get_visual ());
00667   gtk_widget_push_colormap (gdk_rgb_get_cmap ());
00668 
00669   // Set the cursor
00670   gc_cursor_set(GCOMPRIS_DEFAULT_CURSOR);
00671 
00672   /* For anti alias canvas */
00673   /*
00674   gtk_widget_push_visual(gdk_rgb_get_visual());
00675   gtk_widget_push_colormap(gdk_rgb_get_cmap());
00676   */
00677 
00678   if(antialiased)
00679     {
00680       /* For anti alias canvas */
00681        canvas     = GNOME_CANVAS(gnome_canvas_new_aa ());
00682        canvas_bar = GNOME_CANVAS(gnome_canvas_new_aa ());
00683        canvas_bg = GNOME_CANVAS(gnome_canvas_new_aa ());
00684     }
00685   else
00686     {
00687       /* For non anti alias canvas */
00688       canvas     = GNOME_CANVAS(gnome_canvas_new ());
00689       canvas_bar = GNOME_CANVAS(gnome_canvas_new ());
00690       canvas_bg  = GNOME_CANVAS(gnome_canvas_new ());
00691     }
00692 
00693   gtk_signal_connect_after (GTK_OBJECT (window), "key_press_event",
00694                          GTK_SIGNAL_FUNC (board_widget_key_press_callback), 0);
00695   gtk_signal_connect_after (GTK_OBJECT (canvas), "key_press_event",
00696                          GTK_SIGNAL_FUNC (board_widget_key_press_callback), 0);
00697   gtk_signal_connect_after (GTK_OBJECT (canvas_bar), "key_press_event",
00698                          GTK_SIGNAL_FUNC (board_widget_key_press_callback), 0);
00699   gtk_signal_connect_after (GTK_OBJECT (canvas_bg), "key_press_event",
00700                          GTK_SIGNAL_FUNC (board_widget_key_press_callback), 0);
00701 
00702   gc_im_init(window);
00703 
00704 
00705   if(properties->fullscreen)
00706     gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET(canvas_bg));
00707 
00708   gtk_widget_pop_colormap ();
00709   gtk_widget_pop_visual ();
00710 
00711 
00712   gtk_widget_show (GTK_WIDGET(canvas_bg));
00713 
00714   gc_board_init();
00715 
00716 
00717   /* Load all the menu once */
00718   gc_menu_load();
00719 
00720   /* Load the mime type */
00721   gc_mime_type_load();
00722 
00723   /* Save the root_menu */
00724   properties->menu_board = gc_menu_section_get(properties->root_menu);
00725 
00726   /* By default, the menu will be started */
00727   board_to_start = properties->menu_board;
00728 
00729   /* Get and Run the root menu */
00730   if(properties->administration)
00731     {
00732       board_to_start = gc_menu_section_get("/administration/administration");
00733     }
00734   else
00735     {
00736       /* If we have a profile defined, run the login screen
00737        * (the login screen is a board that uppon login completion
00738        * starts the menu)
00739        */
00740       if(properties->profile && properties->profile->group_ids)
00741        {
00742          gboolean found = FALSE;
00743 
00744          GList *group_id;
00745 
00746          for (group_id = properties->profile->group_ids; group_id != NULL; group_id = group_id->next)
00747            if (g_list_length(gc_db_users_from_group_get( *((int *) group_id->data))) > 0){
00748              found = TRUE;
00749              break;
00750            }
00751 
00752          /* No profile start normally */
00753          if (found)
00754            board_to_start = gc_menu_section_get("/login/login");
00755          else {
00756            board_to_start = gc_menu_section_get(properties->root_menu);
00757            /* this will set user information to system one */
00758            gc_profile_set_current_user(NULL);
00759          }
00760        }
00761       else
00762        /* this will set user information to system one */
00763        gc_profile_set_current_user(NULL);
00764     }
00765 
00766     /* Run the bar */
00767   gc_bar_start(canvas_bar);
00768 
00769   init_background();
00770 
00771   if(!board_to_start) {
00772     gchar *tmpstr= g_strdup_printf("Couldn't find the board menu %s, or plugin execution error", properties->root_menu);
00773     gc_dialog(tmpstr, NULL);
00774     g_free(tmpstr);
00775   } else if(!gc_board_check_file(board_to_start)) {
00776     gchar *tmpstr= g_strdup_printf("Couldn't find the board menu, or plugin execution error");
00777     gc_dialog(tmpstr, NULL);
00778     g_free(tmpstr);
00779   } else {
00780     g_warning("Fine, we got the gcomprisBoardMenu, xml boards parsing went fine");
00781     gc_board_play(board_to_start);
00782   }
00783 
00784   display_activation_dialog();
00785 
00786 }
00787 
00788 #ifdef WIN32
00789 extern int gc_board_number_in_demo;
00793 void
00794 display_activation_dialog()
00795 {
00796   int board_count = 0;
00797   GList *list;
00798   guint  key_is_valid = 0;
00799 
00800   key_is_valid = gc_activation_check(properties->key);
00801 
00802   if(key_is_valid == 1)
00803     return;
00804 
00805   /* Count non menu boards */
00806   for (list = gc_menu_get_boards(); list != NULL; list = list->next)
00807     {
00808       GcomprisBoard *board = list->data;
00809       if (strcmp(board->type, "menu") != 0 &&
00810          strcmp(board->section, "/experimental") != 0 &&
00811          strcmp(board->section, "/administration") != 0)
00812        board_count++;
00813     }
00814 
00815   /* Entry area */
00816   widget_activation_entry = (GtkEntry *)gtk_entry_new();
00817   gtk_entry_set_max_length(widget_activation_entry, 6);
00818   activation_item = \
00819     gnome_canvas_item_new (gnome_canvas_root(canvas),
00820                         gnome_canvas_widget_get_type (),
00821                         "widget", GTK_WIDGET(widget_activation_entry),
00822                         "x", (double) BOARDWIDTH / 2 - 50,
00823                         "y", (double) BOARDHEIGHT - 60,
00824                         "width", 100.0,
00825                         "height", 30.0,
00826                         "anchor", GTK_ANCHOR_NW,
00827                         "size_pixels", FALSE,
00828                         NULL);
00829   gtk_signal_connect(GTK_OBJECT(widget_activation_entry), "activate",
00830                    GTK_SIGNAL_FUNC(activation_enter_callback),
00831                    NULL);
00832 
00833   gtk_widget_show(GTK_WIDGET(widget_activation_entry));
00834   gtk_entry_set_text(GTK_ENTRY(widget_activation_entry), "CODE");
00835 
00836   gc_board_stop();
00837 
00838   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>\nThe Linux version does not have this restriction. Note that GCompris is being developed to free schools from monopolistic software vendors. 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>"),
00839                            gc_board_number_in_demo, board_count);
00840   gc_dialog(msg, activation_done);
00841   g_free(msg);
00842 }
00843 
00849 int gc_activation_check(char *code)
00850 {
00851   int value = 0;
00852   int i;
00853   char crc1 = 0;
00854   char crc2 = 0;
00855   char codeddate[4];
00856 
00857   if(strlen(code) != 6)
00858     return -1;
00859 
00860   for(i=3; i>=0; i--)
00861     {
00862       value |= code[i] & 0x07;
00863       value = value << 3;
00864       crc1 = (crc1 ^ code[i]) & 0x07;
00865     }
00866   value = value >> 3;
00867   crc1 = 0x30 | crc1;
00868   crc2 = 0x30 | (code[2] ^ code[3]);
00869 
00870   if(crc1 != code[4])
00871     return(-1);
00872 
00873   if(crc2 != code[5])
00874     return(-1);
00875 
00876   codeddate[3] = 0x30 | (value & 0x000F);
00877   value = value >> 4;
00878 
00879   codeddate[2] = 0x30 | (value & 0x0001);
00880   value = value >> 1;
00881 
00882   codeddate[1] = 0x30 | (value & 0x000F);
00883   value = value >> 4;
00884 
00885   codeddate[0] = 0x30 | (value & 0x0003);
00886   codeddate[4] = '\0';
00887 
00888   if(atoi(codeddate) + 200 >= atoi(BUILD_DATE))
00889     return(1);
00890   else
00891     return(0);
00892 }
00893 
00894 /* Check the activation code
00895  *
00896  */
00897 static void
00898 activation_enter_callback( GtkWidget *entry,
00899                         GtkWidget *notused )
00900 {
00901   switch(gc_activation_check((char *)gtk_entry_get_text(GTK_ENTRY(entry))))
00902     {
00903     case 1:
00904       gc_prop_get()->key = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
00905       gc_prop_save(properties);
00906       gtk_entry_set_text(GTK_ENTRY(entry), "GOOD");
00907       break;
00908     case 0:
00909       gtk_entry_set_text(GTK_ENTRY(entry), "EXPIRE");
00910       break;
00911     case -1:
00912       gtk_entry_set_text(GTK_ENTRY(entry), "WRONG");
00913       break;
00914     }
00915 }
00916 
00917 /* Callback for the activation dialog
00918  *
00919  */
00920 static void
00921 activation_done()
00922 {
00923   if ((strcmp((char *)gtk_entry_get_text(GTK_ENTRY(widget_activation_entry)), "CODE") != 0) &&
00924       (strcmp((char *)gtk_entry_get_text(GTK_ENTRY(widget_activation_entry)), "GOOD") != 0) &&
00925       (strcmp((char *)gtk_entry_get_text(GTK_ENTRY(widget_activation_entry)), "WRONG") != 0))
00926     {
00927       activation_enter_callback(widget_activation_entry, NULL);
00928     }
00929 
00930   gc_board_play(properties->menu_board);
00931   gtk_object_destroy (GTK_OBJECT(activation_item));
00932 }
00933 #endif
00934 
00938 void gc_board_end()
00939 {
00940   if (gc_board_get_current()->previous_board) {
00941     /* Run the previous board */
00942     gc_board_play(gc_board_get_current()->previous_board);
00943   }
00944 }
00945 
00950 void gc_fullscreen_set(gboolean state)
00951 {
00952 #ifdef XF86_VIDMODE
00953   xf86_vidmode_set_fullscreen(state);
00954 #endif
00955   if(state)
00956     {
00957       gdk_window_set_decorations (window->window, 0);
00958       gdk_window_set_functions (window->window, 0);
00959 #ifdef XF86_VIDMODE
00960       if(properties->noxf86vm)
00961 #endif
00962        gtk_window_fullscreen (GTK_WINDOW(window));
00963       gtk_widget_set_uposition (window, 0, 0);
00964     }
00965   else
00966     {
00967       /* The hide must be done at least for KDE */
00968       if (is_mapped)
00969         gtk_widget_hide (window);
00970       gdk_window_set_decorations (window->window, GDK_DECOR_ALL);
00971       if (is_mapped)
00972         gtk_widget_show (window);
00973       gdk_window_set_functions (window->window, GDK_FUNC_ALL);
00974 #ifdef XF86_VIDMODE
00975       if(properties->noxf86vm)
00976 #endif
00977        gtk_window_unfullscreen (GTK_WINDOW(window));
00978       gtk_widget_set_uposition (window, 0, 0);
00979     }
00980 
00981 }
00982 
00983 /* Use these instead of the gnome_canvas ones for proper fullscreen mousegrab
00984    handling. */
00985 int gc_canvas_item_grab (GnomeCanvasItem *item, unsigned int event_mask,
00986                          GdkCursor *cursor, guint32 etime)
00987 {
00988   int retval;
00989 
00990   retval = gnome_canvas_item_grab(item, event_mask, cursor, etime);
00991   if (retval != GDK_GRAB_SUCCESS)
00992     return retval;
00993 
00994 #ifdef XF86_VIDMODE
00995   /* When fullscreen override mouse grab with our own which
00996      confines the cursor to our fullscreen window */
00997   if (XF86VidModeData.fullscreen_active)
00998     if (gdk_pointer_grab(item->canvas->layout.bin_window, FALSE, event_mask,
00999           window->window, cursor, etime+1) != GDK_GRAB_SUCCESS)
01000       g_warning("Pointer grab failed");
01001 #endif
01002 
01003   return retval;
01004 }
01005 
01006 void gc_canvas_item_ungrab (GnomeCanvasItem *item, guint32 etime)
01007 {
01008   gnome_canvas_item_ungrab(item, etime);
01009 #ifdef XF86_VIDMODE
01010   /* When fullscreen restore the normal mouse grab which avoids
01011      scrolling the virtual desktop */
01012   if (XF86VidModeData.fullscreen_active)
01013     if (gdk_pointer_grab(window->window, TRUE, 0, window->window, NULL,
01014           etime+1) != GDK_GRAB_SUCCESS)
01015       g_warning("Pointer grab failed");
01016 #endif
01017 }
01018 
01019 static void cleanup()
01020 {
01021   /* Do not loopback in exit */
01022   signal(SIGINT,  NULL);
01023   signal(SIGSEGV, NULL);
01024 
01025   gc_board_stop();
01026   gc_db_exit();
01027   gc_fullscreen_set(FALSE);
01028   gc_menu_destroy();
01029   gc_prop_destroy(gc_prop_get());
01030 }
01031 
01032 void gc_exit()
01033 {
01034   g_signal_emit_by_name(G_OBJECT(window), "delete_event");
01035 }
01036 
01037 static void quit_cb (GtkWidget *widget, gpointer data)
01038 {
01039 
01040 #ifdef DMALLOC
01041   dmalloc_shutdown();
01042 #endif
01043   cleanup();
01044   gtk_main_quit();
01045 
01046   /*
01047    * Very important or GCompris crashes on exit when closed from the dialog
01048    * It's like if code in the dialog callback continue after the gtk_main_quit is done
01049    */
01050   exit(0);
01051 }
01052 
01053 /*
01054  * We want GCompris to be set as fullscreen the later possible
01055  *
01056  */
01057 static void map_cb (GtkWidget *widget, gpointer data)
01058 {
01059   if(is_mapped == FALSE)
01060     {
01061       gc_fullscreen_set(properties->fullscreen);
01062       is_mapped = TRUE;
01063     }
01064   g_warning("gcompris window is now mapped");
01065 }
01066 
01067 /*
01068  * Process the cleanup of the child (no zombies)
01069  * ---------------------------------------------
01070  */
01071 void gc_terminate(int signum)
01072 {
01073 
01074   g_warning("gcompris got the %d signal, starting exit procedure", signum);
01075 
01076   gc_exit();
01077 
01078 }
01079 
01080 static void load_properties ()
01081 {
01082   gchar *prefix_dir;
01083   gchar *tmpstr;
01084 
01085   properties = gc_prop_new ();
01086 
01087   /* Initialize the binary relocation API
01088    *  http://autopackage.org/docs/binreloc/
01089    */
01090   if(gbr_init (NULL))
01091     g_warning("Binary relocation enabled");
01092   else
01093     g_warning("Binary relocation disabled");
01094 
01095   prefix_dir = gbr_find_prefix(NULL);
01096 
01097   /* Check if we are in the source code (developper usage) */
01098   tmpstr = g_strconcat(prefix_dir, "/gcompris.c", NULL);
01099   if(g_file_test(tmpstr, G_FILE_TEST_EXISTS))
01100     {
01101       /* Set all directory to get data from the source code we are run in */
01102       properties->package_data_dir = g_strconcat(prefix_dir, "/../../boards", NULL);
01103 
01104       /* In source code, locale mo files are not generated, use the installed one */
01105       properties->package_locale_dir = g_strdup(PACKAGE_LOCALE_DIR);
01106 
01107       properties->package_plugin_dir = g_strconcat(prefix_dir, "/../boards/.libs", NULL);
01108       properties->package_python_plugin_dir = g_strconcat(prefix_dir, "/../boards/python", NULL);
01109       properties->system_icon_dir = g_strconcat(prefix_dir, "/../..", NULL);
01110     }
01111   else
01112     {
01113       gchar *pkg_data_dir = gbr_find_data_dir(PACKAGE_DATA_DIR);
01114       gchar *pkg_clib_dir = gbr_find_lib_dir(PACKAGE_CLIB_DIR);
01115 
01116       properties->package_data_dir = g_strconcat(pkg_data_dir, "/gcompris/boards", NULL);
01117       properties->package_locale_dir = gbr_find_locale_dir(PACKAGE_LOCALE_DIR);
01118       properties->package_plugin_dir = g_strconcat(pkg_clib_dir, "/gcompris", NULL);
01119       properties->package_python_plugin_dir = g_strconcat(pkg_data_dir, "/gcompris/python", NULL);
01120       properties->system_icon_dir = g_strconcat(pkg_data_dir, "/pixmaps", NULL);
01121       g_free(pkg_data_dir);
01122       g_free(pkg_clib_dir);
01123     }
01124   g_free(tmpstr);
01125   g_free(prefix_dir);
01126 
01127 
01128   /* Display the directory value we have */
01129   printf("package_data_dir         = %s\n", properties->package_data_dir);
01130   printf("package_locale_dir       = %s\n", properties->package_locale_dir);
01131   printf("package_plugin_dir       = %s\n", properties->package_plugin_dir);
01132   printf("package_python_plugin_dir= %s\n", properties->package_python_plugin_dir);
01133 
01134 }
01135 
01136 GcomprisProperties *gc_prop_get ()
01137 {
01138   return (properties);
01139 }
01140 
01141 /* Return the database file name
01142  * Must be called after properties is initialised
01143  */
01144 gchar *gc_db_get_filename ()
01145 {
01146   g_assert(properties!=NULL);
01147 
01148   return (properties->database);
01149 }
01150 
01151 /*
01152  * This returns the locale for which text must be displayed
01153  *
01154  */
01155 const gchar *gc_locale_get()
01156 {
01157   const gchar *locale;
01158 
01159   /* First check locale got overrided by the user */
01160   if(gc_locale != NULL)
01161     return(gc_locale);
01162 
01163   locale = g_getenv("LC_ALL");
01164   if(locale == NULL)
01165     locale = g_getenv("LC_MESSAGES");
01166   if(locale == NULL)
01167     locale = g_getenv("LANG");
01168 
01169   if(locale!=NULL)
01170     return(locale);
01171 
01172   return("en_US.UTF-8");
01173 }
01174 
01175 /*
01176  * This return the user default locale like it was at program
01177  * startup before we started changing the locale
01178  *
01179  */
01180 char *gc_locale_get_user_default()
01181 {
01182   return gc_user_default_locale;
01183 }
01184 
01185 /*
01186  * This set the locale for which text must be displayed
01187  *
01188  */
01189 void
01190 gc_locale_set(gchar *locale)
01191 {
01192 
01193   if(!locale)
01194     return;
01195 
01196   g_message("gc_locale_set '%s'\n", locale);
01197   if(gc_locale != NULL)
01198     g_free(gc_locale);
01199 
01200 #if defined WIN32
01201   /* On windows, it always works */
01202   gc_locale = g_strdup(locale);
01203   setlocale(LC_MESSAGES, locale);
01204   setlocale(LC_ALL, locale);
01205 #else
01206   gc_locale = g_strdup(setlocale(LC_MESSAGES, locale));
01207   if (!gc_locale)
01208     gc_locale = g_strdup(locale);
01209 #endif
01210 
01211   if(gc_locale!=NULL && strcmp(locale, gc_locale))
01212     g_warning("Requested locale '%s' got '%s'", locale, gc_locale);
01213 
01214   if(gc_locale==NULL)
01215     g_warning("Failed to set requested locale %s got %s", locale, gc_locale);
01216 
01217   /* Override the env locale to what the user requested */
01218   /* This makes gettext to give us the new locale text  */
01219   gc_setenv ("LC_ALL", gc_locale_get());
01220   gc_setenv ("LC_MESSAGES", gc_locale_get());
01221   gc_setenv ("LANGUAGE", gc_locale_get());
01222   gc_setenv ("LANG", gc_locale_get());
01223 
01224   /* This does update gettext translation uppon next gettext call */
01225   /* Call for localization startup */
01226   bindtextdomain (GETTEXT_PACKAGE, properties->package_locale_dir);
01227   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
01228   textdomain (GETTEXT_PACKAGE);
01229 
01230 #ifndef WIN32
01231   /* Make change known.  */
01232   {
01233     extern int  _nl_msg_cat_cntr;
01234     ++_nl_msg_cat_cntr;
01235   }
01236 #endif
01237 
01238 }
01239 
01240 void gc_log_handler (const gchar *log_domain,
01241                         GLogLevelFlags log_level,
01242                         const gchar *message,
01243                         gpointer user_data) {
01244   if(gc_debug)
01245     g_printerr ("%s: %s\n\n", "gcompris", message);
01246 }
01247 
01248 #ifdef XF86_VIDMODE
01249 /*
01250  * XF86VidMode STUFF
01251  * -----------------
01252  */
01253 static void
01254 xf86_vidmode_init ( void )
01255 {
01256   int i,j, mode_count;
01257   XF86VidModeModeInfo **modes;
01258   XF86VidModeModeLine *l = (XF86VidModeModeLine *)((char *)
01259     &XF86VidModeData.orig_mode + sizeof XF86VidModeData.orig_mode.dotclock);
01260 
01261   if (properties->noxf86vm)
01262     return;
01263 
01264   if (!XF86VidModeQueryVersion(GDK_DISPLAY(), &i, &j))
01265     properties->noxf86vm = TRUE;
01266   else if (!XF86VidModeQueryExtension(GDK_DISPLAY(), &i, &j))
01267     properties->noxf86vm = TRUE;
01268   else if (!XF86VidModeGetModeLine(GDK_DISPLAY(), GDK_SCREEN_XNUMBER(
01269             gdk_screen_get_default()), (int*)&XF86VidModeData.orig_mode.dotclock, l))
01270     properties->noxf86vm = TRUE;
01271   else if (!XF86VidModeGetViewPort(GDK_DISPLAY(), GDK_SCREEN_XNUMBER(
01272             gdk_screen_get_default()), &XF86VidModeData.orig_viewport_x,
01273             &XF86VidModeData.orig_viewport_y))
01274     properties->noxf86vm = TRUE;
01275   else if (!XF86VidModeGetAllModeLines(GDK_DISPLAY(), GDK_SCREEN_XNUMBER(
01276         gdk_screen_get_default()), &mode_count, &modes))
01277     properties->noxf86vm = TRUE;
01278   else {
01279     for (i = 0; i < mode_count; i++)
01280       {
01281         if ((modes[i]->hdisplay == BOARDWIDTH) &&
01282             (modes[i]->vdisplay == BOARDHEIGHT+BARHEIGHT))
01283           {
01284             XF86VidModeData.fs_mode = *modes[i];
01285             break;
01286           }
01287       }
01288     if (i == mode_count)
01289       properties->noxf86vm = TRUE;
01290     XFree(modes);
01291   }
01292 
01293   if (properties->noxf86vm)
01294       g_warning("XF86VidMode (or 800x600 resolution) not available");
01295   else
01296       g_warning("XF86VidMode support enabled");
01297 }
01298 
01299 
01300 static void
01301 xf86_vidmode_set_fullscreen ( int state )
01302 {
01303   if (properties->noxf86vm || XF86VidModeData.fullscreen_active == state)
01304     return;
01305 
01306   if (state)
01307     {
01308       if (!XF86VidModeSwitchToMode(GDK_DISPLAY(), GDK_SCREEN_XNUMBER(
01309             gdk_screen_get_default()), &XF86VidModeData.fs_mode))
01310         g_warning("XF86VidMode could not switch resolution");
01311       /* Notice the pointer must be grabbed before setting the viewport
01312          otherwise setviewport may get "canceled" by the pointer being outside
01313          the current viewport. */
01314       if (gdk_pointer_grab(window->window, TRUE, 0, window->window, NULL,
01315             GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
01316         g_warning("Pointer grab failed");
01317       if (!XF86VidModeSetViewPort(GDK_DISPLAY(),
01318             GDK_SCREEN_XNUMBER(gdk_screen_get_default()),
01319               XF86VidModeData.window_x, XF86VidModeData.window_y))
01320         g_warning("XF86VidMode could not change viewport");
01321     }
01322   else
01323     {
01324       if (!XF86VidModeSwitchToMode(GDK_DISPLAY(), GDK_SCREEN_XNUMBER(
01325             gdk_screen_get_default()), &XF86VidModeData.orig_mode))
01326         g_warning("XF86VidMode could not restore original resolution");
01327 
01328       gdk_pointer_ungrab(GDK_CURRENT_TIME);
01329       if (XF86VidModeData.orig_viewport_x || XF86VidModeData.orig_viewport_y)
01330         if (!XF86VidModeSetViewPort(GDK_DISPLAY(), GDK_SCREEN_XNUMBER(
01331               gdk_screen_get_default()), XF86VidModeData.orig_viewport_x,
01332               XF86VidModeData.orig_viewport_y))
01333           g_warning("XF86VidMode could not restore original viewport");
01334     }
01335   XF86VidModeData.fullscreen_active = state;
01336 }
01337 
01338 /* We need to accuratly now the window position, this is the only way to get
01339    it. We also grab the pointer to be sure it is really grabbed. Gtk seems
01340    to be playing tricks with the window (destroying and recreating?) when
01341    switching fullscreen <-> window which sometimes (race condition) causes
01342    the pointer to not be properly grabbed.
01343 
01344    This has the added advantage that this way we know for sure the pointer is
01345    always grabbed before setting the viewport otherwise setviewport may get
01346    "canceled" by the pointer being outside the current viewport. */
01347 static gint xf86_window_configured(GtkWindow *window,
01348   GdkEventConfigure *event, gpointer param)
01349 {
01350   XF86VidModeData.window_x = event->x;
01351   XF86VidModeData.window_y = event->y;
01352 
01353   if(XF86VidModeData.fullscreen_active) {
01354     if (gdk_pointer_grab(event->window, TRUE, 0, event->window, NULL,
01355           GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
01356       g_warning("Pointer grab failed");
01357     if (!XF86VidModeSetViewPort(GDK_DISPLAY(),
01358           GDK_SCREEN_XNUMBER(gdk_screen_get_default()), event->x, event->y))
01359       g_warning("XF86VidMode could not change viewport");
01360   }
01361   /* Act as if we aren't there / aren't hooked up */
01362   return FALSE;
01363 }
01364 
01365 static gint xf86_focus_changed(GtkWindow *window,
01366   GdkEventFocus *event, gpointer param)
01367 {
01368   if (!event->in && XF86VidModeData.ignore_focus_out)
01369     XF86VidModeData.ignore_focus_out--;
01370   else if (properties->fullscreen)
01371     xf86_vidmode_set_fullscreen(event->in);
01372   /* Act as if we aren't there / aren't hooked up */
01373   return FALSE;
01374 }
01375 
01376 #endif
01377 
01378 /*****************************************
01379  * Main
01380  *
01381  */
01382 
01383 int
01384 gc_init (int argc, char *argv[])
01385 {
01386   poptContext pctx;
01387   int popt_option;
01388 
01389   /* First, Remove the gnome crash dialog because it locks the user when in full screen */
01390   signal(SIGSEGV, gc_terminate);
01391   signal(SIGINT, gc_terminate);
01392 
01393   load_properties();
01394 
01395   gc_skin_load(properties->skin);
01396 
01397   bindtextdomain (GETTEXT_PACKAGE, properties->package_locale_dir);
01398   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
01399   textdomain (GETTEXT_PACKAGE);
01400 
01401   /* To have some real random behaviour */
01402   srand (time (NULL));
01403 
01404   /* Default difficulty filter: non specified */
01405   popt_difficulty_filter = -1;
01406 
01407   gtk_init (&argc, &argv);
01408 
01409   pctx = poptGetContext (PACKAGE, argc, (const char **)argv, options, 0);
01410 
01411   /* Argument parsing */
01412   popt_option = poptGetNextOpt (pctx);
01413 
01414   // Set the default gcompris cursor
01415   properties->defaultcursor = GCOMPRIS_DEFAULT_CURSOR;
01416 
01417   /* Save the default locale */
01418 #if defined WIN32
01419   gc_user_default_locale = g_win32_getlocale();
01420   // Set the user's choice locale
01421   if(properties->locale[0]=='\0') {
01422     gc_locale_set(gc_user_default_locale);
01423   } else {
01424     gc_locale_set(properties->locale);
01425   }
01426 #else
01427   gc_user_default_locale = g_strdup(setlocale(LC_MESSAGES, NULL));
01428   // Set the user's choice locale
01429   gc_locale_set(properties->locale);
01430 #endif
01431 
01432   /* Set the default message handler, it avoids message with option -D */
01433   g_log_set_handler (NULL, G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_DEBUG | G_LOG_FLAG_FATAL
01434                    | G_LOG_FLAG_RECURSION, gc_log_handler, NULL);
01435 
01436   /*------------------------------------------------------------*/
01437   if (popt_version)
01438     {
01439       printf (_("GCompris\nVersion: %s\nLicence: GPL\n"
01440               "More info at http://gcompris.net\n"),
01441              VERSION);
01442       exit (0);
01443     }
01444 
01445   if (popt_debug)
01446     {
01447       gc_debug = TRUE;
01448     }
01449 
01450   if (popt_fullscreen)
01451     {
01452       properties->fullscreen = TRUE;
01453     }
01454 
01455   if (popt_noxf86vm)
01456     {
01457       properties->noxf86vm = TRUE;
01458     }
01459 
01460   if (popt_window)
01461     {
01462       properties->fullscreen = FALSE;
01463     }
01464 
01465   if (popt_mute)
01466     {
01467       g_warning("Sound disabled");
01468       properties->music = FALSE;
01469       properties->fx = FALSE;
01470     }
01471 
01472   if (popt_sound)
01473     {
01474       g_warning("Sound enabled");
01475       properties->music = TRUE;
01476       properties->fx = TRUE;
01477     }
01478 
01479   if (popt_cursor)
01480     {
01481       g_warning("Default gnome cursor enabled");
01482       properties->defaultcursor = GDK_LEFT_PTR;
01483     }
01484 #ifdef WIN32
01485   properties->defaultcursor = GDK_LEFT_PTR;
01486 #endif
01487 
01488   if (popt_aalias)
01489     {
01490       g_warning("Slower Antialiased canvas used");
01491       antialiased = TRUE;
01492     }
01493 
01494   if (popt_experimental)
01495     {
01496       g_warning("Experimental boards allowed");
01497       properties->experimental  = TRUE;
01498     }
01499 
01500   if (popt_no_quit)
01501     {
01502       g_warning("Disable quit button");
01503       properties->disable_quit = TRUE;
01504     }
01505 
01506   if (popt_no_config)
01507     {
01508       g_warning("Disable config button");
01509       properties->disable_config = TRUE;
01510     }
01511 
01512   if (popt_difficulty_filter>=0)
01513     {
01514       /* This option provide less capacity than the GUI since we cannot set the filter_style */
01515       g_warning("Display only activities of level %d", popt_difficulty_filter);
01516       properties->difficulty_filter = popt_difficulty_filter;
01517       properties->filter_style      = GCOMPRIS_FILTER_EQUAL;
01518     }
01519 
01520   if (popt_local_activity){
01521     g_warning("Adding local activies from %s.", popt_local_activity);
01522     properties->local_directory = g_strdup(popt_local_activity);
01523   }
01524 
01525   if (popt_root_menu){
01526     if (strcmp(popt_root_menu,"list")==0){
01527       /* check the list of possible values for -l, then exit */
01528       printf(_("Use -l to access an activity directly.\n"));
01529       printf(_("The list of available activities is :\n"));
01530       properties->root_menu = "/";
01531 
01532       gc_db_init();
01533 
01534       gc_menu_load();
01535 
01536       GList *list = NULL;
01537       GList *menulist = NULL;
01538       GList *menu_todo = NULL;
01539       int board_count = 0;
01540 
01541       menu_todo = g_list_append(menu_todo,g_strdup("/"));
01542 
01543       while ( menu_todo != NULL) {
01544        menulist = gc_menu_getlist(menu_todo->data);
01545        g_free(menu_todo->data);
01546        menu_todo = menu_todo->next;
01547 
01548        for(list = menulist; list != NULL; list = list->next) {
01549          GcomprisBoard *board = list->data;
01550 
01551          if (board){
01552            if (strcmp(board->type,"menu")==0)
01553              menu_todo = g_list_prepend(menu_todo, g_strdup_printf("%s/%s",board->section, board->name));
01554            else
01555              board_count++;
01556 
01557            printf("%s/%s : %s (%s) \n", board->section, board->name, board->title, board->description );
01558          }
01559        }
01560       }
01561       /* FIXME: Need to translate */
01562       printf("Number of activities: %d\n", board_count);
01563 
01564       exit(0);
01565     }
01566     else {
01567     g_warning("Using menu %s as root.", popt_root_menu);
01568     properties->root_menu = g_strdup(popt_root_menu);
01569     properties->menu_position = g_strdup(popt_root_menu);
01570     }
01571   }
01572 
01573   if (popt_users_dir){
01574     if ((!g_file_test(popt_users_dir, G_FILE_TEST_IS_DIR)) ||
01575        (access(popt_users_dir, popt_administration? R_OK : W_OK ) == -1)){
01576        g_warning("%s does not exists or is not %s ", popt_users_dir,
01577                 popt_administration? "readable" : "writable");
01578        exit(0);
01579     } else {
01580       g_warning("Using %s as users directory.", popt_users_dir);
01581       properties->users_dir = g_strdup(popt_users_dir);
01582     }
01583   }
01584 
01585   if (popt_shared_dir){
01586     if ((!g_file_test(popt_shared_dir, G_FILE_TEST_IS_DIR)) ||
01587        (access(popt_shared_dir, popt_administration? W_OK : R_OK ) == -1)){
01588       g_warning("%s does not exists or is not %s", popt_shared_dir,
01589               popt_administration? "writable" : "readable"     );
01590       exit(0);
01591     }
01592     else {
01593       g_warning("Using %s as shared directory.", popt_shared_dir);
01594       properties->shared_dir = g_strdup(popt_shared_dir);
01595     }
01596   }
01597 
01598   /* shared_dir initialised, now we can set the default */
01599   g_free(properties->database);
01600   properties->database = gc_prop_default_database_name_get ( properties->shared_dir );
01601   g_warning( "Infos:\n   Shared dir '%s'\n   Users dir '%s'\n   Database '%s'\n",
01602             properties->shared_dir,
01603             properties->users_dir,
01604             properties->database);
01605 
01606   if (popt_database)
01607     {
01608       properties->database = g_strdup(popt_database);
01609 
01610       if (g_file_test(properties->database, G_FILE_TEST_EXISTS))
01611        {
01612          if (access(properties->database, R_OK)==-1)
01613            {
01614              g_warning("%s exists but is not readable or writable", properties->database);
01615              exit(0);
01616            }
01617          else
01618            {
01619              g_warning("Using %s as database", properties->database);
01620            }
01621        }
01622     }
01623 
01624   if (popt_create_db)
01625     {
01626       gchar *dirname = g_path_get_dirname (properties->database);
01627       if (access(dirname, W_OK)==-1)
01628        {
01629          g_warning("Cannot create %s : %s is not writable !", properties->database, dirname);
01630          exit (0);
01631        }
01632       /* We really want to recreate it, erase the old one */
01633       g_warning("Removing %s database.", properties->database);
01634       unlink(properties->database);
01635     }
01636 
01637   if (popt_administration){
01638     if (popt_database){
01639       if (access(popt_database,R_OK|W_OK)==-1){
01640        g_warning("%s exists but is not writable", popt_database);
01641        exit(0);
01642       }
01643     }
01644     g_warning("Running in administration mode");
01645     properties->administration = TRUE;
01646     g_warning("Background music disabled");
01647     properties->music = FALSE;
01648     g_warning("Fullscreen is disabled");
01649     properties->fullscreen = FALSE;
01650   }
01651 
01652   if (popt_reread_menu){
01653     g_warning("Rebuild db from xml files");
01654     if (access(properties->database, W_OK)==-1)
01655       g_warning("Cannot reread menu when database is read-only !");
01656     else
01657       properties->reread_menu = TRUE;
01658   }
01659 
01660   if (popt_server){
01661 #ifdef USE_GNET
01662       properties->server = g_strdup(popt_server);
01663 #else
01664       printf("The --server option cannot be used because GCompris has been compiled without network support!");
01665       exit(1);
01666 #endif
01667   }
01668 
01669   if(popt_web_only) {
01670     g_free(properties->package_data_dir);
01671     properties->package_data_dir = g_strdup("");
01672 
01673     g_free(properties->system_icon_dir);
01674     properties->system_icon_dir = g_strdup("");
01675   }
01676 
01677   if (popt_server){
01678       properties->cache_dir = g_strdup(popt_cache_dir);
01679   }
01680 
01681   /*
01682    * Database init MUST BE after properties
01683    * And after a possible alternate database as been provided
01684    *
01685    */
01686   gc_db_init();
01687 
01688   /* An alternate profile is requested, check it does exists */
01689   if (popt_profile){
01690     properties->profile = gc_db_profile_from_name_get(popt_profile);
01691 
01692     if(properties->profile == NULL)
01693       {
01694        printf("ERROR: Profile '%s' is not found. Run 'gcompris --profile-list' to list available ones\n",
01695               popt_profile);
01696        exit(1);
01697       }
01698   }
01699 
01700   /* List all available profiles */
01701   if (popt_profile_list){
01702     GList * profile_list;
01703     int i;
01704 
01705     profile_list = gc_db_profiles_list_get();
01706 
01707     printf(_("The list of available profiles is:\n"));
01708     for(i=0; i< g_list_length(profile_list); i++)
01709       {
01710        GcomprisProfile *profile = g_list_nth_data(profile_list, i);
01711        printf("   %s\n", profile->name);
01712       }
01713 
01714     g_list_free(profile_list);
01715 
01716     exit(0);
01717   }
01718 
01719   /* An alternate profile is requested, check it does exists */
01720   if (popt_display_resource){
01721     properties->display_resource = TRUE;
01722     properties->reread_menu = TRUE;
01723     printf("Resources for selected activities (as selected by gcompris --administration):\n");
01724     gc_menu_load();
01725     exit(0);
01726   }
01727 
01728   poptFreeContext(pctx);
01729   /*------------------------------------------------------------*/
01730 
01731   if(properties->music || properties->fx)
01732     gc_sound_init();
01733 
01734   /* Gdk-Pixbuf */
01735   gdk_rgb_init();
01736 
01737   /* Cache init */
01738   gc_cache_init(-1);
01739 
01740   /* networking init */
01741   gc_net_init();
01742 
01743   setup_window ();
01744 
01745   gtk_widget_show_all (window);
01746 
01747   if (properties->music)
01748     gc_sound_play_ogg("music/intro.ogg", "sounds/$LOCALE/misc/welcome.ogg", NULL);
01749   else
01750     gc_sound_play_ogg("sounds/$LOCALE/misc/welcome.ogg", NULL);
01751 
01752   gtk_main ();
01753   return 0;
01754 }