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