1 /*
2   XBubble - init.c
3 
4   Copyright (C) 2002  Ivan Djelic <ivan@savannah.gnu.org>
5 
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10 
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <limits.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <math.h>
27 #include <X11/Xlib.h>
28 #include <dirent.h>
29 
30 #include "setting.h"
31 #include "cell.h"
32 #include "rgba.h"
33 #include "dialog.h"
34 #include "frame.h"
35 #include "bubble.h"
36 #include "board.h"
37 #include "gettext.h"
38 
39 extern Display *display;
40 extern Visual *visual;
41 extern Window root;
42 extern Window win;
43 extern int screen;
44 extern int depth;
45 
46 extern Colormap colormap;
47 
48 extern char * data_dir;
49 extern char * theme;
50 extern int scale;
51 extern int win_width;
52 extern int win_height;
53 
54 extern int nb_levels;
55 extern int level[MAX_NB_LEVELS][NB_CELLS];
56 
57 XFontStruct *title_font;
58 XFontStruct *dialog_font;
59 XFontStruct *menu_font;
60 GC dialog_gc;
61 GC dialog_text_gc;
62 GC menu_gc;
63 GC selected_gc;
64 Pixmap win_bg;
65 Pixmap board_decoration;
66 Pixmap board_decoration_mask;
67 Pixmap cup_on;
68 Pixmap cup_off;
69 Pixmap cup_on_mask;
70 Pixmap cup_off_mask;
71 
72 Set alert_animation;
73 Set canon_animation;
74 Set countdown_animation;
75 Set bubble_animation[NB_COLORS][NB_BUBBLE_STATES];
76 char *game_fonts[] = FONTS;
77 
78 int titlefont_color[3] = TITLEFONT_COLOR;
79 int menufont_color[3] = MENUFONT_COLOR;
80 int menufont_selected_color[3] = MENUFONT_SELECTED_COLOR;
81 int notitle = 0;
82 
data_file(char * file,int themed)83 char * data_file( char * file, int themed ) {
84   int path_max;
85   int theme_len;
86   char * abs_data_dir;
87   static int offset = 0;
88   static char buffer[1024];
89   if ( ! offset ) {
90 #ifdef PATH_MAX
91     path_max = PATH_MAX;
92 #else
93     path_max = pathconf (path, _PC_PATH_MAX);
94     if (path_max <= 0)
95       path_max = 4096;
96 #endif
97     abs_data_dir = (char *) xmalloc( path_max * sizeof(char));
98     realpath( data_dir, abs_data_dir );
99     offset = strlen(abs_data_dir);
100     if ( offset > 1024-128 )
101       offset = 1024-128;
102     strncpy( buffer, abs_data_dir, offset );
103     buffer[offset++] = '/';
104     buffer[1023] = '\0';
105     free( abs_data_dir );
106   }
107   if (themed) {
108     theme_len=strlen(theme);
109     strncpy( buffer + offset, "themes/", 126);
110     strncpy( buffer + offset + 7, theme, 119);
111     strncpy( buffer + offset + theme_len + 7, "/", 119 - theme_len);
112     strncpy( buffer + offset + theme_len + 8, file, 118 - theme_len);
113   } else {
114     strncpy( buffer + offset, file, 126);
115   }
116   return buffer;
117 }
118 
119 
load_levels(char * file)120 void load_levels( char * file ) {
121   FILE *fd;
122   char line[128];
123   unsigned char r[8];
124   int i, cell = 0;
125   int line_counter = 0;
126   int long_row = 1;
127   int color, parse_error = 0;
128 
129   nb_levels = 0;
130   file = data_file(file, 0);
131 
132   fd = fopen( file, "r" );
133   if ( fd == NULL ) {
134     warn( _("cannot open levels file %s."), file);
135     return;
136   }
137   while (( fgets( line, 128, fd ) != NULL )&&( ! parse_error )) {
138     line_counter++;
139     if (( isalnum(line[0]) )||( line[0] == '-' )||( line[0] == ' ' )) {
140       /* parse row */
141       if ( long_row )
142 	parse_error = ( sscanf( line, "%c   %c   %c   %c   %c   %c   %c   %c",
143 				r, r+1, r+2, r+3, r+4, r+5, r+6, r+7 ) != 8);
144       else
145 	parse_error = ( sscanf( line, "  %c   %c   %c   %c   %c   %c   %c",
146 				r+1, r+2, r+3, r+4, r+5, r+6, r+7 ) != 7 );
147       if ( ! parse_error ) {
148 	for ( i = 0; i < 8; i++ ) {
149 	  switch( r[i] ) {
150 	  default:
151 	  /* the shift in values read and stored comes from the compatibility with fb */
152 	  case '-': color = 0; break;
153 	  case '0': color = 1; break;
154 	  case '1': color = 2; break;
155 	  case '2': color = 3; break;
156 	  case '3': color = 4; break;
157 	  case '4': color = 5; break;
158 	  case '5': color = 6; break;
159 	  case '6': color = 7; break;
160 	  case '7': color = 8; break;
161 	  }
162 	  level[nb_levels][cell++] = color;
163 	}
164 	long_row = 1 - long_row;
165       }
166       else
167 	warn( _("parse error in file %s at line %d."), file, line_counter );
168     }
169     if ( cell >= (ROWS-1)*8 ) {
170       nb_levels++;
171       cell = 0;
172       long_row = 1;
173     }
174     if ( nb_levels >= MAX_NB_LEVELS ) {
175       warn( _("too many levels in file %s."), file );
176       break;
177     }
178   }
179 }
180 
init_display(char * display_name)181 void init_display( char * display_name ) {
182   int i;
183   XColor colors[256];
184   display = XOpenDisplay( display_name );
185   if ( display == NULL )
186     fail( _("cannot open display.") );
187   screen = DefaultScreen( display);
188   visual = DefaultVisual( display, screen);
189   root = RootWindow( display, screen);
190   depth = DefaultDepth( display, screen);
191   if ( depth < 8 ) {
192     XCloseDisplay(display);
193     fail( _("sorry, your display color depth is not supported.") );
194   }
195   if ( depth == 8 ) { /* allocate our own RRRGGGBB palette */
196     for ( i = 0; i < 256; i++ ) {
197       colors[i].pixel = i;
198       colors[i].red =   (( i & 0xe0 ) << 8 );
199       colors[i].green = (( i & 0x1c ) << 11 );
200       colors[i].blue =  (( i & 0x03 ) << 14 );
201       colors[i].flags = DoRed | DoGreen | DoBlue;
202     }
203     colormap = XCreateColormap( display, root, visual, AllocAll );
204     XStoreColors( display, colormap, colors, 256 );
205   }
206 }
207 
add_font_path(char * path)208 void add_font_path( char * path ) {
209   int i;
210   int npaths;
211   char ** fontpath;
212   char ** new_fontpath;
213 
214   fontpath = XGetFontPath( display, &npaths );
215   if ( fontpath != NULL ) {
216     /* check if path is already present */
217     for ( i = 0; i < npaths; i++ )
218       if ( strncmp( path, fontpath[i], strlen(path) ) == 0 ) {
219 	XFreeFontPath(fontpath);
220 	return;
221       }
222     new_fontpath = (char **) xmalloc( sizeof(char *)*( npaths + 1 ));
223     memcpy( new_fontpath, fontpath, npaths*sizeof(char *));
224     new_fontpath[npaths] = path;
225     XSetFontPath( display, new_fontpath, npaths+1 );
226     XFreeFontPath(fontpath);
227     free(new_fontpath);
228   }
229 }
230 
load_font(int pixel_size)231 XFontStruct * load_font( int pixel_size ) {
232   XFontStruct * xfont;
233   char name[128];
234   int i;
235   static int added_font_path = 0;
236 
237   /* try to load each font in turn */
238   for ( i = 0; game_fonts[i] != NULL; i++ ) {
239     sprintf( name, game_fonts[i], pixel_size );
240     xfont = XLoadQueryFont( display, name );
241     if ( xfont != NULL )
242       return xfont;
243   }
244   /* let's see if we can supply a font */
245   if ( ! added_font_path ) {
246     add_font_path(data_file("",0));
247     added_font_path = 1;
248   }
249   sprintf( name, SUPPLIED_FONT, pixel_size );
250   xfont = XLoadQueryFont( display, name );
251   if ( xfont != NULL )
252     return xfont;
253 
254   /* at least we should have the "fixed" font ... uurgh */
255   xfont = XLoadQueryFont( display, "fixed" );
256   if ( xfont == NULL )
257     fail( _("couldn't load any font !") );
258   return xfont;
259 }
260 
create_copy_gc()261 static GC create_copy_gc() {
262   XGCValues gcv;
263   unsigned long gcm;
264   gcm = GCFunction | GCGraphicsExposures;
265   gcv.graphics_exposures = False;
266   gcv.function = GXcopy;
267   return XCreateGC( display, root, gcm, &gcv );
268 }
269 
load_frame(char * file,double zoom)270 Frame load_frame( char *file, double zoom ) {
271   Pixmap pixmap;
272   Pixmap mask;
273   Pixmap *pmask;
274   RgbaImage ri1;
275   RgbaImage ri2;
276   Frame frame = (Frame) xmalloc( sizeof( struct _Frame ));
277 
278   ri1 = create_rgba_image_from_png_file(data_file(file,1));
279 /*   ri2 = ( zoom < 1.0 )? scale_rgba_image( ri1, zoom, zoom ) : ri1; */
280   ri2 = scale_rgba_image( ri1, zoom, zoom ) ;
281   pmask = ( ri2->has_alpha )? &mask : NULL;
282   create_pixmaps_from_rgba_image( ri2, &pixmap, pmask );
283 
284   frame->width = ri2->width;
285   frame->height = ri2->height;
286   /* center sprite */
287   frame->cx = ri2->width/2;
288   frame->cy = ri2->height/2;
289   /* default frame duration = 40 ms */
290   frame->delay = 40;
291   frame->has_mask = ri2->has_alpha;
292   frame->pixmap = pixmap;
293   if ( frame->has_mask ) {
294     frame->gc = create_copy_gc();
295     /* precompute clipmask */
296     XSetClipMask( display, frame->gc, mask );
297     XFreePixmap( display, mask );
298   }
299   if ( ri1 != ri2 )
300     delete_rgba_image(ri1);
301   delete_rgba_image(ri2);
302   return frame;
303 }
304 
delete_frame(Frame frame)305 void delete_frame( Frame frame ) {
306   XFreePixmap( display, frame->pixmap);
307   if ( frame->has_mask )
308     XFreeGC( display, frame->gc );
309   free(frame);
310 }
311 
load_animation(char * filename,double zoom)312 Set load_animation( char *filename, double zoom ) {
313   Frame frame;
314   Set animation = NULL;
315   int cx;
316   int cy;
317   int delay;
318   int max_nb_frames = 0;
319   int lc = 0;
320   char line[128];
321   char framename[128];
322   FILE *fd;
323 
324   /* open animation description file */
325   fd = fopen( data_file(filename,1), "r" );
326   if ( fd == NULL )
327     fail( _("cannot open animation file %s."), data_file(filename,1) );
328 
329   /* count frames */
330   while ( fgets( line, 128, fd ) != NULL ) {
331     if ( isalnum(line[0]))
332       max_nb_frames++;
333   }
334   rewind(fd);
335   /* load frames */
336   if ( max_nb_frames > 0 ) {
337     animation = set_new(max_nb_frames);
338     while ( fgets( line, 128, fd ) != NULL ) {
339       lc++;
340       /* parse line */
341       if ( isalnum(line[0])) {
342 	if ( sscanf( line, "%127s%d%d%d", framename, &cx, &cy, &delay) == 4 ) {
343 	  frame = load_frame( framename, zoom );
344 	  set_add( animation, frame );
345 	  frame->cx = cx*zoom;
346 	  frame->cy = cy*zoom;
347 	  frame->delay = delay;
348 	}
349 	else
350 	  warn( _("error parsing line %d of file %s."), lc, filename );
351       }
352     }
353     if ( animation->size == 0 )
354       fail( _("animation %s has no valid frames."), filename );
355   }
356   fclose(fd);
357   return animation;
358 }
359 
load_scaled_image(char * file,Pixmap * pix,Pixmap * mask,double zoom)360 void load_scaled_image( char *file, Pixmap *pix, Pixmap *mask, double zoom ) {
361   RgbaImage ri1;
362   RgbaImage ri2;
363   ri1 = create_rgba_image_from_png_file(data_file(file,1));
364   ri2 = ( zoom < 1.0 )? scale_rgba_image( ri1, zoom, zoom ) : ri1;
365   create_pixmaps_from_rgba_image( ri2, pix, mask );
366   delete_rgba_image(ri1);
367   if ( ri2 != ri1 )
368     delete_rgba_image(ri2);
369 }
370 
delete_animation(Set animation)371 void delete_animation( Set animation ) {
372   int i;
373   if (animation) {
374      for ( i = 0; i < animation->size; i++ )
375        delete_frame( animation->element[i] );
376      set_free( animation );
377   }
378 }
379 
make_canon_animation(double zoom)380 void make_canon_animation( double zoom ) {
381   RgbaImage ri;
382   RgbaImage ri2;
383   Pixmap mask;
384   Frame frame;
385   int i;
386 
387   ri2 = create_rgba_image_from_png_file(data_file("canon.png",1));
388   ri2->hotx = CANON_CX;
389   ri2->hoty = CANON_CY;
390   ri = scale_rgba_image( ri2, zoom, zoom );
391   delete_rgba_image(ri2);
392 
393   canon_animation = set_new( NB_ANGLES );
394 
395   for ( i = -CANON_ANGLE_MAX; i <= CANON_ANGLE_MAX; i++ ) {
396     frame = (Frame) xmalloc( sizeof( struct _Frame ));
397     ri2 = rotate_rgba_image( ri, -i*ANGLE_STEP, True );
398     create_pixmaps_from_rgba_image( ri2, &frame->pixmap, &mask );
399     frame->width = ri2->width;
400     frame->height = ri2->height;
401     frame->cx = ri2->hotx;
402     frame->cy = ri2->hoty;
403     frame->delay = 0;
404     frame->has_mask = ri2->has_alpha;
405     if ( frame->has_mask ) {
406       frame->gc = create_copy_gc();
407       /* precompute clipmask */
408       XSetClipMask( display, frame->gc, mask );
409       XFreePixmap( display, mask );
410     }
411     delete_rgba_image(ri2);
412     set_add( canon_animation, frame );
413   }
414   delete_rgba_image(ri);
415 }
416 
417 /* Determine whether it is a valid bubble name or not.
418    The following Naming convention is used :
419    Bubble_<COLOR>_<STATE>_<num>.png
420 */
parse_bubble_name(const char * name,int * color_val,int * state_val)421 int parse_bubble_name(const char *name,int *color_val, int *state_val)
422 {
423   char *copy = NULL, *copy_orig = NULL;
424   char *token = NULL;
425   int color,state;
426   int return_val = 0;
427 
428   copy = copy_orig = calloc(strlen(name) + 1, sizeof(char));
429   strcpy(copy,name);
430   token = strtok(copy,"_");
431 
432   if(strcmp(token,"Bubble")==0) { /* Let's determine the color */
433     token = strtok(NULL,"_");
434 
435     for ( color = 0; color < NB_COLORS; color++ ) {
436       if(strcmp(name_color_get(color),token)==0) {
437 	break;
438       }
439     }
440     if(color==NB_COLORS) {
441       warn( _("%s : %s is not a valid color."), name, token );
442     } else { /* Let's determine the state now */
443       *color_val = color;
444 
445       token = strtok(NULL,"_");
446       for ( state = 0; state < NB_BUBBLE_STATES; state++ ) {
447 	if(strcmp(name_state_get(state),token)==0) {
448 	  break;
449 	}
450       }
451       if((state == NB_BUBBLE_STATES) && (strcmp(DEFAULT_STATE_NAME,token)!=0)) {
452 	warn( _("%s : %s is not a valid state."), name, token );
453       } else {
454 	return_val = 1;
455 	*state_val = ((state==NB_BUBBLE_STATES)?DEFAULT_STATE:state);
456       }
457     }
458   }
459   free(copy_orig);
460   return return_val;
461 }
462 
diren_select_bubbles(struct dirent * d)463 int diren_select_bubbles (struct dirent *d) {
464   int color;
465   int state;
466 
467   /* Check whether this is a .png file or not */
468   if(strcmp(d->d_name + strlen(d->d_name) - 4,".png")!=0) {
469     return 0;
470   }
471   return(parse_bubble_name(d->d_name,&color,&state));
472 }
473 
load_animations(double zoom)474 void load_animations( double zoom ) {
475   int color=-1;
476   int state=-1;
477   int bubble_animation_size[NB_COLORS][NB_BUBBLE_STATES];
478   Set default_animation[NB_COLORS];
479   int default_animation_size[NB_COLORS];
480 
481   struct dirent **namelist = NULL;
482   int n = 0;
483   int i;
484   char *dir = NULL;
485 
486   alert_animation = load_animation( "frame_light.txt", zoom );
487   countdown_animation = load_animation( "countdown.txt", zoom );
488 
489   for ( color = 0; color < NB_COLORS; color++ ) {
490     for ( state = 0; state < NB_BUBBLE_STATES; state++ ) {
491       bubble_animation[color][state] = NULL;
492       bubble_animation_size[color][state] = 0;
493     }
494   }
495 
496   for ( color = 0; color < NB_COLORS; color++ ) {
497       default_animation[color] = NULL;
498       default_animation_size[color] = 0;
499   }
500 
501   color=state=-1;
502 
503   /* bubble animation */
504   dir = data_file("./",1);
505 
506   n = scandir(dir, &namelist, diren_select_bubbles , alphasort);
507   if (n < 0) fail(_("Error while scanning %s"),dir);
508   for(i=0; i<n; i++) {
509     parse_bubble_name(namelist[i]->d_name,&color,&state);
510     if(state!=DEFAULT_STATE) {
511       bubble_animation_size[color][state]++;
512     } else {
513       default_animation_size[color]++;
514     }
515   }
516 
517   for ( color = 0; color < NB_COLORS; color++ ) {
518     if(default_animation_size[color]) {
519       default_animation[color]= set_new(default_animation_size[color]);
520     }
521     for ( state = 0; state < NB_BUBBLE_STATES; state++ ) {
522       if(bubble_animation_size[color][state]==0) {
523 	bubble_animation[color][state] = default_animation[color];
524       } else {
525 	bubble_animation[color][state] = set_new(bubble_animation_size[color][state]);
526       }
527     }
528   }
529 
530   for(i=0; i<n; i++) {
531     color = -1;
532     state = -1;
533     parse_bubble_name(namelist[i]->d_name,&color,&state);
534     if(state!=DEFAULT_STATE) {
535       set_add( bubble_animation[color][state],
536 	       load_frame(namelist[i]->d_name, zoom));
537     } else {
538       set_add( default_animation[color],
539 	       load_frame(namelist[i]->d_name, zoom));
540     }
541   }
542 
543   for ( color = 0; color < NB_COLORS; color++ ) {
544     for ( state = 0; state < NB_BUBBLE_STATES; state++ ) {
545       if(bubble_animation[color][state]==NULL) {
546 	fail(_("Badly formed theme : no image for %s bubbles in state %s"),
547 	     name_color_get(color),name_state_get(state));
548       }
549     }
550   }
551   for(i=0; i<n; i++)
552     free(namelist[i]);
553   free(namelist);
554 }
555 
put_pixmap(Pixmap dest_pixmap,Pixmap dest_mask,Pixmap src_pixmap,Pixmap src_mask,int x,int y,int w,int h,int dx,int dy)556 void put_pixmap( Pixmap dest_pixmap,
557 		 Pixmap dest_mask,
558 		 Pixmap src_pixmap,
559 		 Pixmap src_mask,
560 		 int x, int y, int w, int h, int dx, int dy ) {
561   GC gc;
562   GC gc_mask;
563   XGCValues gcv;
564   unsigned long gcm;
565   gcm = GCFunction | GCGraphicsExposures;
566   gcv.graphics_exposures = False;
567   gcv.function = GXcopy;
568   gc = XCreateGC( display, root, gcm, &gcv );
569   gcv.function = GXor;
570   gc_mask = XCreateGC( display, dest_mask, gcm, &gcv );
571   XSetClipMask( display, gc, src_mask );
572   XSetClipOrigin( display, gc, dx, dy );
573   XCopyArea( display, src_pixmap, dest_pixmap, gc, x, y, w, h, dx, dy );
574   if ( src_mask != None )
575     XCopyArea( display, src_mask, dest_mask, gc_mask, x, y, w, h, dx, dy );
576   else {
577     XSetFillStyle( display, gc_mask, FillSolid );
578     XFillRectangle( display, dest_mask, gc_mask, dx, dy, w, h );
579   }
580   XFreeGC( display, gc );
581   XFreeGC( display, gc_mask );
582 }
583 
load_images(double zoom)584 void load_images( double zoom ) {
585   GC gc;
586   GC gc_mask;
587   int x;
588   int y;
589   unsigned int width;
590   unsigned int height;
591   unsigned int d;
592   Window w;
593   Frame frame;
594   Pixmap tile;
595   Pixmap tile_mask;
596   Pixmap side;
597   Pixmap side_mask;
598   Pixmap tee;
599   Pixmap tee_mask;
600   Pixmap bottom;
601   Pixmap bottom_mask;
602   Pixmap bar;
603   XGCValues gcv;
604   unsigned long gcm;
605   gcm = GCFunction | GCGraphicsExposures;
606   gcv.graphics_exposures = False;
607   gcv.function = GXcopy;
608 
609   load_scaled_image( "blue_bg.png", &tile, &tile_mask, zoom );
610   load_scaled_image( "side.png", &side, &side_mask, zoom );
611   load_scaled_image( "bar.png", &bar, NULL, zoom );
612   load_scaled_image( "tee.png", &tee, &tee_mask, zoom );
613   load_scaled_image( "bottom.png", &bottom, &bottom_mask, zoom );
614   load_scaled_image( "cup_on.png", &cup_on, &cup_on_mask, zoom);
615   load_scaled_image( "cup_off.png", &cup_off, &cup_off_mask, zoom);
616 
617   width = board_win_width(scale);
618   height = board_win_height(scale);
619 
620   /* make board background decoration */
621   board_decoration = XCreatePixmap( display, root, width, height, depth );
622   board_decoration_mask = XCreatePixmap( display, root, width, height, 1);
623   gc = XCreateGC( display, root, gcm, &gcv );
624   gc_mask = XCreateGC( display, board_decoration_mask, gcm, &gcv );
625 
626   /* draw background tile */
627   XSetFillStyle( display, gc, FillTiled );
628   XSetTile( display, gc, tile );
629   XFillRectangle( display, board_decoration, gc, 0, 0, width, height);
630   XSetFillStyle( display, gc_mask, FillTiled );
631   XSetTile( display, gc_mask, tile_mask );
632   XFillRectangle( display, board_decoration_mask, gc_mask, 0, 0, width,height);
633 
634   /* left side */
635   put_pixmap( board_decoration, board_decoration_mask, side, side_mask,
636 	      0, 0, scale_x( 0, scale), height, 0, 0 );
637   /* right side */
638   put_pixmap( board_decoration, board_decoration_mask, side, side_mask,
639 	      0, 0, scale_x( 0, scale), height, width - scale_x(0,scale), 0 );
640 
641   /* bar */
642   x = scale_x( 0, scale );
643   y = scale_y( (ROWS-1)*ROW_HEIGHT, scale );
644   width = scale_x( BOARD_WIDTH, scale ) - x;
645   height = 20*scale/MAX_SCALE;
646   XSetTile( display, gc, bar );
647   XSetForeground( display, gc_mask, WhitePixel(display, root));
648   XSetFillStyle( display, gc_mask, FillSolid );
649   XSetClipMask( display, gc, None );
650   XSetClipOrigin( display, gc, 0, 0 );
651   XFillRectangle( display, board_decoration, gc, x, y, width, height );
652   XFillRectangle( display, board_decoration_mask, gc_mask, x, y, width,height);
653 
654   /* add bottom */
655   XGetGeometry( display, bottom, &w, &x, &y, &width, &height, &d, &d );
656   x = ( board_win_width(scale) - width )/2;
657   y = board_win_height(scale) - height;
658   put_pixmap( board_decoration, board_decoration_mask, bottom, bottom_mask,
659 	      0, 0, width, height, x, y );
660   /* add tee */
661   XGetGeometry( display, tee, &w, &x, &y, &width, &height, &d, &d );
662   x = scale_x( 1.0, scale ) - width/2;
663   y = board_win_height(scale) - height;
664   put_pixmap( board_decoration, board_decoration_mask, tee, tee_mask,
665 	      0, 0, width, height, x, y );
666   /* add top */
667   frame = alert_animation->element[0];
668   XGetGeometry( display, frame->pixmap, &w, &x, &y, &width, &height, &d, &d );
669   x = ( board_win_width(scale) - width )/2;
670   put_pixmap( board_decoration, board_decoration_mask,
671 	      frame->pixmap, None,
672 	      0, 0, frame->width, frame->height, x, 0 );
673 
674   /* cleanup */
675   XFreeGC( display, gc );
676   XFreeGC( display, gc_mask );
677   XFreePixmap( display, bar );
678   XFreePixmap( display, tile );
679   XFreePixmap( display, tile_mask );
680   XFreePixmap( display, side );
681   XFreePixmap( display, side_mask );
682   XFreePixmap( display, bottom );
683   XFreePixmap( display, bottom_mask );
684   XFreePixmap( display, tee );
685   XFreePixmap( display, tee_mask );
686 }
687 
init_gcs()688 void init_gcs() {
689   /* load dialog font */
690   dialog_font = load_font( 3*scale/2 );
691   /* yellow for hilighting menu selection */
692   selected_gc = create_copy_gc();
693   XSetFont( display, selected_gc, menu_font->fid );
694   XSetForeground( display, selected_gc, get_pixel( menufont_selected_color[0],
695 						   menufont_selected_color[1],
696 						   menufont_selected_color[2] ));
697   /* grey for menu items */
698   menu_gc = create_copy_gc();
699   XSetFont( display, menu_gc, menu_font->fid );
700   XSetForeground( display, menu_gc, get_pixel( menufont_color[0], menufont_color[1],
701 				    menufont_color[2] ));
702 }
703 
cleanup_graphics()704 void cleanup_graphics() {
705   int color;
706   delete_animation( alert_animation );
707   delete_animation( canon_animation );
708   delete_animation( countdown_animation );
709   /* FIXME: cleanup animations properly !
710     delete_frame( bubble_animation[0][DEAD]->element[1] );
711    */
712   for ( color = 0; color < NB_COLORS; color++ ) {
713     delete_animation( bubble_animation[color][STUCK] );
714     delete_animation( bubble_animation[color][EXPLODING] );
715     delete_animation( bubble_animation[color][DEAD] );
716   }
717   XFreeGC( display, dialog_gc );
718   XFreeGC( display, dialog_text_gc );
719   XFreeGC( display, menu_gc );
720   XFreeGC( display, selected_gc );
721   XFreePixmap( display, win_bg );
722   XFreePixmap( display, board_decoration );
723   XFreePixmap( display, board_decoration_mask );
724   XFreePixmap( display, cup_on );
725   XFreePixmap( display, cup_off );
726   XFreePixmap( display, cup_on_mask );
727   XFreePixmap( display, cup_off_mask );
728   XFreeFont( display, title_font );
729   XFreeFont( display, dialog_font );
730   XFreeFont( display, menu_font );
731 }
732 
splash_screen(double zoom)733 void splash_screen( double zoom ) {
734   Window splash1=(Window)NULL;
735   Window splash2;
736   int height1;
737   int height2;
738   char * title = "XBubble";
739   char * subtitle = _("Loading graphics ...");
740 
741   char *config_file = "config.txt";
742   FILE *fd = NULL ;
743   char line[128];
744   char *copy = NULL;
745   char *copy_orig = NULL;
746   char *token = NULL;
747   int lc=0;
748   int value = 0;
749   int *font_color = NULL;
750   int font_nb=0;
751   double newzoom = zoom;
752   int i;
753 
754   fd = fopen( data_file(config_file,1), "r" );
755   if(fd) { /* time to change default values... */
756     while ( fgets( line, 128, fd ) != NULL ) {
757       lc++;
758       copy = copy_orig = calloc(strlen(line) + 1, sizeof(char));
759       strcpy(copy,line);
760       copy[strlen(line)-1]=' ';
761       token = strtok(copy," :");
762       if(token==NULL) continue;
763       if(strcmp(token,"BUBBLE_SIZE")==0) { /* We need to scale */
764 	token = strtok(NULL," :");
765 	if(sscanf(token,"%d",&value)!=1)
766 	  warn( _("error parsing line %d of file %s."), lc, config_file );
767 	else
768 	  newzoom = zoom * MAX_SCALE / value;
769       } else if (((strcmp(token,"TITLE_COLOR")==0)&&((font_nb=1))) ||
770 		 ((strcmp(token,"MENU_COLOR")==0)&&((font_nb=2))) ||
771 		 ((strcmp(token,"MENU_SELECTED_COLOR")==0)&&((font_nb=3)))) {
772 	switch (font_nb) {
773 	case 1: font_color = titlefont_color; break;
774 	case 2: font_color = menufont_color; break;
775 	case 3: font_color = menufont_selected_color; break;
776 	default: break;
777 	}
778 	for(i=0; i<3; i++) {
779 	  token = strtok(NULL," :");
780 	  if(sscanf(token,"%d",&font_color[i])!=1) {
781 	    warn( _("error parsing line %d of file %s."), lc, config_file );
782 	    break;
783 	  }
784 	}
785       } else if (strcmp(token,"NO_TITLE")==0) {
786 	notitle = 1;
787       } else
788 	warn( _("error parsing line %d of file %s."), lc, config_file );
789       free(copy_orig);
790     }
791     fclose(fd);
792   }
793 
794   load_scaled_image( "xbubble_bg.png", &win_bg, NULL, zoom);
795   XSetWindowBackgroundPixmap( display, win, win_bg );
796   XMapWindow( display, win );
797 
798   /* load title & menu fonts */
799   title_font = load_font( 3*scale );
800   menu_font = load_font( scale );
801   height1 = title_font->ascent + title_font->descent;
802   height2 = menu_font->ascent + menu_font->descent;
803 
804   /* make GCs */
805   dialog_gc = create_copy_gc();
806   dialog_text_gc = create_copy_gc();
807 
808   /* GC for tiling dialogs background */
809   XSetFillStyle( display, dialog_gc, FillTiled );
810   XSetTile( display, dialog_gc, win_bg );
811   if (!notitle)
812     splash1 = create_dialog( win_width/2, ( win_height - height2 )/2, gettext(title),
813 			     title_font, get_pixel( titlefont_color[0], titlefont_color[1],
814 						    titlefont_color[2] ), 0, 1.0 );
815   splash2 = create_dialog( win_width/2, ( win_height + height1 )/2, gettext(subtitle),
816 			   menu_font, get_pixel( menufont_color[0], menufont_color[1],
817 						 menufont_color[2] ), 0, 1.0 );
818   load_levels( "levels.txt" );
819   load_animations(newzoom);
820   make_canon_animation(zoom);
821   load_images(zoom);
822   init_gcs();
823 
824   if(!notitle)
825     XDestroyWindow( display, splash1 );
826   XDestroyWindow( display, splash2 );
827 }
828