Back to index

gcompris  8.2.2
skin.c
Go to the documentation of this file.
00001 /* gcompris - skin.c
00002  *
00003  * Copyright (C) 2003 GCompris Developpement Team
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #include "string.h"
00021 
00022 #include "skin.h"
00023 #include <libxml/tree.h>
00024 #include <libxml/parser.h>
00025 
00026 GHashTable* gc_skin_fonts   = NULL;
00027 GHashTable* gc_skin_colors  = NULL;
00028 GHashTable* gc_skin_numbers = NULL;
00029 
00030 guint32 gc_skin_color_title;
00031 guint32 gc_skin_color_text_button;
00032 guint32 gc_skin_color_content;
00033 guint32 gc_skin_color_subtitle;
00034 guint32 gc_skin_color_shadow;
00035 
00036 gchar* gc_skin_font_title;
00037 gchar* gc_skin_font_subtitle;
00038 gchar* gc_skin_font_content;
00039 
00040 gchar* gc_skin_font_board_tiny;
00041 gchar* gc_skin_font_board_small;
00042 gchar* gc_skin_font_board_medium;
00043 gchar* gc_skin_font_board_big;
00044 gchar* gc_skin_font_board_big_bold;
00045 gchar* gc_skin_font_board_fixed;
00046 gchar* gc_skin_font_board_title;
00047 gchar* gc_skin_font_board_title_bold;
00048 gchar* gc_skin_font_board_huge;
00049 gchar* gc_skin_font_board_huge_bold;
00050 
00051 
00052 /*
00053  * Given an image name, return an image name
00054  * that includes the skin path
00055  * eg : xx.png -> skins/default/xx.png
00056  *
00057  * The caller must free the returned string
00058  */
00059 gchar *
00060 gc_skin_image_get(gchar *pixmapfile)
00061 {
00062   GcomprisProperties *properties = gc_prop_get();
00063   gchar *filename;
00064 
00065   /* First, test if pixmapfile is in the current skin dir */
00066   filename = g_strdup_printf("%s/skins/%s/%s",
00067                           properties->package_data_dir,
00068                           properties->skin, pixmapfile);
00069 
00070   if (g_file_test ((filename), G_FILE_TEST_EXISTS)) {
00071     g_free(filename);
00072 
00073     filename = g_strdup_printf("skins/%s/%s", properties->skin, pixmapfile);
00074 
00075     return(filename);
00076   }
00077   g_free(filename);
00078 
00079   /* Check it's on the server */
00080   filename = gc_net_get_url_from_file("boards/skins/%s/%s", properties->skin, pixmapfile);
00081   if(filename)
00082     return(filename);
00083 
00084   /* Return the default skin dir */
00085   filename = g_strdup_printf("skins/%s/%s", DEFAULT_SKIN, pixmapfile);
00086   return(filename);
00087 }
00088 
00089 /*
00090  * Load a pixmap from the current skin directory
00091  * If not found, try in the default skin directory
00092  * If not found abort gcompris
00093  */
00094 GdkPixbuf *
00095 gc_skin_pixmap_load(char *pixmapfile)
00096 {
00097   gchar *filename;
00098   GdkPixbuf *result_pixbuf;
00099 
00100   filename = gc_skin_image_get(pixmapfile);
00101 
00102   result_pixbuf = gc_pixmap_load (filename);
00103 
00104   g_free(filename);
00105 
00106   return (result_pixbuf);
00107 }
00108 
00109 /*
00110  * Utility function used when freeing the memory used by
00111  * a hashtable containing strings.
00112  */
00113 static void
00114 gc_skin_free_string(gpointer data)
00115 {
00116   g_free(data);
00117 }
00118 
00119 /*
00120  * Initialize some common variables
00121  * (the one that have to be defined in each skin)
00122  */
00123 void
00124 gc_skin_setup_vars(void)
00125 {
00126   gc_skin_color_title =
00127     gc_skin_get_color_default("gcompris/title", COLOR_TITLE);
00128   gc_skin_color_text_button =
00129     gc_skin_get_color_default("gcompris/text button", COLOR_TEXT_BUTTON);
00130   gc_skin_color_content =
00131     gc_skin_get_color_default("gcompris/content", COLOR_CONTENT);
00132   gc_skin_color_subtitle =
00133     gc_skin_get_color_default("gcompris/subtitle", COLOR_SUBTITLE);
00134   gc_skin_color_shadow =
00135     gc_skin_get_color_default("gcompris/shadow", COLOR_SHADOW);
00136 
00137   gc_skin_font_title =
00138     gc_skin_get_font_default("gcompris/title", FONT_TITLE);
00139   gc_skin_font_subtitle =
00140     gc_skin_get_font_default("gcompris/subtitle", FONT_SUBTITLE);
00141   gc_skin_font_content =
00142     gc_skin_get_font_default("gcompris/content", FONT_CONTENT);
00143 
00144   gc_skin_font_board_tiny =
00145     gc_skin_get_font_default("gcompris/board/tiny", FONT_BOARD_TINY);
00146   gc_skin_font_board_small =
00147     gc_skin_get_font_default("gcompris/board/small", FONT_BOARD_SMALL);
00148   gc_skin_font_board_medium =
00149     gc_skin_get_font_default("gcompris/board/medium", FONT_BOARD_MEDIUM);
00150   gc_skin_font_board_big =
00151     gc_skin_get_font_default("gcompris/board/big", FONT_BOARD_BIG);
00152   gc_skin_font_board_big_bold =
00153     gc_skin_get_font_default("gcompris/board/big bold", FONT_BOARD_BIG_BOLD);
00154   gc_skin_font_board_fixed =
00155     gc_skin_get_font_default("gcompris/board/fixed", FONT_BOARD_FIXED);
00156   gc_skin_font_board_title =
00157     gc_skin_get_font_default("gcompris/board/title", FONT_BOARD_TITLE);
00158   gc_skin_font_board_title_bold =
00159     gc_skin_get_font_default("gcompris/board/title bold", FONT_BOARD_TITLE_BOLD);
00160   gc_skin_font_board_huge =
00161     gc_skin_get_font_default("gcompris/board/huge", FONT_BOARD_HUGE);
00162   gc_skin_font_board_huge_bold =
00163     gc_skin_get_font_default("gcompris/board/huge bold", FONT_BOARD_HUGE_BOLD);
00164 }
00165 
00166 /*
00167  * Convert from string a color expressed in the form 0xRRGGBBAA
00168  * to a unsigned 32 bit integer.
00169  */
00170 gboolean gc_skin_str_to_color(gchar* data, guint32* color){
00171   char c;
00172   int i;
00173   int n = 32;
00174   guint32 result=0;
00175 
00176   if(strlen(data)<10)
00177     return FALSE;
00178 
00179   for(i=0; i<8;i++){
00180     c = data[i+2];
00181     n -= 4;
00182     switch(c){
00183     case '0':
00184       break;
00185     case '1':
00186       result+=(1<<n);
00187       break;
00188     case '2':
00189       result+=(2<<n);
00190       break;
00191     case '3':
00192       result+=(3<<n);
00193       break;
00194     case '4':
00195       result+=(4<<n);
00196       break;
00197     case '5':
00198       result+=(5<<n);
00199       break;
00200     case '6':
00201       result+=(6<<n);
00202       break;
00203     case '7':
00204       result+=(7<<n);
00205       break;
00206     case '8':
00207       result+=(8<<n);
00208       break;
00209     case '9':
00210       result+=(9<<n);
00211       break;
00212     case 'a':
00213     case 'A':
00214       result+=(10<<n);
00215       break;
00216     case 'b':
00217     case 'B':
00218       result+=(11<<n);
00219       break;
00220     case 'c':
00221     case 'C':
00222       result+=(12<<n);
00223       break;
00224     case 'd':
00225     case 'D':
00226       result+=(13<<n);
00227       break;
00228     case 'e':
00229     case 'E':
00230       result+=(14<<n);
00231       break;
00232     case 'f':
00233     case 'F':
00234       result+=(15<<n);
00235       break;
00236     default:
00237       return FALSE;
00238     }
00239   }
00240   *color = result;
00241   return TRUE;
00242 }
00243 
00244 
00245 /*
00246  * Parse a skin.xml file located in the skin directory
00247  * and load the skin properties into memory
00248  */
00249 static void
00250 skin_xml_load (gchar* skin)
00251 {
00252   gchar* xmlfilename;
00253   xmlDocPtr xmldoc;
00254   xmlNodePtr skinNode;
00255   xmlNodePtr node;
00256   gchar* key;
00257   gchar* data;
00258   guint32 color;
00259 
00260   g_return_if_fail(skin!=NULL);
00261 
00262   xmlfilename = \
00263     gc_file_find_absolute("skins/%s/skin.xml",
00264                                 skin,
00265                                 NULL);
00266 
00267   /* if the file doesn't exist */
00268   if(!xmlfilename)
00269     {
00270       g_warning("Couldn't find skin file %s !", skin);
00271       return;
00272     }
00273 
00274   xmldoc = gc_net_load_xml(xmlfilename);
00275   g_free(xmlfilename);
00276 
00277   if(!xmldoc)
00278     return;
00279 
00280   if(/* if there is no root element */
00281      !xmldoc->children ||
00282      /* if it doesn't have a name */
00283      !xmldoc->children->name ||
00284      /* if it isn't a GCompris node */
00285      g_strcasecmp((gchar *)xmldoc->children->name, "GCompris")!=0) {
00286     g_warning("No Gcompris node");
00287     xmlFreeDoc(xmldoc);
00288     return;
00289   }
00290 
00291   skinNode = xmldoc->children->children;
00292   while((skinNode!=NULL)&&(skinNode->type!=XML_ELEMENT_NODE))
00293     skinNode = skinNode->next;
00294 
00295   if((skinNode==NULL)||
00296      g_strcasecmp((gchar *)skinNode->name, "Skin")!=0) {
00297     g_warning("No Skin node %s", xmldoc->children->children->name);
00298     xmlFreeDoc(xmldoc);
00299     return;
00300   }
00301 
00302   node = skinNode->children;
00303   while(node !=NULL)
00304     {
00305       if(g_strcasecmp((gchar *)node->name, "color")==0){
00306        key = (gchar *)xmlGetProp(node,  BAD_CAST "id");
00307        data =(gchar *) xmlGetProp(node,  BAD_CAST "rgba");
00308        if((key!=NULL)&&(data!=NULL)){
00309          if(gc_skin_str_to_color(data, &color)){
00310            g_hash_table_insert(gc_skin_colors, key, GUINT_TO_POINTER(color));
00311          } else {
00312            if(key!=NULL) g_free(key);
00313          }
00314        }
00315        if(data!=NULL) g_free(data);
00316       }
00317       else if(g_strcasecmp((gchar *)node->name, "font")==0){
00318        key = (gchar *)xmlGetProp(node,  BAD_CAST "id");
00319        data = (gchar *)xmlGetProp(node,  BAD_CAST "name");
00320        if((key!=NULL)&&(data!=NULL)){
00321          g_hash_table_insert(gc_skin_fonts, key, data);
00322        } else {
00323          if(key!=NULL) g_free(key);
00324          if(data!=NULL) g_free(data);
00325        }
00326       }
00327       else if(g_strcasecmp((gchar *)node->name, "number")==0){
00328        key = (gchar *)xmlGetProp(node, BAD_CAST "id");
00329        data = (gchar *)xmlGetProp(node, BAD_CAST "value");
00330        if((key!=NULL)&&(data!=NULL)){
00331          int number = atoi(data);
00332          g_hash_table_insert(gc_skin_numbers, key, GUINT_TO_POINTER(number));
00333          g_free(data);
00334        } else {
00335          if(key!=NULL) g_free(key);
00336          if(data!=NULL) g_free(data);
00337        }
00338       }
00339       node = node->next;
00340     }
00341 
00342   xmlFreeDoc(xmldoc);
00343 }
00344 
00345 /*
00346  * Parse the default skin.xml file and the one located in the skin
00347  * directory then load all skins properties into memory
00348  */
00349 void
00350 gc_skin_load (gchar* skin)
00351 {
00352 
00353   if(skin==NULL)
00354     return;
00355 
00356   gc_skin_free();
00357 
00358   gc_skin_fonts = g_hash_table_new_full(g_str_hash, g_str_equal,
00359                                          gc_skin_free_string,
00360                                          gc_skin_free_string);
00361   gc_skin_colors = g_hash_table_new_full(g_str_hash, g_str_equal,
00362                                          gc_skin_free_string,
00363                                          NULL);
00364   gc_skin_numbers = g_hash_table_new_full(g_str_hash, g_str_equal,
00365                                          gc_skin_free_string,
00366                                          NULL);
00367   skin_xml_load(DEFAULT_SKIN);
00368   if(strcmp(skin,DEFAULT_SKIN)!=0)
00369     skin_xml_load(skin);
00370 
00371   gc_skin_setup_vars();
00372 }
00373 
00374 /*
00375  * Free the memory used to store the skin properties.
00376  */
00377 void
00378 gc_skin_free (void)
00379 {
00380   if(gc_skin_fonts!=NULL)
00381     g_hash_table_destroy(gc_skin_fonts);
00382 
00383   if(gc_skin_colors!=NULL)
00384     g_hash_table_destroy(gc_skin_colors);
00385 
00386   if(gc_skin_numbers!= NULL)
00387       g_hash_table_destroy(gc_skin_numbers);
00388 }
00389 
00390 /*
00391  * Get the skin color associated to the id
00392  */
00393 guint32
00394 gc_skin_get_color_default(gchar* id, guint32 def)
00395 {
00396   gpointer result;
00397   result = g_hash_table_lookup(gc_skin_colors, (gpointer)id);
00398   if(result!=NULL)
00399     return GPOINTER_TO_UINT(result);
00400   return def;
00401 }
00402 
00403 /*
00404  * Get the skin gdkcolor associated to the id
00405  *
00406  * The color is returned in the given gdkcolor
00407  */
00408 void
00409 gc_skin_get_gdkcolor_default(gchar* id, guint32 def, GdkColor *gdkcolor)
00410 {
00411   gchar *tmp;
00412   guint32 color;
00413 
00414   color = gc_skin_get_color_default(id, def);
00415 
00416   tmp = g_strdup_printf("#%06X", gc_skin_get_color(id) >> 8);
00417   gdk_color_parse(tmp, gdkcolor);
00418   g_free(tmp);
00419 }
00420 
00421 /*
00422  * Get the skin font name associated to the id
00423  */
00424 gchar*
00425 gc_skin_get_font_default(gchar* id, gchar* def)
00426 {
00427   gpointer result;
00428   result = g_hash_table_lookup(gc_skin_fonts, (gpointer)id);
00429   if(result!=NULL)
00430     return (gchar*)result;
00431   return def;
00432 }
00433 
00434 /*
00435  * Get the skin 'number' associated to the id
00436  */
00437 guint32
00438 gc_skin_get_number_default(gchar* id, guint32 def)
00439 {
00440   gpointer result;
00441   result = g_hash_table_lookup(gc_skin_numbers, (gpointer)id);
00442   if(result!=NULL)
00443     return GPOINTER_TO_UINT(result);
00444   return def;
00445 }