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