rnd-20100619-1-src
[rocksndiamonds.git] / src / libgame / system.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * system.c                                                 *
12 ***********************************************************/
13
14 #include <string.h>
15 #include <signal.h>
16
17 #include "platform.h"
18
19 #if defined(PLATFORM_MSDOS)
20 #include <fcntl.h>
21 #endif
22
23 #include "system.h"
24 #include "image.h"
25 #include "sound.h"
26 #include "setup.h"
27 #include "joystick.h"
28 #include "misc.h"
29
30
31 /* ========================================================================= */
32 /* exported variables                                                        */
33 /* ========================================================================= */
34
35 struct ProgramInfo      program;
36 struct OptionInfo       options;
37 struct VideoSystemInfo  video;
38 struct AudioSystemInfo  audio;
39 struct GfxInfo          gfx;
40 struct ArtworkInfo      artwork;
41 struct JoystickInfo     joystick;
42 struct SetupInfo        setup;
43
44 LevelDirTree           *leveldir_first_all = NULL;
45 LevelDirTree           *leveldir_first = NULL;
46 LevelDirTree           *leveldir_current = NULL;
47 int                     level_nr;
48
49 Display                *display = NULL;
50 Visual                 *visual = NULL;
51 int                     screen = 0;
52 Colormap                cmap = None;
53
54 DrawWindow             *window = NULL;
55 DrawBuffer             *backbuffer = NULL;
56 DrawBuffer             *drawto = NULL;
57
58 int                     button_status = MB_NOT_PRESSED;
59 boolean                 motion_status = FALSE;
60
61 int                     redraw_mask = REDRAW_NONE;
62 int                     redraw_tiles = 0;
63
64 int                     FrameCounter = 0;
65
66
67 /* ========================================================================= */
68 /* init/close functions                                                      */
69 /* ========================================================================= */
70
71 void InitProgramInfo(char *argv0,
72                      char *userdata_subdir, char *userdata_subdir_unix,
73                      char *program_title, char *window_title, char *icon_title,
74                      char *x11_icon_filename, char *x11_iconmask_filename,
75                      char *sdl_icon_filename, char *msdos_cursor_filename,
76                      char *cookie_prefix, char *filename_prefix,
77                      int program_version)
78 {
79   program.command_basepath = getBasePath(argv0);
80   program.command_basename = getBaseName(argv0);
81
82   program.userdata_subdir = userdata_subdir;
83   program.userdata_subdir_unix = userdata_subdir_unix;
84   program.userdata_path = getUserGameDataDir();
85
86   program.program_title = program_title;
87   program.window_title = window_title;
88   program.icon_title = icon_title;
89
90   program.x11_icon_filename = x11_icon_filename;
91   program.x11_iconmask_filename = x11_iconmask_filename;
92   program.sdl_icon_filename = sdl_icon_filename;
93   program.msdos_cursor_filename = msdos_cursor_filename;
94
95   program.cookie_prefix = cookie_prefix;
96   program.filename_prefix = filename_prefix;
97
98   program.version_major = VERSION_MAJOR(program_version);
99   program.version_minor = VERSION_MINOR(program_version);
100   program.version_patch = VERSION_PATCH(program_version);
101
102   program.error_filename = getErrorFilename(ERROR_BASENAME);
103   program.error_file = stderr;
104 }
105
106 void InitExitFunction(void (*exit_function)(int))
107 {
108   program.exit_function = exit_function;
109
110   /* set signal handlers to custom exit function */
111   signal(SIGINT, exit_function);
112   signal(SIGTERM, exit_function);
113
114 #if defined(TARGET_SDL)
115   /* set exit function to automatically cleanup SDL stuff after exit() */
116   atexit(SDL_Quit);
117 #endif
118 }
119
120 void InitPlatformDependentStuff(void)
121 {
122 #if defined(PLATFORM_MSDOS)
123   _fmode = O_BINARY;
124 #endif
125
126 #if defined(PLATFORM_MACOSX)
127   updateUserGameDataDir();
128 #endif
129
130 #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX)
131   openErrorFile();
132 #endif
133
134 #if defined(TARGET_SDL)
135   if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
136     Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
137
138   SDLNet_Init();
139 #endif
140 }
141
142 void ClosePlatformDependentStuff(void)
143 {
144 #if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS)
145   closeErrorFile();
146 #endif
147
148 #if defined(PLATFORM_MSDOS)
149   dumpErrorFile();
150 #endif
151 }
152
153 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
154                       int real_sx, int real_sy,
155                       int full_sxsize, int full_sysize,
156                       Bitmap *field_save_buffer)
157 {
158   gfx.sx = sx;
159   gfx.sy = sy;
160   gfx.sxsize = sxsize;
161   gfx.sysize = sysize;
162   gfx.real_sx = real_sx;
163   gfx.real_sy = real_sy;
164   gfx.full_sxsize = full_sxsize;
165   gfx.full_sysize = full_sysize;
166
167   gfx.field_save_buffer = field_save_buffer;
168
169 #if 0
170   gfx.background_bitmap = NULL;
171   gfx.background_bitmap_mask = REDRAW_NONE;
172 #endif
173
174   SetDrawDeactivationMask(REDRAW_NONE);         /* do not deactivate drawing */
175   SetDrawBackgroundMask(REDRAW_NONE);           /* deactivate masked drawing */
176 }
177
178 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
179 {
180   gfx.dx = dx;
181   gfx.dy = dy;
182   gfx.dxsize = dxsize;
183   gfx.dysize = dysize;
184 }
185
186 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
187 {
188   gfx.vx = vx;
189   gfx.vy = vy;
190   gfx.vxsize = vxsize;
191   gfx.vysize = vysize;
192 }
193
194 void InitGfxWindowInfo(int win_xsize, int win_ysize)
195 {
196   gfx.win_xsize = win_xsize;
197   gfx.win_ysize = win_ysize;
198
199 #if 1
200   gfx.background_bitmap_mask = REDRAW_NONE;
201
202   ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
203 #endif
204 }
205
206 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
207 {
208   /* currently only used by MSDOS code to alloc VRAM buffer, if available */
209   /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
210   gfx.scrollbuffer_width = scrollbuffer_width;
211   gfx.scrollbuffer_height = scrollbuffer_height;
212 }
213
214 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
215 {
216   gfx.clipping_enabled = enabled;
217   gfx.clip_x = x;
218   gfx.clip_y = y;
219   gfx.clip_width = width;
220   gfx.clip_height = height;
221 }
222
223 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
224 {
225   gfx.draw_busy_anim_function = draw_busy_anim_function;
226 }
227
228 void InitGfxCustomArtworkInfo()
229 {
230   gfx.override_level_graphics = FALSE;
231   gfx.override_level_sounds = FALSE;
232   gfx.override_level_music = FALSE;
233
234   gfx.draw_init_text = TRUE;
235 }
236
237 void SetDrawDeactivationMask(int draw_deactivation_mask)
238 {
239   gfx.draw_deactivation_mask = draw_deactivation_mask;
240 }
241
242 void SetDrawBackgroundMask(int draw_background_mask)
243 {
244   gfx.draw_background_mask = draw_background_mask;
245 }
246
247 #if 0
248
249 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
250                                int dest_x, int dest_y, int width, int height)
251 {
252   int bitmap_xsize = width;
253   int bitmap_ysize = height;
254   int tile_xsize = tile->width;
255   int tile_ysize = tile->height;
256   int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
257   int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
258   int x, y;
259
260   for (y = 0; y < tile_ysteps; y++)
261   {
262     for (x = 0; x < tile_xsteps; x++)
263     {
264       int draw_x = dest_x + x * tile_xsize;
265       int draw_y = dest_y + y * tile_ysize;
266       int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
267       int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
268
269       BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
270     }
271   }
272 }
273
274 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
275 {
276   if (background_bitmap_tile != NULL)
277     gfx.background_bitmap_mask |= mask;
278   else
279     gfx.background_bitmap_mask &= ~mask;
280
281 #if 0
282   if (gfx.background_bitmap == NULL)
283     gfx.background_bitmap = CreateBitmap(video.width, video.height,
284                                          DEFAULT_DEPTH);
285 #endif
286
287   if (background_bitmap_tile == NULL)   /* empty background requested */
288     return;
289
290   if (mask == REDRAW_ALL)
291     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
292                        0, 0, video.width, video.height);
293   else if (mask == REDRAW_FIELD)
294     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
295                        gfx.real_sx, gfx.real_sy,
296                        gfx.full_sxsize, gfx.full_sysize);
297   else if (mask == REDRAW_DOOR_1)
298   {
299     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
300                        gfx.dx, gfx.dy,
301                        gfx.dxsize, gfx.dysize);
302   }
303 }
304
305 #else
306
307 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
308 {
309   if (background_bitmap_tile != NULL)
310     gfx.background_bitmap_mask |= mask;
311   else
312     gfx.background_bitmap_mask &= ~mask;
313
314 #if 0
315   if (gfx.background_bitmap == NULL)
316     gfx.background_bitmap = CreateBitmap(video.width, video.height,
317                                          DEFAULT_DEPTH);
318 #endif
319
320   if (background_bitmap_tile == NULL)   /* empty background requested */
321     return;
322
323   if (mask == REDRAW_ALL)
324     BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
325                     0, 0, video.width, video.height);
326   else if (mask == REDRAW_FIELD)
327     BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
328                     gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
329   else if (mask == REDRAW_DOOR_1)
330   {
331     BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
332                     gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
333   }
334 }
335
336 #endif
337
338 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
339 {
340   /* remove every mask before setting mask for window */
341   /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
342   SetBackgroundBitmap(NULL, 0xffff);            /* !!! FIX THIS !!! */
343   SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
344 }
345
346 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
347 {
348   /* remove window area mask before setting mask for main area */
349   /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
350   SetBackgroundBitmap(NULL, REDRAW_ALL);        /* !!! FIX THIS !!! */
351   SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
352 }
353
354 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
355 {
356   /* remove window area mask before setting mask for door area */
357   /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
358   SetBackgroundBitmap(NULL, REDRAW_ALL);        /* !!! FIX THIS !!! */
359   SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
360 }
361
362
363 /* ========================================================================= */
364 /* video functions                                                           */
365 /* ========================================================================= */
366
367 inline static int GetRealDepth(int depth)
368 {
369   return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
370 }
371
372 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
373                                int width, int height, Pixel color)
374 {
375 #if defined(TARGET_SDL)
376   SDLFillRectangle(bitmap, x, y, width, height, color);
377 #else
378   X11FillRectangle(bitmap, x, y, width, height, color);
379 #endif
380 }
381
382 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
383                                int src_x, int src_y, int width, int height,
384                                int dst_x, int dst_y, int mask_mode)
385 {
386 #if defined(TARGET_SDL)
387   SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
388               dst_x, dst_y, mask_mode);
389 #else
390   X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
391               dst_x, dst_y, mask_mode);
392 #endif
393 }
394
395 void InitVideoDisplay(void)
396 {
397 #if defined(TARGET_SDL)
398   SDLInitVideoDisplay();
399 #else
400   X11InitVideoDisplay();
401 #endif
402 }
403
404 void CloseVideoDisplay(void)
405 {
406   KeyboardAutoRepeatOn();
407
408 #if defined(TARGET_SDL)
409   SDL_QuitSubSystem(SDL_INIT_VIDEO);
410 #else
411   if (display)
412     XCloseDisplay(display);
413 #endif
414 }
415
416 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
417 {
418   video.width = width;
419   video.height = height;
420   video.depth = GetRealDepth(depth);
421
422   video.fullscreen_available = FULLSCREEN_STATUS;
423   video.fullscreen_enabled = FALSE;
424 #if 0
425   video.fullscreen_mode_current = NULL;
426   video.fullscreen_modes = NULL;
427 #endif
428
429 #if defined(TARGET_SDL)
430   SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
431 #else
432   X11InitVideoBuffer(&backbuffer, &window);
433 #endif
434
435   drawto = backbuffer;
436 }
437
438 inline static void FreeBitmapPointers(Bitmap *bitmap)
439 {
440   if (bitmap == NULL)
441     return;
442
443 #if defined(TARGET_SDL)
444   SDLFreeBitmapPointers(bitmap);
445 #else
446   X11FreeBitmapPointers(bitmap);
447 #endif
448
449   checked_free(bitmap->source_filename);
450   bitmap->source_filename = NULL;
451 }
452
453 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
454                                           Bitmap *dst_bitmap)
455 {
456   if (src_bitmap == NULL || dst_bitmap == NULL)
457     return;
458
459   FreeBitmapPointers(dst_bitmap);
460
461   *dst_bitmap = *src_bitmap;
462 }
463
464 void FreeBitmap(Bitmap *bitmap)
465 {
466   if (bitmap == NULL)
467     return;
468
469   FreeBitmapPointers(bitmap);
470
471   free(bitmap);
472 }
473
474 Bitmap *CreateBitmapStruct(void)
475 {
476 #if defined(TARGET_SDL)
477   return checked_calloc(sizeof(struct SDLSurfaceInfo));
478 #else
479   return checked_calloc(sizeof(struct X11DrawableInfo));
480 #endif
481 }
482
483 Bitmap *CreateBitmap(int width, int height, int depth)
484 {
485   Bitmap *new_bitmap = CreateBitmapStruct();
486   int real_width  = MAX(1, width);      /* prevent zero bitmap width */
487   int real_height = MAX(1, height);     /* prevent zero bitmap height */
488   int real_depth  = GetRealDepth(depth);
489
490 #if defined(TARGET_SDL)
491   SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
492 #else
493   X11CreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
494 #endif
495
496   new_bitmap->width  = real_width;
497   new_bitmap->height = real_height;
498
499   return new_bitmap;
500 }
501
502 void ReCreateBitmap(Bitmap **bitmap, int width, int height, int depth)
503 {
504   Bitmap *new_bitmap = CreateBitmap(width, height, depth);
505
506   if (*bitmap == NULL)
507   {
508     *bitmap = new_bitmap;
509   }
510   else
511   {
512     TransferBitmapPointers(new_bitmap, *bitmap);
513     free(new_bitmap);
514   }
515 }
516
517 void CloseWindow(DrawWindow *window)
518 {
519 #if defined(TARGET_X11)
520   X11CloseWindow(window);
521 #endif
522 }
523
524 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
525                                        int draw_mask)
526 {
527   if (draw_mask == REDRAW_NONE)
528     return FALSE;
529
530   if (draw_mask & REDRAW_ALL)
531     return TRUE;
532
533   if ((draw_mask & REDRAW_FIELD) &&
534       x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize)
535     return TRUE;
536
537   if ((draw_mask & REDRAW_DOOR_1) &&
538       x >= gfx.dx && y < gfx.dy + gfx.dysize)
539     return TRUE;
540
541   if ((draw_mask & REDRAW_DOOR_2) &&
542       x >= gfx.dx && y >= gfx.vy)
543     return TRUE;
544
545   return FALSE;
546 }
547
548 boolean DrawingDeactivated(int x, int y, int width, int height)
549 {
550   return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
551 }
552
553 boolean DrawingOnBackground(int x, int y)
554 {
555   return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
556           CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
557 }
558
559 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
560                                   int *width, int *height, boolean is_dest)
561 {
562 #if 1
563   int clip_x, clip_y, clip_width, clip_height;
564
565   if (gfx.clipping_enabled && is_dest)  /* only clip destination bitmap */
566   {
567     clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
568     clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
569     clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
570     clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
571   }
572   else
573   {
574     clip_x = 0;
575     clip_y = 0;
576     clip_width = bitmap->width;
577     clip_height = bitmap->height;
578   }
579
580   /* skip if rectangle completely outside bitmap */
581
582   if (*x + *width  <= clip_x ||
583       *y + *height <= clip_y ||
584       *x >= clip_x + clip_width ||
585       *y >= clip_y + clip_height)
586     return FALSE;
587
588   /* clip if rectangle overlaps bitmap */
589
590   if (*x < clip_x)
591   {
592     *width -= clip_x - *x;
593     *x = clip_x;
594   }
595   else if (*x + *width > clip_x + clip_width)
596   {
597     *width = clip_x + clip_width - *x;
598   }
599
600   if (*y < clip_y)
601   {
602     *height -= clip_y - *y;
603     *y = clip_y;
604   }
605   else if (*y + *height > clip_y + clip_height)
606   {
607     *height = clip_y + clip_height - *y;
608   }
609
610   return TRUE;
611
612 #else
613
614   /* skip if rectangle completely outside bitmap */
615
616   if (*x + *width <= 0 ||
617       *y + *height <= 0 ||
618       *x >= bitmap->width ||
619       *y >= bitmap->height)
620     return FALSE;
621
622   /* clip if rectangle overlaps bitmap */
623
624   if (*x < 0)
625   {
626     *width += *x;
627     *x = 0;
628   }
629   else if (*x + *width > bitmap->width)
630   {
631     *width = bitmap->width - *x;
632   }
633
634   if (*y < 0)
635   {
636     *height += *y;
637     *y = 0;
638   }
639   else if (*y + *height > bitmap->height)
640   {
641     *height = bitmap->height - *y;
642   }
643
644   return TRUE;
645 #endif
646 }
647
648 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
649                 int src_x, int src_y, int width, int height,
650                 int dst_x, int dst_y)
651 {
652   int dst_x_unclipped = dst_x;
653   int dst_y_unclipped = dst_y;
654
655   if (DrawingDeactivated(dst_x, dst_y, width, height))
656     return;
657
658 #if 1
659   if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
660       !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
661     return;
662
663   /* source x/y might need adjustment if destination x/y was clipped top/left */
664   src_x += dst_x - dst_x_unclipped;
665   src_y += dst_y - dst_y_unclipped;
666
667 #else
668   /* skip if rectangle starts outside bitmap */
669   if (src_x >= src_bitmap->width ||
670       src_y >= src_bitmap->height ||
671       dst_x >= dst_bitmap->width ||
672       dst_y >= dst_bitmap->height)
673     return;
674
675   /* clip if rectangle overlaps bitmap */
676   if (src_x + width > src_bitmap->width)
677     width = src_bitmap->width - src_x;
678   if (src_y + height > src_bitmap->height)
679     height = src_bitmap->height - src_y;
680   if (dst_x + width > dst_bitmap->width)
681     width = dst_bitmap->width - dst_x;
682   if (dst_y + height > dst_bitmap->height)
683     height = dst_bitmap->height - dst_y;
684 #endif
685
686 #if 0
687   /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
688   /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
689      but is already fixed in SVN and should therefore finally be fixed with
690      the next official SDL release, which is probably version 1.2.14.) */
691 #if 1
692   /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
693 #if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
694   if (src_bitmap == dst_bitmap)
695   {
696     /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
697
698     /* needed when blitting directly to same bitmap -- should not be needed with
699        recent SDL libraries, but apparently does not work in 1.2.11 directly */
700
701     static Bitmap *tmp_bitmap = NULL;
702     static int tmp_bitmap_xsize = 0;
703     static int tmp_bitmap_ysize = 0;
704
705     /* start with largest static bitmaps for initial bitmap size ... */
706     if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
707     {
708       tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
709       tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
710     }
711
712     /* ... and allow for later re-adjustments due to custom artwork bitmaps */
713     if (src_bitmap->width > tmp_bitmap_xsize ||
714         src_bitmap->height > tmp_bitmap_ysize)
715     {
716       tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
717       tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
718
719       FreeBitmap(tmp_bitmap);
720
721       tmp_bitmap = NULL;
722     }
723
724     if (tmp_bitmap == NULL)
725       tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
726                                 DEFAULT_DEPTH);
727
728     sysCopyArea(src_bitmap, tmp_bitmap,
729                 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
730     sysCopyArea(tmp_bitmap, dst_bitmap,
731                 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
732
733     return;
734   }
735 #endif
736 #endif
737 #endif
738
739   sysCopyArea(src_bitmap, dst_bitmap,
740               src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
741 }
742
743 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
744                      int src_x, int src_y, int src_width, int src_height,
745                      int dst_x, int dst_y, int dst_width, int dst_height)
746 {
747   int src_xsize = (src_width  == 0 ? src_bitmap->width  : src_width);
748   int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
749   int dst_xsize = dst_width;
750   int dst_ysize = dst_height;
751   int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
752   int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
753   int x, y;
754
755   for (y = 0; y < src_ysteps; y++)
756   {
757     for (x = 0; x < src_xsteps; x++)
758     {
759       int draw_x = dst_x + x * src_xsize;
760       int draw_y = dst_y + y * src_ysize;
761       int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
762       int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
763
764       BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
765                  draw_x, draw_y);
766     }
767   }
768 }
769
770 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
771                    int fade_mode, int fade_delay, int post_delay,
772                    void (*draw_border_function)(void))
773 {
774 #if 1
775   /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
776   if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
777     return;
778 #endif
779
780 #if defined(TARGET_SDL)
781   SDLFadeRectangle(bitmap_cross, x, y, width, height,
782                    fade_mode, fade_delay, post_delay, draw_border_function);
783 #else
784   X11FadeRectangle(bitmap_cross, x, y, width, height,
785                    fade_mode, fade_delay, post_delay, draw_border_function);
786 #endif
787 }
788
789 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
790                    Pixel color)
791 {
792   if (DrawingDeactivated(x, y, width, height))
793     return;
794
795 #if 1
796   if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
797     return;
798 #else
799   /* skip if rectangle starts outside bitmap */
800   if (x >= bitmap->width ||
801       y >= bitmap->height)
802     return;
803
804   /* clip if rectangle overlaps bitmap */
805   if (x + width > bitmap->width)
806     width = bitmap->width - x;
807   if (y + height > bitmap->height)
808     height = bitmap->height - y;
809 #endif
810
811   sysFillRectangle(bitmap, x, y, width, height, color);
812 }
813
814 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
815 {
816   FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
817 }
818
819 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
820                                 int width, int height)
821 {
822   if (DrawingOnBackground(x, y))
823     BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
824   else
825     ClearRectangle(bitmap, x, y, width, height);
826 }
827
828 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
829 {
830 #if defined(TARGET_X11)
831   if (clip_gc)
832   {
833     bitmap->clip_gc = clip_gc;
834     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
835   }
836 #endif
837 }
838
839 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
840 {
841 #if defined(TARGET_X11)
842   if (clip_gc)
843   {
844     bitmap->clip_gc = clip_gc;
845     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
846   }
847 #endif
848 }
849
850 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
851                       int src_x, int src_y, int width, int height,
852                       int dst_x, int dst_y)
853 {
854   if (DrawingDeactivated(dst_x, dst_y, width, height))
855     return;
856
857   sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
858               dst_x, dst_y, BLIT_MASKED);
859 }
860
861 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
862                             int src_x, int src_y, int width, int height,
863                             int dst_x, int dst_y)
864 {
865   if (DrawingOnBackground(dst_x, dst_y))
866   {
867     /* draw background */
868     BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
869                dst_x, dst_y);
870
871     /* draw foreground */
872     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
873                   dst_x - src_x, dst_y - src_y);
874     BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
875                      dst_x, dst_y);
876   }
877   else
878     BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
879                dst_x, dst_y);
880 }
881
882 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
883                          int to_x, int to_y)
884 {
885 #if defined(TARGET_SDL)
886   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
887 #else
888   X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
889 #endif
890 }
891
892 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
893                          int to_x, int to_y)
894 {
895 #if defined(TARGET_SDL)
896   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
897 #else
898   X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
899 #endif
900 }
901
902 #if !defined(TARGET_X11_NATIVE)
903 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
904               int to_x, int to_y, Pixel pixel, int line_width)
905 {
906   int x, y;
907
908   for (x = 0; x < line_width; x++)
909   {
910     for (y = 0; y < line_width; y++)
911     {
912       int dx = x - line_width / 2;
913       int dy = y - line_width / 2;
914
915       if ((x == 0 && y == 0) ||
916           (x == 0 && y == line_width - 1) ||
917           (x == line_width - 1 && y == 0) ||
918           (x == line_width - 1 && y == line_width - 1))
919         continue;
920
921 #if defined(TARGET_SDL)
922       SDLDrawLine(bitmap,
923                   from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
924 #elif defined(TARGET_ALLEGRO)
925       AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
926                       to_x + dx, to_y + dy, pixel);
927 #endif
928     }
929   }
930 }
931 #endif
932
933 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
934 {
935 #if !defined(TARGET_X11_NATIVE)
936   int line_width = 4;
937   int i;
938
939   for (i = 0; i < num_points - 1; i++)
940     DrawLine(bitmap, points[i].x, points[i].y,
941              points[i + 1].x, points[i + 1].y, pixel, line_width);
942
943   /*
944   SDLDrawLines(bitmap->surface, points, num_points, pixel);
945   */
946 #else
947   XSetForeground(display, bitmap->line_gc[1], pixel);
948   XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
949              (XPoint *)points, num_points, CoordModeOrigin);
950 #endif
951 }
952
953 Pixel GetPixel(Bitmap *bitmap, int x, int y)
954 {
955   if (x < 0 || x >= bitmap->width ||
956       y < 0 || y >= bitmap->height)
957     return BLACK_PIXEL;
958
959 #if defined(TARGET_SDL)
960   return SDLGetPixel(bitmap, x, y);
961 #elif defined(TARGET_ALLEGRO)
962   return AllegroGetPixel(bitmap->drawable, x, y);
963 #else
964   return X11GetPixel(bitmap, x, y);
965 #endif
966 }
967
968 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
969                       unsigned int color_g, unsigned int color_b)
970 {
971 #if defined(TARGET_SDL)
972   return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
973 #elif defined(TARGET_ALLEGRO)
974   return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
975 #else
976   return X11GetPixelFromRGB(color_r, color_g, color_b);
977 #endif
978 }
979
980 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
981 {
982   unsigned int color_r = (color >> 16) & 0xff;
983   unsigned int color_g = (color >>  8) & 0xff;
984   unsigned int color_b = (color >>  0) & 0xff;
985
986   return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
987 }
988
989 /* execute all pending screen drawing operations */
990 void FlushDisplay(void)
991 {
992 #ifndef TARGET_SDL
993   XFlush(display);
994 #endif
995 }
996
997 /* execute and wait for all pending screen drawing operations */
998 void SyncDisplay(void)
999 {
1000 #ifndef TARGET_SDL
1001   XSync(display, FALSE);
1002 #endif
1003 }
1004
1005 void KeyboardAutoRepeatOn(void)
1006 {
1007 #if defined(TARGET_SDL)
1008   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1009                       SDL_DEFAULT_REPEAT_INTERVAL / 2);
1010   SDL_EnableUNICODE(1);
1011 #else
1012   if (display)
1013     XAutoRepeatOn(display);
1014 #endif
1015 }
1016
1017 void KeyboardAutoRepeatOff(void)
1018 {
1019 #if defined(TARGET_SDL)
1020   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1021   SDL_EnableUNICODE(0);
1022 #else
1023   if (display)
1024     XAutoRepeatOff(display);
1025 #endif
1026 }
1027
1028 boolean PointerInWindow(DrawWindow *window)
1029 {
1030 #if defined(TARGET_SDL)
1031   return TRUE;
1032 #else
1033   Window root, child;
1034   int root_x, root_y;
1035   unsigned int mask;
1036   int win_x, win_y;
1037
1038   /* if XQueryPointer() returns False, the pointer
1039      is not on the same screen as the specified window */
1040   return XQueryPointer(display, window->drawable, &root, &child,
1041                        &root_x, &root_y, &win_x, &win_y, &mask);
1042 #endif
1043 }
1044
1045 boolean SetVideoMode(boolean fullscreen)
1046 {
1047 #if defined(TARGET_SDL)
1048   return SDLSetVideoMode(&backbuffer, fullscreen);
1049 #else
1050   boolean success = TRUE;
1051
1052   if (fullscreen && video.fullscreen_available)
1053   {
1054     Error(ERR_WARN, "fullscreen not available in X11 version");
1055
1056     /* display error message only once */
1057     video.fullscreen_available = FALSE;
1058
1059     success = FALSE;
1060   }
1061
1062   return success;
1063 #endif
1064 }
1065
1066 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1067 {
1068 #if defined(TARGET_SDL)
1069   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1070       (!fullscreen && video.fullscreen_enabled))
1071     fullscreen = SetVideoMode(fullscreen);
1072 #endif
1073
1074   return fullscreen;
1075 }
1076
1077 Bitmap *LoadImage(char *filename)
1078 {
1079   Bitmap *new_bitmap;
1080
1081 #if defined(TARGET_SDL)
1082   new_bitmap = SDLLoadImage(filename);
1083 #else
1084   new_bitmap = X11LoadImage(filename);
1085 #endif
1086
1087   if (new_bitmap)
1088     new_bitmap->source_filename = getStringCopy(filename);
1089
1090   return new_bitmap;
1091 }
1092
1093 Bitmap *LoadCustomImage(char *basename)
1094 {
1095   char *filename = getCustomImageFilename(basename);
1096   Bitmap *new_bitmap;
1097
1098   if (filename == NULL)
1099     Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1100
1101   if ((new_bitmap = LoadImage(filename)) == NULL)
1102     Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
1103
1104   return new_bitmap;
1105 }
1106
1107 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1108 {
1109   char *filename = getCustomImageFilename(basename);
1110   Bitmap *new_bitmap;
1111
1112   if (filename == NULL)         /* (should never happen) */
1113   {
1114     Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1115     return;
1116   }
1117
1118   if (strEqual(filename, bitmap->source_filename))
1119   {
1120     /* The old and new image are the same (have the same filename and path).
1121        This usually means that this image does not exist in this graphic set
1122        and a fallback to the existing image is done. */
1123
1124     return;
1125   }
1126
1127   if ((new_bitmap = LoadImage(filename)) == NULL)
1128   {
1129     Error(ERR_WARN, "LoadImage() failed: %s", GetError());
1130     return;
1131   }
1132
1133   if (bitmap->width != new_bitmap->width ||
1134       bitmap->height != new_bitmap->height)
1135   {
1136     Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1137           filename);
1138     FreeBitmap(new_bitmap);
1139     return;
1140   }
1141
1142   TransferBitmapPointers(new_bitmap, bitmap);
1143   free(new_bitmap);
1144 }
1145
1146 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1147 {
1148   Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
1149
1150 #if defined(TARGET_SDL)
1151   SDLZoomBitmap(src_bitmap, dst_bitmap);
1152 #else
1153   X11ZoomBitmap(src_bitmap, dst_bitmap);
1154 #endif
1155
1156   return dst_bitmap;
1157 }
1158
1159 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
1160                                 boolean create_small_bitmaps)
1161 {
1162   Bitmap swap_bitmap;
1163   Bitmap *new_bitmap;
1164   Bitmap *tmp_bitmap_1;
1165   Bitmap *tmp_bitmap_2;
1166   Bitmap *tmp_bitmap_4;
1167   Bitmap *tmp_bitmap_8;
1168   Bitmap *tmp_bitmap_16;
1169   Bitmap *tmp_bitmap_32;
1170   int width_1, height_1;
1171   int width_2, height_2;
1172   int width_4, height_4;
1173   int width_8, height_8;
1174   int width_16, height_16;
1175   int width_32, height_32;
1176   int new_width, new_height;
1177
1178   /* calculate new image dimensions for normal sized image */
1179   width_1  = old_bitmap->width  * zoom_factor;
1180   height_1 = old_bitmap->height * zoom_factor;
1181
1182   /* get image with normal size (this might require scaling up) */
1183   if (zoom_factor != 1)
1184     tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1185   else
1186     tmp_bitmap_1 = old_bitmap;
1187
1188   /* this is only needed to make compilers happy */
1189   tmp_bitmap_2 = NULL;
1190   tmp_bitmap_4 = NULL;
1191   tmp_bitmap_8 = NULL;
1192   tmp_bitmap_16 = NULL;
1193   tmp_bitmap_32 = NULL;
1194
1195   if (create_small_bitmaps)
1196   {
1197     /* calculate new image dimensions for small images */
1198     width_2  = width_1  / 2;
1199     height_2 = height_1 / 2;
1200     width_4  = width_1  / 4;
1201     height_4 = height_1 / 4;
1202     width_8  = width_1  / 8;
1203     height_8 = height_1 / 8;
1204     width_16  = width_1  / 16;
1205     height_16 = height_1 / 16;
1206     width_32  = width_1  / 32;
1207     height_32 = height_1 / 32;
1208
1209     UPDATE_BUSY_STATE();
1210
1211     /* get image with 1/2 of normal size (for use in the level editor) */
1212     if (zoom_factor != 2)
1213       tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
1214     else
1215       tmp_bitmap_2 = old_bitmap;
1216
1217     UPDATE_BUSY_STATE();
1218
1219     /* get image with 1/4 of normal size (for use in the level editor) */
1220     if (zoom_factor != 4)
1221       tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
1222     else
1223       tmp_bitmap_4 = old_bitmap;
1224
1225     UPDATE_BUSY_STATE();
1226
1227     /* get image with 1/8 of normal size (for use on the preview screen) */
1228     if (zoom_factor != 8)
1229       tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
1230     else
1231       tmp_bitmap_8 = old_bitmap;
1232
1233     UPDATE_BUSY_STATE();
1234
1235     /* get image with 1/16 of normal size (for use on the preview screen) */
1236     if (zoom_factor != 16)
1237       tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1238     else
1239       tmp_bitmap_16 = old_bitmap;
1240
1241     UPDATE_BUSY_STATE();
1242
1243     /* get image with 1/32 of normal size (for use on the preview screen) */
1244     if (zoom_factor != 32)
1245       tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1246     else
1247       tmp_bitmap_32 = old_bitmap;
1248
1249     UPDATE_BUSY_STATE();
1250   }
1251
1252 #if 0
1253   /* if image was scaled up, create new clipmask for normal size image */
1254   if (zoom_factor != 1)
1255   {
1256 #if defined(TARGET_X11)
1257     if (old_bitmap->clip_mask)
1258       XFreePixmap(display, old_bitmap->clip_mask);
1259
1260     old_bitmap->clip_mask =
1261       Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
1262
1263     XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1264 #else
1265     SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1266
1267     if (old_bitmap->surface_masked)
1268       SDL_FreeSurface(old_bitmap->surface_masked);
1269
1270     SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
1271                     SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1272     if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1273       Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1274     SDL_SetColorKey(tmp_surface_1, 0, 0);       /* reset transparent pixel */
1275 #endif
1276   }
1277 #endif
1278
1279   if (create_small_bitmaps)
1280   {
1281     new_width  = width_1;
1282     new_height = height_1 + (height_1 + 1) / 2;     /* prevent odd height */
1283
1284     new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1285
1286     BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1287     BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1288                0, height_1);
1289     BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1290                width_1 / 2, height_1);
1291     BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1292                3 * width_1 / 4, height_1);
1293     BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1294                7 * width_1 / 8, height_1);
1295     BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1296                15 * width_1 / 16, height_1);
1297
1298     UPDATE_BUSY_STATE();
1299   }
1300   else
1301   {
1302     new_width  = width_1;
1303     new_height = height_1;
1304
1305     new_bitmap = tmp_bitmap_1;  /* directly use tmp_bitmap_1 as new bitmap */
1306   }
1307
1308   if (create_small_bitmaps)
1309   {
1310     /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1311     if (zoom_factor != 1)
1312       FreeBitmap(tmp_bitmap_1);
1313
1314     if (zoom_factor != 2)
1315       FreeBitmap(tmp_bitmap_2);
1316
1317     if (zoom_factor != 4)
1318       FreeBitmap(tmp_bitmap_4);
1319
1320     if (zoom_factor != 8)
1321       FreeBitmap(tmp_bitmap_8);
1322
1323     if (zoom_factor != 16)
1324       FreeBitmap(tmp_bitmap_16);
1325
1326     if (zoom_factor != 32)
1327       FreeBitmap(tmp_bitmap_32);
1328   }
1329
1330   /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1331 #if defined(TARGET_SDL)
1332   swap_bitmap.surface = old_bitmap->surface;
1333   old_bitmap->surface = new_bitmap->surface;
1334   new_bitmap->surface = swap_bitmap.surface;
1335 #else
1336   swap_bitmap.drawable = old_bitmap->drawable;
1337   old_bitmap->drawable = new_bitmap->drawable;
1338   new_bitmap->drawable = swap_bitmap.drawable;
1339 #endif
1340
1341   old_bitmap->width  = new_bitmap->width;
1342   old_bitmap->height = new_bitmap->height;
1343
1344 #if 1
1345   /* this replaces all blit masks created when loading -- maybe optimize this */
1346   {
1347 #if defined(TARGET_X11)
1348     if (old_bitmap->clip_mask)
1349       XFreePixmap(display, old_bitmap->clip_mask);
1350
1351     old_bitmap->clip_mask =
1352       Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1353
1354     XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1355 #else
1356     SDL_Surface *old_surface = old_bitmap->surface;
1357
1358     if (old_bitmap->surface_masked)
1359       SDL_FreeSurface(old_bitmap->surface_masked);
1360
1361     SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY,
1362                     SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1363     if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1364       Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1365     SDL_SetColorKey(old_surface, 0, 0);         /* reset transparent pixel */
1366 #endif
1367   }
1368 #endif
1369
1370   UPDATE_BUSY_STATE();
1371
1372   FreeBitmap(new_bitmap);       /* this actually frees the _old_ bitmap now */
1373 }
1374
1375 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1376 {
1377   CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1378 }
1379
1380 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1381 {
1382   CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1383 }
1384
1385
1386 /* ------------------------------------------------------------------------- */
1387 /* mouse pointer functions                                                   */
1388 /* ------------------------------------------------------------------------- */
1389
1390 #if !defined(PLATFORM_MSDOS)
1391 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER            0
1392 /* XPM image definitions */
1393 static const char *cursor_image_none[] =
1394 {
1395   /* width height num_colors chars_per_pixel */
1396   "    16    16        3            1",
1397
1398   /* colors */
1399   "X c #000000",
1400   ". c #ffffff",
1401   "  c None",
1402
1403   /* pixels */
1404   "                ",
1405   "                ",
1406   "                ",
1407   "                ",
1408   "                ",
1409   "                ",
1410   "                ",
1411   "                ",
1412   "                ",
1413   "                ",
1414   "                ",
1415   "                ",
1416   "                ",
1417   "                ",
1418   "                ",
1419   "                ",
1420
1421   /* hot spot */
1422   "0,0"
1423 };
1424 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1425 static const char *cursor_image_dot[] =
1426 {
1427   /* width height num_colors chars_per_pixel */
1428   "    16    16        3            1",
1429
1430   /* colors */
1431   "X c #000000",
1432   ". c #ffffff",
1433   "  c None",
1434
1435   /* pixels */
1436   " X              ",
1437   "X.X             ",
1438   " X              ",
1439   "                ",
1440   "                ",
1441   "                ",
1442   "                ",
1443   "                ",
1444   "                ",
1445   "                ",
1446   "                ",
1447   "                ",
1448   "                ",
1449   "                ",
1450   "                ",
1451   "                ",
1452
1453   /* hot spot */
1454   "1,1"
1455 };
1456 static const char **cursor_image_playfield = cursor_image_dot;
1457 #else
1458 /* some people complained about a "white dot" on the screen and thought it
1459    was a graphical error... OK, let's just remove the whole pointer :-) */
1460 static const char **cursor_image_playfield = cursor_image_none;
1461 #endif
1462
1463 #if defined(TARGET_SDL)
1464 static const int cursor_bit_order = BIT_ORDER_MSB;
1465 #elif defined(TARGET_X11_NATIVE)
1466 static const int cursor_bit_order = BIT_ORDER_LSB;
1467 #endif
1468
1469 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1470 {
1471   struct MouseCursorInfo *cursor;
1472   boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1473   int header_lines = 4;
1474   int x, y, i;
1475
1476   cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1477
1478   sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1479
1480   i = -1;
1481   for (y = 0; y < cursor->width; y++)
1482   {
1483     for (x = 0; x < cursor->height; x++)
1484     {
1485       int bit_nr = x % 8;
1486       int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1487
1488       if (bit_nr == 0)
1489       {
1490         i++;
1491         cursor->data[i] = cursor->mask[i] = 0;
1492       }
1493
1494       switch (image[header_lines + y][x])
1495       {
1496         case 'X':
1497           cursor->data[i] |= bit_mask;
1498           cursor->mask[i] |= bit_mask;
1499           break;
1500
1501         case '.':
1502           cursor->mask[i] |= bit_mask;
1503           break;
1504
1505         case ' ':
1506           break;
1507       }
1508     }
1509   }
1510
1511   sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1512
1513   return cursor;
1514 }
1515 #endif  /* !PLATFORM_MSDOS */
1516
1517 void SetMouseCursor(int mode)
1518 {
1519 #if !defined(PLATFORM_MSDOS)
1520   static struct MouseCursorInfo *cursor_none = NULL;
1521   static struct MouseCursorInfo *cursor_playfield = NULL;
1522   struct MouseCursorInfo *cursor_new;
1523
1524   if (cursor_none == NULL)
1525     cursor_none = get_cursor_from_image(cursor_image_none);
1526
1527   if (cursor_playfield == NULL)
1528     cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1529
1530   cursor_new = (mode == CURSOR_DEFAULT   ? NULL :
1531                 mode == CURSOR_NONE      ? cursor_none :
1532                 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1533
1534 #if defined(TARGET_SDL)
1535   SDLSetMouseCursor(cursor_new);
1536 #elif defined(TARGET_X11_NATIVE)
1537   X11SetMouseCursor(cursor_new);
1538 #endif
1539 #endif
1540 }
1541
1542
1543 /* ========================================================================= */
1544 /* audio functions                                                           */
1545 /* ========================================================================= */
1546
1547 void OpenAudio(void)
1548 {
1549   /* always start with reliable default values */
1550   audio.sound_available = FALSE;
1551   audio.music_available = FALSE;
1552   audio.loops_available = FALSE;
1553
1554   audio.sound_enabled = FALSE;
1555   audio.sound_deactivated = FALSE;
1556
1557   audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1558   audio.mixer_pid = 0;
1559   audio.device_name = NULL;
1560   audio.device_fd = -1;
1561
1562   audio.num_channels = 0;
1563   audio.music_channel = 0;
1564   audio.first_sound_channel = 0;
1565
1566 #if defined(TARGET_SDL)
1567   SDLOpenAudio();
1568 #elif defined(PLATFORM_UNIX)
1569   UnixOpenAudio();
1570 #elif defined(PLATFORM_MSDOS)
1571   MSDOSOpenAudio();
1572 #endif
1573 }
1574
1575 void CloseAudio(void)
1576 {
1577 #if defined(TARGET_SDL)
1578   SDLCloseAudio();
1579 #elif defined(PLATFORM_UNIX)
1580   UnixCloseAudio();
1581 #elif defined(PLATFORM_MSDOS)
1582   MSDOSCloseAudio();
1583 #endif
1584
1585   audio.sound_enabled = FALSE;
1586 }
1587
1588 void SetAudioMode(boolean enabled)
1589 {
1590   if (!audio.sound_available)
1591     return;
1592
1593   audio.sound_enabled = enabled;
1594 }
1595
1596
1597 /* ========================================================================= */
1598 /* event functions                                                           */
1599 /* ========================================================================= */
1600
1601 void InitEventFilter(EventFilter filter_function)
1602 {
1603 #if defined(TARGET_SDL)
1604   /* set event filter to filter out certain events */
1605   SDL_SetEventFilter(filter_function);
1606 #endif
1607 }
1608
1609 boolean PendingEvent(void)
1610 {
1611 #if defined(TARGET_SDL)
1612   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1613 #else
1614   return (XPending(display) ? TRUE : FALSE);
1615 #endif
1616 }
1617
1618 void NextEvent(Event *event)
1619 {
1620 #if defined(TARGET_SDL)
1621   SDLNextEvent(event);
1622 #else
1623   XNextEvent(display, event);
1624 #endif
1625 }
1626
1627 void PeekEvent(Event *event)
1628 {
1629 #if defined(TARGET_SDL)
1630   SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1631 #else
1632   XPeekEvent(display, event);
1633 #endif
1634 }
1635
1636 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1637 {
1638 #if defined(TARGET_SDL)
1639
1640 #if 0
1641   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1642          (int)event->keysym.unicode,
1643          (int)event->keysym.sym,
1644          (int)SDL_GetModState());
1645 #endif
1646
1647   if (with_modifiers &&
1648       event->keysym.unicode > 0x0000 &&
1649       event->keysym.unicode < 0x2000)
1650     return event->keysym.unicode;
1651   else
1652     return event->keysym.sym;
1653
1654 #else
1655
1656 #if 0
1657   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1658          (int)XLookupKeysym(event, event->state),
1659          (int)XLookupKeysym(event, 0));
1660 #endif
1661
1662   if (with_modifiers)
1663     return XLookupKeysym(event, event->state);
1664   else
1665     return XLookupKeysym(event, 0);
1666 #endif
1667 }
1668
1669 KeyMod HandleKeyModState(Key key, int key_status)
1670 {
1671   static KeyMod current_modifiers = KMOD_None;
1672
1673   if (key != KSYM_UNDEFINED)    /* new key => check for modifier key change */
1674   {
1675     KeyMod new_modifier = KMOD_None;
1676
1677     switch(key)
1678     {
1679       case KSYM_Shift_L:
1680         new_modifier = KMOD_Shift_L;
1681         break;
1682       case KSYM_Shift_R:
1683         new_modifier = KMOD_Shift_R;
1684         break;
1685       case KSYM_Control_L:
1686         new_modifier = KMOD_Control_L;
1687         break;
1688       case KSYM_Control_R:
1689         new_modifier = KMOD_Control_R;
1690         break;
1691       case KSYM_Meta_L:
1692         new_modifier = KMOD_Meta_L;
1693         break;
1694       case KSYM_Meta_R:
1695         new_modifier = KMOD_Meta_R;
1696         break;
1697       case KSYM_Alt_L:
1698         new_modifier = KMOD_Alt_L;
1699         break;
1700       case KSYM_Alt_R:
1701         new_modifier = KMOD_Alt_R;
1702         break;
1703       default:
1704         break;
1705     }
1706
1707     if (key_status == KEY_PRESSED)
1708       current_modifiers |= new_modifier;
1709     else
1710       current_modifiers &= ~new_modifier;
1711   }
1712
1713   return current_modifiers;
1714 }
1715
1716 KeyMod GetKeyModState()
1717 {
1718 #if defined(TARGET_SDL)
1719   return (KeyMod)SDL_GetModState();
1720 #else
1721   return HandleKeyModState(KSYM_UNDEFINED, 0);
1722 #endif
1723 }
1724
1725 KeyMod GetKeyModStateFromEvents()
1726 {
1727   /* always use key modifier state as tracked from key events (this is needed
1728      if the modifier key event was injected into the event queue, but the key
1729      was not really pressed on keyboard -- SDL_GetModState() seems to directly
1730      query the keys as held pressed on the keyboard) -- this case is currently
1731      only used to filter out clipboard insert events from "True X-Mouse" tool */
1732
1733   return HandleKeyModState(KSYM_UNDEFINED, 0);
1734 }
1735
1736 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1737 {
1738   if (event->type != EVENT_CLIENTMESSAGE)
1739     return FALSE;
1740
1741 #if defined(TARGET_SDL)
1742   return TRUE;          /* the only possible message here is SDL_QUIT */
1743 #elif defined(PLATFORM_UNIX)
1744   if ((event->window == window->drawable) &&
1745       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1746     return TRUE;
1747 #endif
1748
1749   return FALSE;
1750 }
1751
1752
1753 /* ========================================================================= */
1754 /* joystick functions                                                        */
1755 /* ========================================================================= */
1756
1757 void InitJoysticks()
1758 {
1759   int i;
1760
1761 #if defined(NO_JOYSTICK)
1762   return;       /* joysticks generally deactivated by compile-time directive */
1763 #endif
1764
1765   /* always start with reliable default values */
1766   joystick.status = JOYSTICK_NOT_AVAILABLE;
1767   for (i = 0; i < MAX_PLAYERS; i++)
1768     joystick.fd[i] = -1;                /* joystick device closed */
1769
1770 #if defined(TARGET_SDL)
1771   SDLInitJoysticks();
1772 #elif defined(PLATFORM_UNIX)
1773   UnixInitJoysticks();
1774 #elif defined(PLATFORM_MSDOS)
1775   MSDOSInitJoysticks();
1776 #endif
1777
1778 #if 0
1779   for (i = 0; i < MAX_PLAYERS; i++)
1780     printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1781 #endif
1782 }
1783
1784 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1785 {
1786 #if defined(TARGET_SDL)
1787   return SDLReadJoystick(nr, x, y, b1, b2);
1788 #elif defined(PLATFORM_UNIX)
1789   return UnixReadJoystick(nr, x, y, b1, b2);
1790 #elif defined(PLATFORM_MSDOS)
1791   return MSDOSReadJoystick(nr, x, y, b1, b2);
1792 #endif
1793 }