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