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