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