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