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