This is the doxygen documentation for gtkboard.
.00001 /* This file is a part of gtkboard, a board games system. 00002 Copyright (C) 2003, Arvind Narayanan <arvindn@users.sourceforge.net> 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA 00017 00018 */ 00019 #include <time.h> 00020 #include <stdio.h> 00021 #include <sys/types.h> 00022 #include <sys/stat.h> 00023 #include <unistd.h> 00024 #include <string.h> 00025 #include <stdlib.h> 00026 00027 #include "prefs.h" 00028 #include "ui_common.h" 00029 00030 static Score scores[MAX_HIGHSCORES]; 00031 static int num_highscores = 0; 00032 static gchar *gamename; // ugly 00033 00034 SCORE_FIELD prefs_score_fields_def[] = 00035 {SCORE_FIELD_USER, SCORE_FIELD_SCORE, SCORE_FIELD_TIME, SCORE_FIELD_DATE, SCORE_FIELD_NONE}; 00036 00037 gchar* prefs_score_field_names_def[] = {"User", "Score", "Time", "Date", NULL}; 00038 00039 static void prefs_strip_special_chars (gchar *str) 00040 // $ is the field separator in our scores file 00041 // '<' and '>' are used for markup in GtkLabel 00042 { 00043 for (; *str; str++) 00044 if (*str == '$' || *str == '<' || *str == '>') 00045 *str = ' '; 00046 } 00047 00048 static gboolean prefs_create_dir (gchar *dir) 00049 { 00050 int retval; 00051 struct stat Stat; 00052 retval = stat (dir, &Stat); 00053 if (retval < 0) 00054 { 00055 // try to create the directory 00056 retval = mkdir (dir, 0755); 00057 if (retval < 0) return FALSE; 00058 } 00059 else if (!S_ISDIR (Stat.st_mode)) return FALSE; 00060 return TRUE; 00061 } 00062 00063 static gboolean prefs_first_time () 00064 { 00065 static gboolean first_time = TRUE; 00066 static gboolean status = FALSE; 00067 gchar * prefsdir, *tempstr; 00068 if (!first_time) return status; 00069 first_time = FALSE; 00070 prefsdir = g_strdup_printf ("%s/%s", getenv("HOME"), ".gtkboard"); 00071 if (!prefs_create_dir (prefsdir)) return FALSE; 00072 tempstr = g_strdup_printf ("%s/%s", prefsdir, "scores"); 00073 if (!prefs_create_dir (tempstr)) return FALSE; 00074 g_free (tempstr); 00075 tempstr = g_strdup_printf ("%s/%s", prefsdir, "prefs"); 00076 if (!prefs_create_dir (tempstr)) return FALSE; 00077 g_free (tempstr); 00078 tempstr = g_strdup_printf ("%s/%s", prefsdir, "plugins"); 00079 if (!prefs_create_dir (tempstr)) return FALSE; 00080 g_free (tempstr); 00081 g_free (prefsdir); 00082 return status = TRUE; 00083 } 00084 00085 gboolean prefs_load_scores (gchar *name) 00086 { 00087 gchar *scorefile; 00088 FILE *in; 00089 char linebuf[128]; 00090 int i; 00091 gamename = name; 00092 if (!prefs_first_time ()) return FALSE; 00093 scorefile = g_strdup_printf ("%s/%s/%s", getenv("HOME"), 00094 ".gtkboard/scores", name); 00095 in = fopen (scorefile, "r"); 00096 if (!in) 00097 { 00098 g_free (scorefile); 00099 return FALSE; 00100 } 00101 for (i=0; !feof (in) && i < MAX_HIGHSCORES;) 00102 { 00103 gchar **realline; 00104 gchar ** score_fields; 00105 /* 00106 if (fscanf (in, "%[^$]$%[^$]$%d$%d\n", 00107 scores[i].name, scores[i].score, 00108 &scores[i].time, &scores[i].date) == EOF)*/ 00109 //scanf is buggy!!! - %[] shouldn't strip leading whitespace but does 00110 if (!fgets (linebuf, 128, in)) 00111 break; 00112 realline = g_strsplit (linebuf, "#", -1); 00113 score_fields = g_strsplit (realline[0], "$", -1); 00114 if (!score_fields[0] || !score_fields[1]) 00115 { 00116 g_strfreev (realline); 00117 g_strfreev (score_fields); 00118 continue; 00119 } 00120 if (!score_fields[2] || !score_fields[3]) 00121 { 00122 sb_error ("Error loading scores file", FALSE); 00123 g_strfreev (realline); 00124 g_strfreev (score_fields); 00125 break; 00126 } 00127 strncpy (scores[i].name, score_fields[0], 31); 00128 strncpy (scores[i].score, score_fields[1], 31); 00129 scores[i].time = atoi(score_fields[2]); 00130 scores[i].date = atoi(score_fields[3]); 00131 g_strfreev (realline); 00132 g_strfreev (score_fields); 00133 i++; 00134 } 00135 num_highscores = i; 00136 fclose (in); 00137 g_free (scorefile); 00138 return TRUE; 00139 } 00140 00141 static void prefs_show_scores_real (int index) 00142 { 00143 int i, j; 00144 gchar tempstr [128], tempstr1[128]; 00145 time_t temps; 00146 GtkWidget *dialog, *okay_button, *label, *hbox, *vboxes[5]; 00147 00148 snprintf (tempstr, 128, "%s highscores - gtkboard", gamename); 00149 00150 #if GTK_MAJOR_VERSION == 1 00151 dialog = gtk_dialog_new(); 00152 gtk_window_set_title (GTK_WINDOW (dialog), tempstr); 00153 okay_button = gtk_button_new_with_label("OK"); 00154 00155 gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked", 00156 GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog); 00157 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), 00158 okay_button); 00159 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG(dialog)->vbox), 5); 00160 snprintf (tempstr, 128, "%s highscores", gamename); 00161 label = gtk_label_new (tempstr); 00162 #else 00163 dialog = gtk_dialog_new_with_buttons (tempstr, GTK_WINDOW (main_window), 00164 GTK_DIALOG_MODAL, NULL); 00165 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 100); 00166 okay_button = gtk_dialog_add_button (GTK_DIALOG (dialog), 00167 GTK_STOCK_OK, GTK_RESPONSE_NONE); 00168 g_signal_connect_swapped (GTK_OBJECT (dialog), 00169 "response", G_CALLBACK (gtk_widget_destroy), GTK_OBJECT (dialog)); 00170 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG(dialog)->vbox), 5); 00171 snprintf (tempstr, 128, "<big>%s highscores</big>", gamename); 00172 label = gtk_label_new (""); 00173 gtk_label_set_markup (GTK_LABEL (label), tempstr); 00174 #endif 00175 gtk_widget_grab_focus (okay_button); 00176 00177 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label); 00178 hbox = gtk_hbox_new (FALSE, 20); 00179 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), hbox); 00180 00181 for (i=0; i<=num_highscores; i++) 00182 { 00183 int num_score_fields; 00184 gchar *strings[10]; 00185 gboolean found = FALSE; 00186 for (j=0; !found && j < 10; j++) 00187 { 00188 switch (game_score_fields[j]) 00189 { 00190 case SCORE_FIELD_NONE: found = TRUE; break; 00191 case SCORE_FIELD_RANK: 00192 sprintf (tempstr, "%d", i); 00193 strings[j] = i ? tempstr : game_score_field_names[j]; 00194 break; 00195 case SCORE_FIELD_USER: 00196 strings[j] = i ? scores[i-1].name : game_score_field_names[j]; 00197 break; 00198 case SCORE_FIELD_SCORE: 00199 strings[j] = i ? scores[i-1].score : game_score_field_names[j]; 00200 break; 00201 case SCORE_FIELD_TIME: 00202 strings[j] = i ? sb_ftime (scores[i-1].time) : game_score_field_names[j]; 00203 break; 00204 case SCORE_FIELD_DATE: 00205 temps = scores[i-1].date; 00206 strncpy (tempstr1, ctime (&temps), 127); 00207 tempstr1 [strlen (tempstr1) - 1] = '\0'; 00208 strings[j] = i ? tempstr1 : game_score_field_names[j]; 00209 break; 00210 default: 00211 break; 00212 } 00213 } 00214 num_score_fields = j-1; 00215 for (j=0; j<num_score_fields; j++) 00216 { 00217 if (i == 0) 00218 { 00219 vboxes[j] = gtk_vbox_new (FALSE, 0); 00220 gtk_box_pack_start (GTK_BOX (hbox), vboxes[j], TRUE, TRUE, 0); 00221 } 00222 label = gtk_label_new (""); 00223 #if GTK_MAJOR_VERSION > 1 00224 gtk_label_set_selectable (GTK_LABEL (label), TRUE); 00225 if (i > 0 && i-1 == index) 00226 { 00227 gchar *tempstr = g_strdup_printf 00228 ("<span foreground=\"blue\">%s</span>", strings[j]); 00229 gtk_label_set_markup (GTK_LABEL (label), tempstr); 00230 g_free (tempstr); 00231 } 00232 else 00233 #endif 00234 gtk_label_set_text (GTK_LABEL (label), strings[j]); 00235 gtk_box_pack_start (GTK_BOX (vboxes[j]), label, FALSE, FALSE, 00236 i ? 0 : 5); 00237 } 00238 } 00239 gtk_widget_show_all (dialog); 00240 } 00241 00242 void prefs_show_scores () 00243 { 00244 if (!gamename) 00245 return; 00246 prefs_show_scores_real (-1); 00247 } 00248 00249 gboolean prefs_save_scores (gchar *name) 00250 { 00251 gchar *scorefile; 00252 FILE *out; 00253 char linebuf[128]; 00254 int i; 00255 if (!prefs_first_time ()) return FALSE; 00256 scorefile = g_strdup_printf ("%s/%s/%s", getenv("HOME"), 00257 ".gtkboard/scores", name); 00258 out = fopen (scorefile, "w"); 00259 if (!out) 00260 { 00261 gchar *tempstr; 00262 sb_error (tempstr = g_strdup_printf 00263 ("couldn't write to %s", scorefile), 00264 FALSE); 00265 g_free (tempstr); 00266 g_free (scorefile); 00267 return FALSE; 00268 } 00269 fprintf (out, "#This is the gtkboard highscores file for the game %s\n" 00270 "#The format is: name$score$time taken in ms$date (time (2))\n" 00271 "#VERSION=0.10.0\n" 00272 , gamename); 00273 for (i=0; i < num_highscores; i++) 00274 { 00275 fprintf (out, "%s$%s$%d$%d\n", 00276 scores[i].name, scores[i].score, 00277 scores[i].time, scores[i].date); 00278 } 00279 fclose (out); 00280 g_free (scorefile); 00281 gamename = NULL; 00282 return TRUE; 00283 } 00284 00285 int prefs_scorecmp_dscore (gchar *score1, int temps1, gchar* score2, int temps2) 00286 { 00287 int s1 = atoi (score1); 00288 int s2 = atoi (score2); 00289 if (s1 > s2) return 1; 00290 if (s1 < s2) return -1; 00291 if (temps1 < temps2) return 1; 00292 if (temps1 > temps2) return -1; 00293 return 0; 00294 } 00295 00296 int prefs_scorecmp_iscore (gchar *score1, int temps1, gchar* score2, int temps2) 00297 { 00298 int s1 = atoi (score1); 00299 int s2 = atoi (score2); 00300 if (s1 < s2) return 1; 00301 if (s1 > s2) return -1; 00302 if (temps1 < temps2) return 1; 00303 if (temps1 > temps2) return -1; 00304 return 0; 00305 } 00306 00307 int prefs_scorecmp_time (gchar *score1, int temps1, gchar* score2, int temps2) 00308 { 00309 if (temps1 < temps2) return 1; 00310 if (temps1 > temps2) return -1; 00311 return 0; 00312 } 00313 00314 static int highscore_temps, highscore_index, highscore_date; 00315 static gchar highscore_score[32]; 00316 00317 static void prefs_username_cb (GtkWidget *dialog, GtkEntry *entry) 00318 { 00319 int j; 00320 gchar username[32], *namep; 00321 strncpy (username, gtk_entry_get_text (entry), 31); 00322 prefs_strip_special_chars (username); 00323 for (j = num_highscores + 1; j > highscore_index; j--) 00324 { 00325 if (j >= MAX_HIGHSCORES) continue; 00326 memcpy (scores + j, scores + j - 1, sizeof (Score)); 00327 } 00328 strncpy (scores[highscore_index].name, username, 31); 00329 snprintf (scores[highscore_index].score, 32, "%d", atoi (highscore_score)); 00330 scores[highscore_index].time = highscore_temps; 00331 scores[highscore_index].date = highscore_date; 00332 if (num_highscores < MAX_HIGHSCORES) num_highscores++; 00333 gtk_widget_destroy (GTK_WIDGET (dialog)); 00334 prefs_show_scores_real (highscore_index); 00335 } 00336 00337 void prefs_show_username_dialog () 00338 { 00339 GtkWidget *dialog, *label, *hbox, *entry; 00340 gchar *title = "Enter your name - gtkboard"; 00341 00342 entry = gtk_entry_new_with_max_length (31); 00343 gtk_entry_set_text (GTK_ENTRY (entry), getenv ("USER")); 00344 gtk_widget_grab_focus (entry); 00345 00346 #if GTK_MAJOR_VERSION == 1 00347 dialog = gtk_dialog_new(); 00348 gtk_window_set_title (GTK_WINDOW (dialog), title); 00349 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (main_window)); 00350 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); 00351 gtk_signal_connect_object (GTK_OBJECT (entry), "activate", 00352 GTK_SIGNAL_FUNC (prefs_username_cb), GTK_OBJECT (dialog)); 00353 #else 00354 dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (main_window), 00355 GTK_DIALOG_MODAL, NULL); 00356 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 100); 00357 g_signal_connect_swapped (GTK_OBJECT (entry), 00358 "activate", G_CALLBACK (prefs_username_cb), GTK_OBJECT (dialog)); 00359 gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_NONE); 00360 #endif 00361 00362 label = gtk_label_new ("You've got a highscore!"); 00363 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label); 00364 hbox = gtk_hbox_new (TRUE, 0); 00365 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), hbox); 00366 label = gtk_label_new ("Enter your name"); 00367 gtk_container_add (GTK_CONTAINER (hbox), label); 00368 gtk_container_add (GTK_CONTAINER (hbox), entry); 00369 gtk_widget_show_all (dialog); 00370 #if GTK_MAJOR_VERSION > 1 00371 gtk_dialog_run (GTK_DIALOG (dialog)); 00372 prefs_username_cb (dialog, GTK_ENTRY (entry)); 00373 #endif 00374 } 00375 00376 void prefs_add_highscore (gchar *score, int temps) 00377 // the argument score is the string returned by game_who_won. We expect 00378 // it to have a substring which is an integer 00379 { 00380 int i, j; 00381 char *realscore = strpbrk (score, "0123456789"); 00382 if (!realscore) realscore = ""; 00383 if (!game_scorecmp) return; 00384 for (i=0; i<num_highscores; i++) 00385 if (game_scorecmp (realscore, temps, 00386 scores[i].score, scores[i].time) > 0) 00387 break; 00388 if (i == MAX_HIGHSCORES) return; 00389 highscore_index = i; 00390 strncpy (highscore_score, realscore, 31); 00391 prefs_strip_special_chars (highscore_score); 00392 highscore_temps = temps; 00393 highscore_date = time (0); 00394 prefs_show_username_dialog (); 00395 } 00396 00397 void prefs_zap_highscores () 00398 { 00399 gchar *tempstr; 00400 GtkWidget *dialog, *label; 00401 gint result; 00402 if (!gamename) return; 00403 #if GTK_MAJOR_VERSION == 1 00404 menu_show_dialog ("Zapped highscores", 00405 tempstr = g_strdup_printf ("Zapped %s highscores", gamename)); 00406 g_free (tempstr); 00407 #else 00408 dialog = gtk_dialog_new_with_buttons ("Zap highscores?", 00409 GTK_WINDOW (main_window), GTK_DIALOG_MODAL, 00410 GTK_STOCK_YES, GTK_RESPONSE_ACCEPT, 00411 GTK_STOCK_NO, GTK_RESPONSE_REJECT, 00412 NULL); 00413 tempstr = g_strdup_printf ( 00414 "<b>Warning</b>: This will clear your %s highscores.\n" 00415 "Your highscores in other games will be unaffected.\nProceed?", gamename); 00416 label = gtk_label_new (NULL); 00417 gtk_label_set_markup (GTK_LABEL (label), tempstr); 00418 g_free (tempstr); 00419 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label); 00420 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 100); 00421 gtk_widget_show_all (dialog); 00422 result = gtk_dialog_run (GTK_DIALOG (dialog)); 00423 gtk_widget_destroy (dialog); 00424 if (result == GTK_RESPONSE_REJECT) 00425 return; 00426 #endif 00427 num_highscores = 0; 00428 }