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