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