Back to index

gcompris  8.2.2
gameutil.c
Go to the documentation of this file.
00001 /* gcompris - gameutil.c
00002  *
00003  * Time-stamp: <2006/08/20 12:41:31 bruno>
00004  *
00005  * Copyright (C) 2000-2006 Bruno Coudoin
00006  *
00007  *   This program is free software; you can redistribute it and/or modify
00008  *   it under the terms of the GNU General Public License as published by
00009  *   the Free Software Foundation; either version 2 of the License, or
00010  *   (at your option) any later version.
00011  *
00012  *   This program is distributed in the hope that it will be useful,
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *   GNU General Public License for more details.
00016  *
00017  *   You should have received a copy of the GNU General Public License
00018  *   along with this program; if not, write to the Free Software
00019  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  */
00021 
00022 #include <math.h>
00023 #include <string.h>
00024 #include <time.h>
00025 
00026 /* g_mkdir */
00027 #define G_STDIO_NO_WRAP_ON_UNIX
00028 #include <glib/gstdio.h>
00029 
00030 /* libxml includes */
00031 #include <libxml/parserInternals.h>
00032 
00033 #include "gcompris.h"
00034 
00035 extern GnomeCanvas *canvas;
00036 
00037 typedef void (*sighandler_t)(int);
00038 
00039 
00048 GdkPixbuf *gc_pixmap_load(const gchar *format, ...)
00049 {
00050   va_list args;
00051   gchar *filename;
00052   gchar *pixmapfile;
00053   GdkPixbuf *pixmap=NULL;
00054 
00055   if (!format)
00056     return NULL;
00057 
00058   va_start (args, format);
00059   pixmapfile = g_strdup_vprintf (format, args);
00060   va_end (args);
00061 
00062   /* Search */
00063   filename = gc_file_find_absolute(pixmapfile);
00064 
00065   if(filename)
00066     pixmap = gc_net_load_pixmap(filename);
00067 
00068   if (!filename || !pixmap)
00069     {
00070       char *str;
00071 
00072       if(!pixmap)
00073        g_warning("Loading image '%s' returned a null pointer", filename);
00074       else
00075        g_warning ("Couldn't find file %s !", pixmapfile);
00076 
00077       str = g_strdup_printf("%s\n%s\n%s\n%s",
00078                          _("Couldn't find or load the file"),
00079                          pixmapfile,
00080                          _("This activity is incomplete."),
00081                          _("Exit it and report\nthe problem to the authors."));
00082       gc_dialog (str, NULL);
00083       g_free(pixmapfile);
00084       g_free(str);
00085       return NULL;
00086     }
00087 
00088   g_free(pixmapfile);
00089   g_free(filename);
00090 
00091 
00092   return(pixmap);
00093 }
00094 
00095 /*************************************************************
00096  * colorshift a pixbuf
00097  * code taken from the gnome-panel of gnome-core
00098  */
00099 static void
00100 do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift)
00101 {
00102   gint i, j;
00103   gint width, height, has_alpha, srcrowstride, destrowstride;
00104   guchar *target_pixels;
00105   guchar *original_pixels;
00106   guchar *pixsrc;
00107   guchar *pixdest;
00108   int val;
00109   guchar r,g,b;
00110 
00111   has_alpha = gdk_pixbuf_get_has_alpha (src);
00112   width = gdk_pixbuf_get_width (src);
00113   height = gdk_pixbuf_get_height (src);
00114   srcrowstride = gdk_pixbuf_get_rowstride (src);
00115   destrowstride = gdk_pixbuf_get_rowstride (dest);
00116   target_pixels = gdk_pixbuf_get_pixels (dest);
00117   original_pixels = gdk_pixbuf_get_pixels (src);
00118 
00119   for (i = 0; i < height; i++) {
00120     pixdest = target_pixels + i*destrowstride;
00121     pixsrc = original_pixels + i*srcrowstride;
00122     for (j = 0; j < width; j++) {
00123       r = *(pixsrc++);
00124       g = *(pixsrc++);
00125       b = *(pixsrc++);
00126       val = r + shift;
00127       *(pixdest++) = CLAMP(val, 0, 255);
00128       val = g + shift;
00129       *(pixdest++) = CLAMP(val, 0, 255);
00130       val = b + shift;
00131       *(pixdest++) = CLAMP(val, 0, 255);
00132       if (has_alpha)
00133        *(pixdest++) = *(pixsrc++);
00134     }
00135   }
00136 }
00137 
00138 
00139 
00140 static GdkPixbuf *
00141 make_hc_pixbuf(GdkPixbuf *pb, gint val)
00142 {
00143   GdkPixbuf *new;
00144   if(!pb)
00145     return NULL;
00146 
00147   new = gdk_pixbuf_new(gdk_pixbuf_get_colorspace(pb),
00148                      gdk_pixbuf_get_has_alpha(pb),
00149                      gdk_pixbuf_get_bits_per_sample(pb),
00150                      gdk_pixbuf_get_width(pb),
00151                      gdk_pixbuf_get_height(pb));
00152   do_colorshift(new, pb, val);
00153   /*do_saturate_darken (new, pb, (int)(1.00*255), (int)(1.15*255));*/
00154 
00155   return new;
00156 }
00157 
00164 void
00165 gc_item_focus_free(GnomeCanvasItem *item, void *none)
00166 {
00167   GdkPixbuf *pixbuf;
00168 
00169   pixbuf = (GdkPixbuf *)g_object_get_data (G_OBJECT (item), "pixbuf_ref");
00170   if(pixbuf)
00171     {
00172       g_object_set_data (G_OBJECT (item), "pixbuf_ref", NULL);
00173       gdk_pixbuf_unref(pixbuf);
00174     }
00175 }
00176 
00181 void gc_item_focus_set(GnomeCanvasItem *item, gboolean focus)
00182 {
00183   GdkPixbuf *dest = NULL;
00184   GdkPixbuf *pixbuf;
00185   GdkPixbuf *pixbuf_ref;
00186 
00187   gtk_object_get (GTK_OBJECT (item), "pixbuf", &pixbuf, NULL);
00188   g_return_if_fail (pixbuf != NULL);
00189   gdk_pixbuf_unref(pixbuf);
00190 
00191   /* Store the first pixbuf */
00192   pixbuf_ref = (GdkPixbuf *)g_object_get_data (G_OBJECT (item), "pixbuf_ref");
00193   if(!pixbuf_ref)
00194     {
00195       g_object_set_data (G_OBJECT (item), "pixbuf_ref", pixbuf);
00196       pixbuf_ref = pixbuf;
00197       gdk_pixbuf_ref(pixbuf);
00198       g_signal_connect (item, "destroy",
00199                      G_CALLBACK (gc_item_focus_free),
00200                      NULL);
00201 
00202     }
00203 
00204 
00205   switch (focus)
00206     {
00207     case TRUE:
00208       dest = make_hc_pixbuf(pixbuf, 30);
00209       gnome_canvas_item_set (item,
00210                           "pixbuf", dest,
00211                           NULL);
00212 
00213       break;
00214     case FALSE:
00215       gnome_canvas_item_set (item,
00216                           "pixbuf", pixbuf_ref,
00217                           NULL);
00218       break;
00219     default:
00220       break;
00221     }
00222 
00223   if(dest!=NULL)
00224     gdk_pixbuf_unref (dest);
00225 
00226 }
00227 
00233 gint
00234 gc_item_focus_event(GnomeCanvasItem *item, GdkEvent *event,
00235                   GnomeCanvasItem *dest_item)
00236 {
00237 
00238   if(dest_item!=NULL)
00239     item = dest_item;
00240 
00241   switch (event->type)
00242     {
00243     case GDK_ENTER_NOTIFY:
00244       gc_item_focus_set(item, TRUE);
00245       break;
00246     case GDK_LEAVE_NOTIFY:
00247       gc_item_focus_set(item, FALSE);
00248       break;
00249     default:
00250       break;
00251     }
00252 
00253   return FALSE;
00254 }
00255 
00256 /*
00257  * Return a new copy of the given string in which it has
00258  * changes '\''n' to '\n'.
00259  * The recognized sequences are \b
00260  * \f \n \r \t \\ \" and the octal format.
00261  *
00262  */
00263 gchar *reactivate_newline(char *str)
00264 {
00265   gchar *newstr;
00266 
00267   if(str==NULL)
00268     return NULL;
00269 
00270   xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
00271 
00272   newstr =  (gchar *)xmlStringDecodeEntities(ctxt,
00273                                         BAD_CAST str,
00274                                         XML_SUBSTITUTE_REF,
00275                                         0,
00276                                         0,
00277                                         0);
00278 
00279   xmlFreeParserCtxt(ctxt);
00280 
00281   return newstr;
00282 }
00283 
00284 /* ======================================= */
00285 void gc_item_absolute_move(GnomeCanvasItem *item, int x, int y) {
00286   double dx1, dy1, dx2, dy2;
00287   gnome_canvas_item_get_bounds(item, &dx1, &dy1, &dx2, &dy2);
00288   gnome_canvas_item_move(item, ((double)x)-dx1, ((double)y)-dy1);
00289 }
00290 
00291 /* ======================================= */
00297 void
00298 gc_item_rotate(GnomeCanvasItem *item, double angle) {
00299   double r[6],t[6], x1, x2, y1, y2;
00300 
00301   gnome_canvas_item_get_bounds( item, &x1, &y1, &x2, &y2 );
00302   art_affine_translate( t , -(x2+x1)/2, -(y2+y1)/2 );
00303   art_affine_rotate( r, angle );
00304   art_affine_multiply( r, t, r);
00305   art_affine_translate( t , (x2+x1)/2, (y2+y1)/2 );
00306   art_affine_multiply( r, r, t);
00307 
00308   gnome_canvas_item_affine_absolute(item, r );
00309 }
00310 
00311 /* As gnome does not implement its own API : gc_item_rotate_relative
00312    we have to do it ourselves ....
00313    IMPORTANT NOTE : This is designed for an item with "anchor" =  GTK_ANCHOR_CENTER
00314    rotation is clockwise if angle > 0
00315  */
00316 void
00317 gc_item_rotate_relative(GnomeCanvasItem *item, double angle) {
00318   double x1, x2, y1, y2;
00319   double tx1, tx2, ty1, ty2;
00320   double cx, cy;
00321   double t;
00322   double r[6];
00323 
00324   //  gnome_canvas_item_get_bounds( item, &x1, &y1, &x2, &y2 );
00325   /* WARNING: Do not use gnome_canvas_item_get_bounds which gives unpredictable results */
00326   if(GNOME_IS_CANVAS_LINE(item)) {
00327     GnomeCanvasPoints       *points;
00328     gtk_object_get (GTK_OBJECT (item), "points", &points, NULL);
00329     x1 = points->coords[0];
00330     y1 = points->coords[1];
00331     x2 = points->coords[2];
00332     y2 = points->coords[3];
00333   } else if(GNOME_IS_CANVAS_PIXBUF(item)){
00334     gtk_object_get (GTK_OBJECT (item), "x", &x1, NULL);
00335     gtk_object_get (GTK_OBJECT (item), "y", &y1, NULL);
00336     gtk_object_get (GTK_OBJECT (item), "width",  &x2, NULL);
00337     gtk_object_get (GTK_OBJECT (item), "height", &y2, NULL);
00338     x2 += x1;
00339     y2 += y1;
00340   } else if(GNOME_IS_CANVAS_GROUP(item)){
00341     gtk_object_get (GTK_OBJECT (item), "x", &x1, NULL);
00342     gtk_object_get (GTK_OBJECT (item), "y", &y1, NULL);
00343     x2 = x1;
00344     y2 = y1;
00345   } else {
00346     gtk_object_get (GTK_OBJECT (item), "x1", &x1, NULL);
00347     gtk_object_get (GTK_OBJECT (item), "y1", &y1, NULL);
00348     gtk_object_get (GTK_OBJECT (item), "x2", &x2, NULL);
00349     gtk_object_get (GTK_OBJECT (item), "y2", &y2, NULL);
00350   }
00351 
00352   tx1 = x1;
00353   ty1 = y1;
00354   tx2 = x2;
00355   ty2 = y2;
00356 
00357   x1 = MIN(tx1,tx2);
00358   y1 = MIN(ty1,ty2);
00359   x2 = MAX(tx1,tx2);
00360   y2 = MAX(ty1,ty2);
00361 
00362 
00363   cx = (x2+x1)/2;
00364   cy = (y2+y1)/2;
00365 
00366   /* Taken from anim by Yves Combe
00367    * This matrix rotate around ( cx, cy )
00368    * This is the result of the product:
00369    *            T_{-c}             Rot (t)                 T_c
00370    *
00371    *       1    0   cx       cos(t) -sin(t)    0        1    0  -cx
00372    *       0    1   cy  by   sin(t)  cos(t)    0   by   0    1  -cy
00373    *       0    0    1         0       0       1        0    0   1
00374    */
00375 
00376   t = M_PI*angle/180.0;
00377 
00378   r[0] = cos(t);
00379   r[1] = sin(t);
00380   r[2] = -sin(t);
00381   r[3] = cos(t);
00382   r[4] = (1-cos(t))*cx + sin(t)*cy;
00383   r[5] = -sin(t)*cx + (1 - cos(t))*cy;
00384 
00385   gnome_canvas_item_affine_relative(item, r );
00386 }
00387 
00390 void
00391 gc_item_rotate_with_center(GnomeCanvasItem *item, double angle, int x, int y) {
00392   double r[6],t[6], x1, x2, y1, y2, tx, ty;
00393 
00394   gnome_canvas_item_get_bounds( item, &x1, &y1, &x2, &y2 );
00395   tx = x1 + x;
00396   ty = y1 + y;
00397   art_affine_translate( t , -tx, -ty );
00398   art_affine_rotate( r, angle );
00399   art_affine_multiply( r, t, r);
00400   art_affine_translate( t , tx, ty );
00401   art_affine_multiply( r, r, t);
00402 
00403   gnome_canvas_item_affine_absolute(item, r );
00404 }
00405 
00409 void
00410 gc_item_rotate_relative_with_center(GnomeCanvasItem *item, double angle, int x, int y) {
00411   double r[6],t[6], x1, x2, y1, y2, tx, ty;
00412 
00413   gnome_canvas_item_get_bounds( item, &x1, &y1, &x2, &y2 );
00414   tx = x1 + x;
00415   ty = y1 + y;
00416   art_affine_translate( t , -tx, -ty );
00417   art_affine_rotate( r, angle );
00418   art_affine_multiply( r, t, r);
00419   art_affine_translate( t , tx, ty );
00420   art_affine_multiply( r, r, t);
00421 
00422   gnome_canvas_item_affine_relative(item, r );
00423 }
00424 
00431 GnomeCanvasGroup *gc_difficulty_display(GnomeCanvasGroup *parent,
00432                                               double x, double y,
00433                                               double ratio,
00434                                               gint difficulty)
00435 {
00436   GdkPixbuf *pixmap = NULL;
00437   GnomeCanvasGroup *stars_group = NULL;
00438   GnomeCanvasPixbuf *item = NULL;
00439   gchar *filename = NULL;
00440 
00441   if(difficulty==0 || difficulty>6)
00442     return NULL;
00443 
00444   filename = g_strdup_printf("difficulty_star%d.png", difficulty);
00445   pixmap   = gc_skin_pixmap_load(filename);
00446   g_free(filename);
00447 
00448   if(!pixmap)
00449     return NULL;
00450 
00451   stars_group = GNOME_CANVAS_GROUP(
00452                               gnome_canvas_item_new (parent,
00453                                                   gnome_canvas_group_get_type (),
00454                                                   "x", (double) 0,
00455                                                   "y", (double) 0,
00456                                                   NULL));
00457 
00458   item = GNOME_CANVAS_PIXBUF(gnome_canvas_item_new (stars_group,
00459                                               gnome_canvas_pixbuf_get_type (),
00460                                               "pixbuf", pixmap,
00461                                               "x", x,
00462                                               "y", y,
00463                                               "width", (double) gdk_pixbuf_get_width(pixmap) * ratio,
00464                                               "height", (double) gdk_pixbuf_get_height(pixmap) * ratio,
00465                                               "width_set", TRUE,
00466                                               "height_set", TRUE,
00467                                               NULL));
00468 
00469   gtk_signal_connect(GTK_OBJECT(item), "event",
00470                    (GtkSignalFunc) gc_item_focus_event,
00471                    NULL);
00472 
00473   gdk_pixbuf_unref(pixmap);
00474 
00475   return(stars_group);
00476 }
00477 
00478 gchar *g_utf8_strndup(gchar* utf8text, gint n)
00479 {
00480  gchar* result;
00481 
00482  gint len = g_utf8_strlen(utf8text, -1);
00483 
00484  if( n < len && n > 0 )
00485    len = n;
00486 
00487  result = g_strndup(utf8text, g_utf8_offset_to_pointer(utf8text, len) - utf8text);
00488 
00489  return result;
00490 }
00491 
00501 gchar*
00502 gc_file_find_absolute(const gchar *format, ...)
00503 {
00504   va_list             args;
00505   int                 i = 0;
00506   gchar                     *filename;
00507   gchar                     *absolute_filename;
00508   gchar                     *dir_to_search[4];
00509   GcomprisProperties *properties = gc_prop_get();
00510 
00511   if (!format)
00512     return NULL;
00513 
00514   va_start (args, format);
00515   filename = g_strdup_vprintf (format, args);
00516   va_end (args);
00517 
00518   /* Check it's already an absolute file */
00519   if( ((g_path_is_absolute (filename) &&
00520        g_file_test (filename, G_FILE_TEST_EXISTS))
00521        || gc_net_is_url(filename)) )
00522     {
00523       return filename;
00524     }
00525 
00526   /*
00527    * Search it on the file system
00528    */
00529 
00530   dir_to_search[i++] = properties->package_data_dir;
00531   dir_to_search[i++] = properties->user_data_dir;
00532   dir_to_search[i++] = NULL;
00533 
00534   absolute_filename = g_strdup(filename);
00535   i = 0;
00536 
00537   while (dir_to_search[i])
00538     {
00539       gchar **tmp;
00540       g_free(absolute_filename);
00541 
00542       /* Check there is a $LOCALE to replace */
00543       if((tmp = g_strsplit(filename, "$LOCALE", -1)))
00544        {
00545          gchar locale[6];
00546          gchar *filename2;
00547 
00548          /* First try with the long locale */
00549          g_strlcpy(locale, gc_locale_get(), sizeof(locale));
00550          filename2 = g_strjoinv(locale, tmp);
00551          absolute_filename = g_strdup_printf("%s/%s", dir_to_search[i], filename2);
00552          if(g_file_test (absolute_filename, G_FILE_TEST_EXISTS))
00553            {
00554              g_strfreev(tmp);
00555              g_free(filename2);
00556              goto FOUND;
00557            }
00558       g_free(absolute_filename);
00559          /* Now check if this file is on the net */
00560          if((absolute_filename = gc_net_get_url_from_file(filename2, NULL)))
00561            {
00562              g_strfreev(tmp);
00563              g_free(filename2);
00564              goto FOUND;
00565            }
00566 
00567       g_free(filename2);
00568       g_free(absolute_filename);
00569          /* Try the short locale */
00570          if(g_strv_length(tmp)>1)
00571            {
00572              locale[2] = '\0';
00573              filename2 = g_strjoinv(locale, tmp);
00574              g_strfreev(tmp);
00575              absolute_filename = g_strdup_printf("%s/%s", dir_to_search[i], filename2);
00576              if(g_file_test (absolute_filename, G_FILE_TEST_EXISTS))
00577               {
00578                 g_free(filename2);
00579                 goto FOUND;
00580               }
00581 
00582              /* Now check if this file is on the net */
00583              if((absolute_filename = gc_net_get_url_from_file(filename2, NULL)))
00584               {
00585                 g_free(filename2);
00586                 goto FOUND;
00587               }
00588         g_free(filename2);
00589 
00590            }
00591       else
00592           g_strfreev(tmp);
00593        }
00594       else
00595        {
00596          absolute_filename = g_strdup_printf("%s/%s", dir_to_search[i], filename);
00597 
00598          if(g_file_test (absolute_filename, G_FILE_TEST_EXISTS))
00599            goto FOUND;
00600     g_free(absolute_filename);
00601          /* Now check if this file is on the net */
00602          if((absolute_filename = gc_net_get_url_from_file(filename, NULL)))
00603            goto FOUND;
00604       g_free(absolute_filename);
00605        }
00606 
00607       i++;
00608     }
00609 
00610   g_free(filename);
00611   g_free(absolute_filename);
00612   return NULL;
00613 
00614  FOUND:
00615   g_free(filename);
00616   return absolute_filename;
00617 }
00618 
00626 int
00627 gc_util_create_rootdir (gchar *rootdir)
00628 {
00629 
00630   /* Case where ~/.gcompris already exist as a file. We remove it */
00631   if(g_file_test(rootdir, G_FILE_TEST_IS_REGULAR)) {
00632     g_unlink(rootdir);
00633   }
00634 
00635   if(g_file_test(rootdir, G_FILE_TEST_IS_DIR)) {
00636     return 0;
00637   }
00638 
00639   return(g_mkdir(rootdir, 0755));
00640 
00641 }