1 #include "config.h"
2 
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <strings.h>
7 #include <sys/param.h>
8 
9 #include <sys/stat.h>
10 #include <fts.h>
11 #include <unistd.h>
12 
13 #include <X11/Xlib.h>
14 #include <Imlib2.h>
15 
16 #include "Wlib.h"
17 #include "defs.h"
18 #include "struct.h"
19 #include "data.h"
20 
21 #include "defaults.h"
22 #include "x11window.h"
23 
24 #include "x11sprite.h"
25 
26 #define W_Void2Window(win) (((struct window *) (win)))
27 #define NoPixmapError 0
28 
29 struct S_Object
30   {
31     Drawable drawable;
32     GC      gc;
33     int     view, nviews, width, height, cloak;
34     Pixmap  image;
35     Pixmap  shape;
36   };
37 
38 #define NUM_BG_IMGS 6
39 #define NUM_PL_IMGS 11
40 
41 #define PL_PIX_UKN 0
42 #define PL_PIX_ROCK 1
43 #define PL_PIX_AGRI 2
44 #define PL_PIX_ARMY 3
45 #define PL_PIX_REPAIR 4
46 #define PL_PIX_FUEL 5
47 #define PL_PIX_IND 6
48 #define PL_PIX_FED 7
49 #define PL_PIX_ROM 8
50 #define PL_PIX_KLI 9
51 #define PL_PIX_ORI 10
52 
53 const int reremap[5] =
54 {NO_IND_PIX, NO_FED_PIX, NO_ROM_PIX,
55  NO_KLI_PIX, NO_ORI_PIX};
56 
57 static struct S_Object mplanetImg[NUM_PL_IMGS];
58 static struct S_Object shipImg[NUMTEAM + 1][NUM_TYPES];
59 static struct S_Object torpImg[NUMTEAM + 1][2];
60 static struct S_Object plasmaImg[NUMTEAM + 1][2];
61 static struct S_Object cloakImg;
62 static struct S_Object explosionImg[2];
63 
64 /*
65  * static struct S_Object planetImg[NUM_PL_IMGS];
66  * static struct S_Object shieldImg[NUM_SH_IMGS];
67  * static struct S_Object hullImg[NUM_HL_IMGS];
68  */
69 
70 static Pixmap backPix[NUM_BG_IMGS];
71 
72 extern Window W_Root;
73 extern Colormap W_Colormap;
74 extern Visual *W_Visual;
75 extern int takeNearest;
76 
77 extern Display *W_Display;
78 
79 const char teamnames[NUMTEAM + 1][4] =
80 {"Ind", "Fed", "Rom", "Kli", "Ori"};
81 
82 const char mplanetfiles[NUM_PL_IMGS][12] =
83 {"UNKN.png",
84  "ROCK.png",
85  "AGRI.png",
86  "army.png",
87  "repair.png",
88  "fuel.png",
89  "Ind.png",
90  "Fed.png",
91  "Rom.png",
92  "Kli.png",
93  "Ori.png"
94 };
95 const char shipfiles[NUM_TYPES][8] =
96 {"SC.png",
97  "DD.png",
98  "CA.png",
99  "BB.png",
100  "AS.png",
101  "SB.png",
102  "GA.png",
103  "AT.png"
104 };
105 const char torpfiles[2][14] =
106 {"torp.png", "torp_det.png"};
107 const char plasmafiles[2][16] =
108 {"plasma.png", "plasma_det.png"};
109 const char cloakfile[10] = "cloak.png";
110 const char explosionfiles[2][18] =
111 {"explosion.png", "sbexplosion.png"};
112 const char bgfiles[NUM_BG_IMGS][16] =
113 {"map_back.png",
114  "local_back.png",
115  "ghostbust.png",
116  "genocide.png",
117  "greet.png",
118  "hockey.png"
119 };
120 
121 
ReadFileToSprite(char * filename,struct S_Object * sprite,Drawable drawable)122 static int ReadFileToSprite(char *filename, struct S_Object *sprite, Drawable drawable)
123 {
124   Imlib_Image im;
125   int width, height, nviews;
126 
127   if (access(filename, R_OK) != 0) {
128     fprintf(stderr, "image %s is not readable\n", filename);
129     goto fail;
130   }
131 
132   im = imlib_load_image(filename);
133   if (!im) {
134     fprintf(stderr, "image %s failed to load\n", filename);
135     goto fail;
136   }
137 
138   imlib_context_set_display(W_Display);
139   imlib_context_set_visual(W_Visual);
140   imlib_context_set_colormap(W_Colormap);
141   imlib_context_set_image(im);
142   imlib_context_set_drawable(drawable);
143   imlib_render_pixmaps_for_whole_image(&sprite->image, &sprite->shape);
144 
145   width = imlib_image_get_width();
146   height = imlib_image_get_height();
147   nviews = height / width;
148   if (nviews * width != height) {
149     nviews = 1;
150   }
151 
152   sprite->drawable = drawable;
153   sprite->gc = XCreateGC(W_Display, sprite->image, 0, NULL);
154   sprite->view = 0;
155   sprite->nviews = nviews;
156   sprite->width = width;
157   sprite->height = height / nviews;
158   sprite->cloak = 0;
159 #ifdef DEBUG
160   fprintf(stderr, "image %s loaded, nv=%d w=%d h=%d (%d)\n", filename,
161           nviews, width, height, sprite->height);
162 #endif
163   imlib_free_image_and_decache();
164   return 0;
165 
166  fail:
167   sprite->image = NoPixmapError;
168   sprite->nviews = 1;
169   return 1;
170 }
171 
ReadFileToTile(char * filename,Pixmap * pix,Drawable drawable)172 int     ReadFileToTile(char *filename, Pixmap *pix, Drawable drawable)
173 {
174   Imlib_Image im;
175 
176   if (access(filename, R_OK) != 0) {
177     fprintf(stderr, "image %s is not readable\n", filename);
178     goto fail;
179   }
180 
181   im = imlib_load_image(filename);
182   if (!im) {
183     fprintf(stderr, "image %s failed to load\n", filename);
184     goto fail;
185   }
186 
187   imlib_context_set_display(W_Display);
188   imlib_context_set_visual(W_Visual);
189   imlib_context_set_colormap(W_Colormap);
190   imlib_context_set_image(im);
191   imlib_context_set_drawable(drawable);
192   imlib_render_pixmaps_for_whole_image(pix, NULL);
193 #ifdef DEBUG
194   fprintf(stderr, "tile %s loaded, w=%d h=%d\n", filename,
195           imlib_image_get_width(), imlib_image_get_height());
196 #endif
197   imlib_free_image_and_decache();
198   return 0;
199 
200  fail:
201   *pix = NoPixmapError;
202   return 1;
203 }
204 
205 static char pixmapDir[1024] = { '\0' };
206 
GetPixmapDir()207 static void GetPixmapDir()
208 {
209   char   *pd;
210 
211   if (pixmapDir[0] != '\0') return;
212 
213   pd = getdefault("pixmapDir");
214   if (pd != (char *) NULL)
215     strncpy(pixmapDir, pd, 1024);
216   else
217     strcpy(pixmapDir, "/usr/local/share/pixmaps/netrek-client-cow");
218 
219   if ((strcmpi(pixmapDir, "None") == 0) || (pixMissing & NO_PIXMAPS)) {
220     pixMissing = NO_IND_PIX | NO_FED_PIX | NO_ROM_PIX |
221       NO_KLI_PIX | NO_ORI_PIX | NO_WEP_PIX | NO_EXP_PIX |
222       NO_CLK_PIX | NO_MAP_PIX | NO_BG_PIX | NO_PIXMAPS;
223     fprintf(stderr, "pixmaps turned off\n");
224   } else {
225     struct stat buf;
226 
227     if ((stat(pixmapDir, &buf)) || (!(S_ISDIR(buf.st_mode)))) {
228       /* if .xtrekrc is wrong, and package default wrong, try default dir */
229       if ((stat("pixmaps", &buf)) || (!(S_ISDIR(buf.st_mode)))) {
230 	pixMissing = NO_IND_PIX | NO_FED_PIX | NO_ROM_PIX |
231 	  NO_KLI_PIX | NO_ORI_PIX | NO_WEP_PIX | NO_EXP_PIX |
232 	  NO_CLK_PIX | NO_MAP_PIX | NO_BG_PIX | NO_PIXMAPS;
233 	fprintf(stderr, "pixmaps not here\n");
234       } else {
235 	strcpy(pixmapDir, "pixmaps");
236       }
237     }
238   }
239 }
240 
GetPixmaps(Display * d,struct window * win,W_Window t,W_Window g)241 void    GetPixmaps(Display * d, struct window *win, W_Window t, W_Window g)
242 {
243   register int i, j;
244   char    buf[1024];
245   int     missing;
246 
247   Drawable tactical = W_Void2Window(t)->window;
248   Drawable galactic = W_Void2Window(g)->window;
249   W_Display = d;
250 
251   GetPixmapDir();
252 
253   for (i = 0; i < NUMTEAM + 1; i++)
254     {
255       missing = 0;
256       for (j = 0; j < NUM_TYPES; j++)
257 	{
258 	  sprintf(buf, "%s/%s/%s", pixmapDir, teamnames[i], shipfiles[j]);
259 	  missing += ReadFileToSprite(buf, &shipImg[i][j], tactical);
260 	}
261       if (missing == NUM_TYPES)
262 	{
263 	  pixMissing |= reremap[i];
264 	  if (!(pixMissing & NO_PIXMAPS))
265 	    fprintf(stderr, "type %s ship pixmaps not available\n", teamnames[i]);
266 	}
267     }
268 
269   missing = 0;
270   for (i = 0; i < NUMTEAM + 1; i++)
271     {
272       for (j = 0; j < 2; j++)
273 	{
274 	  sprintf(buf, "%s/%s/%s", pixmapDir, teamnames[i], torpfiles[j]);
275 	  missing += ReadFileToSprite(buf, &torpImg[i][j], tactical);
276 
277 	  sprintf(buf, "%s/%s/%s", pixmapDir, teamnames[i], plasmafiles[j]);
278 	  missing += ReadFileToSprite(buf, &plasmaImg[i][j], tactical);
279 	}
280     }
281   if (missing == (NUMTEAM + 1) * 4)
282     {
283       pixMissing |= NO_WEP_PIX;
284       if (!(pixMissing & NO_PIXMAPS))
285 	fprintf(stderr, "type weapon pixmaps not available\n");
286     }
287 
288   missing = 0;
289   for (i = 0; i < 2; i++)
290     {
291       sprintf(buf, "%s/Misc/%s", pixmapDir, explosionfiles[i]);
292       missing += ReadFileToSprite(buf, &explosionImg[i], tactical);
293     }
294   if (missing == 2)
295     {
296       pixMissing |= NO_EXP_PIX;
297       if (!(pixMissing & NO_PIXMAPS))
298 	fprintf(stderr, "type explosion pixmaps not available\n");
299     }
300 
301   missing = 0;
302   for (i = 0; i < NUM_PL_IMGS && !missing; i++)
303     {
304       sprintf(buf, "%s/Planets/Map/%s", pixmapDir, mplanetfiles[i]);
305       if (i == PL_PIX_AGRI && missing == 0)
306 	{
307 	  /* If the AGRI pixmap is missing, use the ROCK pixmap */
308 	  if (ReadFileToSprite(buf, &mplanetImg[i], galactic) != 0)
309 	    {
310 	      sprintf(buf, "%s/Planets/%s", pixmapDir, mplanetfiles[i - 1]);
311 	      ReadFileToSprite(buf, &mplanetImg[i], galactic);
312 	    }
313 	}
314       else
315 	missing += ReadFileToSprite(buf, &mplanetImg[i], galactic);
316     }
317   if (missing)
318     {
319       pixMissing |= NO_MAP_PIX;
320       if (!(pixMissing & NO_PIXMAPS))
321 	fprintf(stderr, "type map pixmaps not available\n");
322     }
323 
324   sprintf(buf, "%s/Misc/%s", pixmapDir, cloakfile);
325   if (ReadFileToSprite(buf, &cloakImg, tactical))
326     {
327       pixMissing |= NO_CLK_PIX;
328       if (!(pixMissing & NO_PIXMAPS))
329 	fprintf(stderr, "type cloak pixmaps not available\n");
330     }
331 
332   missing = 0;
333   for (i = 0; i < NUM_BG_IMGS; i++)
334     {
335       sprintf(buf, "%s/Misc/%s", pixmapDir, bgfiles[i]);
336       missing += ReadFileToTile(buf, &backPix[i], galactic);
337     }
338   if (missing == NUM_BG_IMGS)
339     {
340       pixMissing |= NO_BG_PIX;
341       if (!(pixMissing & NO_PIXMAPS))
342 	fprintf(stderr, "type background pixmaps not available\n");
343     }
344 
345   pixMissing &= ~NO_HALOS;
346 }
347 
348 /*************************************************************************
349  *                Now for the drawing routines                           *
350  *************************************************************************/
351 
W_DrawSprite(void * in,int x,int y,int winside)352 int     W_DrawSprite(void *in, int x, int y, int winside)
353 {
354   const int view = SCALE * winside / 2;
355   struct S_Object *sprite = (struct S_Object *) in;
356   int     dx, dy;
357 
358   if ((sprite == NULL) || (sprite->view < 0) || (sprite->view >= sprite->nviews))
359     return 0;
360 
361   if (x > view || x < -view || y > view || y < -view)
362     return 0;
363 
364   dx = x - (sprite->width) / 2;
365   dy = y - (sprite->height) / 2;
366 
367   if ((sprite->cloak > 0) && !(pixFlags & NO_CLK_PIX))
368     {
369       XSetClipMask(W_Display, sprite->gc, cloakImg.shape);
370       XSetClipOrigin(W_Display, sprite->gc,
371 		     dx, dy - cloakImg.view * (cloakImg.height));
372     }
373   else
374     {
375       XSetClipMask(W_Display, sprite->gc, sprite->shape);
376       XSetClipOrigin(W_Display, sprite->gc,
377 		     dx, dy - sprite->view * (sprite->height));
378     }
379 
380   XCopyArea(W_Display, sprite->image, sprite->drawable, sprite->gc,
381 	    0, (sprite->view) * (sprite->height),
382 	    sprite->width, sprite->height,
383 	    dx, dy);
384 
385   return (sprite->width);
386 }
387 
W_DrawSpriteAbsolute(void * in,int x,int y)388 void W_DrawSpriteAbsolute(void *in, int x, int y)
389 {
390   struct S_Object *sprite = (struct S_Object *) in;
391 
392   if (sprite == NULL)
393     return;
394 
395   XSetClipMask(W_Display, sprite->gc, sprite->shape);
396   XSetClipOrigin(W_Display, sprite->gc, x, y);
397   XCopyArea(W_Display, sprite->image, sprite->drawable, sprite->gc,
398             0, 0, sprite->width, sprite->height, x, y);
399 }
400 
W_ClearSpriteAbsolute(void * in,int x,int y)401 void W_ClearSpriteAbsolute(void *in, int x, int y)
402 {
403   struct S_Object *sprite = (struct S_Object *) in;
404 
405   if (sprite == NULL)
406     return;
407 
408   XSetClipMask(W_Display, sprite->gc, sprite->shape);
409   XSetClipOrigin(W_Display, sprite->gc, x, y);
410   XClearArea(W_Display, sprite->drawable,
411              x, y, sprite->width, sprite->height, False);
412 }
413 
S_Ship(int playerno)414 void   *S_Ship(int playerno)
415 {
416   struct S_Object *sprite;
417   struct player *this;
418 
419   if ((playerno > MAXPLAYER) || (playerno < 0))
420     return ((void *) NULL);
421 
422   this = &players[playerno];
423   sprite = &(shipImg[remap[this->p_team]][this->p_ship.s_type]);
424   sprite->cloak = 0;
425 
426   /* The following generalizes "rosette(x)" for an arbitrary number of
427      views in the image */
428 
429   sprite->view = ((((this->p_dir) + 128 / (sprite->nviews))
430 		   / (256 / (sprite->nviews))) % (sprite->nviews));
431 
432   if ((this->p_status != PALIVE) && (this->p_status != PEXPLODE))
433     {
434       return ((void *) NULL);
435     }
436   else if ((this->p_flags & PFOBSERV) && !(this->p_flags & PFPLOCK))
437     {
438       return ((void *) NULL);
439     }
440   else if ((this->p_flags & PFOBSERV) && !(this->p_flags & PFCLOAK))
441     {
442       return ((void *) NULL);
443     }
444   else if (this->p_status == PEXPLODE)
445     {
446       int     i;
447 
448       if (pixFlags & NO_EXP_PIX)
449         return ((void *) NULL);
450 
451       if (this->p_ship.s_type == STARBASE) {
452         i = this->p_explode * 5 / server_ups;
453         sprite = &explosionImg[1];
454       } else {
455         i = this->p_explode * 10 / server_ups;
456         sprite = &explosionImg[0];
457       }
458 
459       if (i >= sprite->nviews)
460 	return ((void *) NULL);
461 
462       sprite->view = i;
463       this->p_explode++;
464     }
465   else if ((this->p_flags & PFCLOAK) || (this->p_cloakphase > 0))
466     {
467       if (this->p_cloakphase == (CLOAK_PHASES - 1))
468 	{
469 	  if ((this == me) && !(pixFlags & NO_CLK_PIX))
470 	    {
471 	      sprite = &cloakImg;
472 	      sprite->view = cloakImg.nviews - 1;
473 	    }
474 	  else
475 	    {
476 	      return ((void *) NULL);
477 	    }
478 	}
479       else
480 	{
481 	  if ((CLOAK_PHASES - 2) == 0)
482 	      return ((void *) NULL);
483 	  sprite->cloak = this->p_cloakphase;
484 	  cloakImg.view = MAX(0, cloakImg.nviews - (this->p_cloakphase * (cloakImg.nviews - 1) / (CLOAK_PHASES - 2)) - 2);
485 	}
486     }
487 
488   if ((sprite->image == NoPixmapError) ||
489       (pixFlags & reremap[remap[this->p_team]]))
490     return ((void *) NULL);
491   else
492     return ((void *) sprite);
493 }
494 
S_mPlanet(int planetno)495 void   *S_mPlanet(int planetno)
496 {
497   struct S_Object *sprite;
498   struct planet *this = &planets[planetno];
499 
500   if (pixFlags & NO_MAP_PIX)
501     return ((void *) NULL);
502 
503   if ((this->pl_info & me->p_team)
504 
505 #ifdef RECORDGAME
506       || playback
507 #endif
508 
509       )
510     {
511       if ((this->pl_flags & PLAGRI) && (F_agri_pix))
512 	sprite = &mplanetImg[PL_PIX_AGRI];
513       else
514 	sprite = &mplanetImg[PL_PIX_ROCK];
515 
516     }
517   else
518     {
519       sprite = &mplanetImg[PL_PIX_UKN];
520     }
521 
522   sprite->view = 0;
523 
524   return ((void *) sprite);
525 }
526 
S_mArmy(int planetno)527 void   *S_mArmy(int planetno)
528 {
529   struct S_Object *sprite = NULL;
530   struct planet *this = &planets[planetno];
531 
532   if ((pixFlags & NO_MAP_PIX) || (showgalactic != 1))
533     return ((void *) NULL);
534 
535   if (((this->pl_info & me->p_team)
536 
537 #ifdef RECORDGAME
538        || playback
539 #endif
540 
541       ) && (this->pl_armies > 4))
542     {
543       sprite = &mplanetImg[PL_PIX_ARMY];
544       sprite->view = 0;
545     }
546 
547   return ((void *) sprite);
548 }
549 
S_mRepair(int planetno)550 void   *S_mRepair(int planetno)
551 {
552   struct S_Object *sprite = NULL;
553   struct planet *this = &planets[planetno];
554 
555   if ((pixFlags & NO_MAP_PIX) || (showgalactic != 1))
556     return ((void *) NULL);
557 
558   if (((this->pl_info & me->p_team)
559 
560 #ifdef RECORDGAME
561        || playback
562 #endif
563 
564       ) && (this->pl_flags & PLREPAIR))
565     {
566       sprite = &mplanetImg[PL_PIX_REPAIR];
567       sprite->view = 0;
568     }
569 
570   return ((void *) sprite);
571 }
572 
S_mFuel(int planetno)573 void   *S_mFuel(int planetno)
574 {
575   struct S_Object *sprite = NULL;
576   struct planet *this = &planets[planetno];
577 
578   if ((pixFlags & NO_MAP_PIX) || (showgalactic != 1))
579     return ((void *) NULL);
580 
581   if (((this->pl_info & me->p_team)
582 
583 #ifdef RECORDGAME
584        || playback
585 #endif
586 
587       ) && (this->pl_flags & PLFUEL))
588     {
589       sprite = &mplanetImg[PL_PIX_FUEL];
590       sprite->view = 0;
591     }
592 
593   return ((void *) sprite);
594 }
595 
S_mOwner(int planetno)596 void   *S_mOwner(int planetno)
597 {
598   struct S_Object *sprite = NULL;
599   struct planet *this = &planets[planetno];
600 
601   if ((pixFlags & NO_MAP_PIX) || (showgalactic != 0))
602     return ((void *) NULL);
603 
604   if ((this->pl_info & me->p_team)
605 
606 #ifdef RECORDGAME
607       || playback
608 #endif
609 
610       )
611     {
612       sprite = &mplanetImg[PL_PIX_IND + remap[this->pl_owner]];
613       sprite->view = 0;
614     }
615 
616   return ((void *) sprite);
617 }
618 
S_Torp(int torpno)619 void   *S_Torp(int torpno)
620 {
621   struct S_Object *sprite;
622   struct torp *this = &torps[torpno];
623   int numdetframes, frame;
624 
625   if (this->t_status == TEXPLODE)
626     {
627       sprite = &torpImg[remap[players[this->t_owner].p_team]][1];
628       this->t_fuse--;
629       numdetframes = NUMDETFRAMES * server_ups / 5;
630       frame = this->t_fuse * 5 / server_ups;
631       if (this->t_fuse <= 0)
632 	{
633 	  this->t_status = PTFREE;
634 	  players[this->t_owner].p_ntorp--;
635 	}
636       else if (this->t_fuse >= numdetframes)
637 	{
638 	  this->t_fuse = numdetframes - 1;
639 	}
640       else
641 	{
642 	  sprite->view = frame;
643 	}
644     }
645   else
646     {
647       sprite = &torpImg[remap[players[this->t_owner].p_team]][0];
648       sprite->view = (sprite->view + 1) % sprite->nviews;
649       // FIXME: torps rotate faster with higher client update rates
650     }
651 
652   if ((sprite->image == NoPixmapError) || (pixFlags & NO_WEP_PIX))
653     return (NULL);
654   else
655     return ((void *) sprite);
656 }
657 
S_Plasma(int plasmatorpno)658 void   *S_Plasma(int plasmatorpno)
659 {
660   struct S_Object *sprite;
661   struct plasmatorp *this = &plasmatorps[plasmatorpno];
662   int numdetframes, frame;
663 
664   if (this->pt_status == PTEXPLODE)
665     {
666       sprite = &plasmaImg[remap[players[this->pt_owner].p_team]][1];
667       this->pt_fuse--;
668       numdetframes = NUMDETFRAMES * server_ups / 5;
669       frame = this->pt_fuse * 5 / server_ups;
670       if (this->pt_fuse <= 0)
671 	{
672 	  this->pt_status = PTFREE;
673 	  players[this->pt_owner].p_nplasmatorp--;
674 	}
675       else if (this->pt_fuse >= numdetframes)
676 	{
677 	  this->pt_fuse = numdetframes - 1;
678 	}
679       else
680 	{
681 	  sprite->view = frame;
682 	}
683     }
684   else
685     {
686       sprite = &plasmaImg[remap[players[this->pt_owner].p_team]][0];
687       sprite->view = (sprite->view + 1) % sprite->nviews;
688     }
689 
690   if ((sprite->image == NoPixmapError) || (pixFlags & NO_WEP_PIX))
691     return (NULL);
692   else
693     return ((void *) sprite);
694 }
695 
W_GalacticBgd(int which)696 void    W_GalacticBgd(int which)
697 {
698   struct window *win = W_Void2Window(mapw);
699 
700   if ((backPix[which] == NoPixmapError) || (pixFlags & NO_BG_PIX))
701     W_UnTileWindow(mapw);
702   else
703     XSetWindowBackgroundPixmap(W_Display, win->window, backPix[which]);
704 
705   W_ClearWindow(mapw);
706 }
707 
W_LocalBgd(int which)708 void    W_LocalBgd(int which)
709 {
710   struct window *win = W_Void2Window(w);
711 
712   if ((backPix[which] == NoPixmapError) || (pixFlags & NO_BG_PIX))
713     W_UnTileWindow(w);
714   else
715     XSetWindowBackgroundPixmap(W_Display, win->window, backPix[which]);
716 
717   W_ClearWindow(w);
718 }
719 
W_SetBackground(W_Window w,int which)720 void    W_SetBackground(W_Window w, int which)
721 {
722   struct window *win = W_Void2Window(w);
723 
724   if ((backPix[which] == NoPixmapError) || (pixFlags & NO_BG_PIX))
725     W_UnTileWindow(w);
726   else
727     XSetWindowBackgroundPixmap(W_Display, win->window, backPix[which]);
728 
729   W_ClearWindow(w);
730 }
731 
W_SetBackgroundImage(W_Window w,char * name)732 void *W_SetBackgroundImage(W_Window w, char *name)
733 {
734   Drawable drawable = W_Void2Window(w)->window;
735   struct S_Object *sprite = calloc(1, sizeof(struct S_Object));
736   char *path;
737 
738   if (sprite == NULL) return NULL;
739 
740   GetPixmapDir();
741   path = malloc(strlen(pixmapDir) + strlen(name) + 2);
742   if (path == NULL) return NULL;
743 
744   sprintf(path, "%s/%s", pixmapDir, name);
745 
746   if (ReadFileToSprite(path, sprite, drawable)) {
747     free(path);
748     return NULL;
749   }
750   free(path);
751 
752   XSetWindowBackgroundPixmap(W_Display, drawable, sprite->image);
753   W_ClearWindow(w);
754   return (void *) sprite;
755 }
756 
757 static struct S_Object *ss = NULL;
758 static int ss_size = 0;
759 static int ss_next = 0;
760 static int ss_show = 0;
761 
ss_init(W_Window w)762 static void ss_init(W_Window w)
763 {
764   char *path, *argv[2];
765   FTS *fts;
766   FTSENT *ent;
767   Drawable drawable = W_Void2Window(w)->window;
768 
769   if (ss != NULL) return;
770 
771   GetPixmapDir();
772 
773   path = malloc(strlen(pixmapDir) + 4);
774   sprintf(path, "%s/ss", pixmapDir);
775   argv[0] = path;
776   argv[1] = NULL;
777 
778   ss_size = 50;
779   ss = (struct S_Object *) malloc(ss_size * sizeof(struct S_Object));
780   ss_next = 0;
781 
782   fts = fts_open(argv, FTS_LOGICAL, NULL);
783   while ((ent = fts_read(fts))) {
784     if (ent->fts_info != FTS_F) continue;
785     memset(&ss[ss_next], 0, sizeof(struct S_Object));
786     if (ReadFileToSprite(ent->fts_path, &ss[ss_next], drawable)) continue;
787     ss_next++;
788     if (ss_next >= ss_size) {
789       ss_size += 10;
790       ss = realloc(ss, ss_size * sizeof(struct S_Object));
791     }
792   }
793   fts_close(fts);
794   free(path);
795 }
796 
W_NextScreenShot(W_Window w,int x,int y)797 void    W_NextScreenShot(W_Window w, int x, int y)
798 {
799   ss_init(w);
800   if (ss_next == 0) return;
801   W_ClearSpriteAbsolute(&ss[ss_show], x, y);
802   ss_show++;
803   if (ss_show >= ss_next) ss_show=0;
804   W_DrawSpriteAbsolute(&ss[ss_show], x, y);
805 }
806 
W_DrawScreenShot(W_Window w,int x,int y)807 void    W_DrawScreenShot(W_Window w, int x, int y)
808 {
809   ss_init(w);
810   if (ss_next == 0) return;
811   W_DrawSpriteAbsolute(&ss[ss_show], x, y);
812 }
813 
W_ReadImage(W_Window w,char * name)814 void    *W_ReadImage(W_Window w, char *name)
815 {
816   Drawable drawable = W_Void2Window(w)->window;
817   struct S_Object *sprite = calloc(1, sizeof(struct S_Object));
818   char *path;
819 
820   if (sprite == NULL) return NULL;
821 
822   GetPixmapDir();
823   path = malloc(strlen(pixmapDir) + strlen(name) + 2);
824   if (path == NULL) return NULL;
825 
826   sprintf(path, "%s/%s", pixmapDir, name);
827 
828   if (ReadFileToSprite(path, sprite, drawable)) {
829     free(path);
830     return NULL;
831   }
832   free(path);
833   return (void *) sprite;
834 }
835 
W_DrawImage(int x,int y,void * sprite_v)836 void    W_DrawImage(int x, int y, void *sprite_v)
837 {
838   struct S_Object *sprite = (struct S_Object *) sprite_v;
839 
840   if (sprite == NULL) return;
841 
842   W_DrawSpriteAbsolute(sprite, x, y);
843 }
844 
W_DropImage(void * sprite_v)845 void    W_DropImage(void *sprite_v)
846 {
847   struct S_Object *sprite = (struct S_Object *) sprite_v;
848 
849   if (sprite == NULL) return;
850 
851   XFreeGC(W_Display, sprite->gc);
852   XFreePixmap(W_Display, sprite->image);
853   XFreePixmap(W_Display, sprite->shape);
854   free(sprite);
855 }
856