rnd-20060816-1-src
[rocksndiamonds.git] / src / libgame / system.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * system.c                                                 *
12 ***********************************************************/
13
14 #include <string.h>
15 #include <signal.h>
16
17 #include "platform.h"
18
19 #if defined(PLATFORM_MSDOS)
20 #include <fcntl.h>
21 #endif
22
23 #include "system.h"
24 #include "image.h"
25 #include "sound.h"
26 #include "setup.h"
27 #include "joystick.h"
28 #include "misc.h"
29
30
31 /* ========================================================================= */
32 /* exported variables                                                        */
33 /* ========================================================================= */
34
35 struct ProgramInfo      program;
36 struct OptionInfo       options;
37 struct VideoSystemInfo  video;
38 struct AudioSystemInfo  audio;
39 struct GfxInfo          gfx;
40 struct ArtworkInfo      artwork;
41 struct JoystickInfo     joystick;
42 struct SetupInfo        setup;
43
44 LevelDirTree           *leveldir_first_all = NULL;
45 LevelDirTree           *leveldir_first = NULL;
46 LevelDirTree           *leveldir_current = NULL;
47 int                     level_nr;
48
49 Display                *display = NULL;
50 Visual                 *visual = NULL;
51 int                     screen = 0;
52 Colormap                cmap = None;
53
54 DrawWindow             *window = NULL;
55 DrawBuffer             *backbuffer = NULL;
56 DrawBuffer             *drawto = NULL;
57
58 int                     button_status = MB_NOT_PRESSED;
59 boolean                 motion_status = FALSE;
60
61 int                     redraw_mask = REDRAW_NONE;
62 int                     redraw_tiles = 0;
63
64 int                     FrameCounter = 0;
65
66
67 /* ========================================================================= */
68 /* init/close functions                                                      */
69 /* ========================================================================= */
70
71 void InitProgramInfo(char *argv0,
72                      char *userdata_subdir, char *userdata_subdir_unix,
73                      char *program_title, char *window_title, char *icon_title,
74                      char *x11_icon_filename, char *x11_iconmask_filename,
75                      char *sdl_icon_filename, char *msdos_cursor_filename,
76                      char *cookie_prefix, char *filename_prefix,
77                      int program_version)
78 {
79   program.command_basepath = getBasePath(argv0);
80   program.command_basename = getBaseName(argv0);
81
82   program.userdata_subdir = userdata_subdir;
83   program.userdata_subdir_unix = userdata_subdir_unix;
84   program.userdata_path = getUserGameDataDir();
85
86   program.program_title = program_title;
87   program.window_title = window_title;
88   program.icon_title = icon_title;
89
90   program.x11_icon_filename = x11_icon_filename;
91   program.x11_iconmask_filename = x11_iconmask_filename;
92   program.sdl_icon_filename = sdl_icon_filename;
93   program.msdos_cursor_filename = msdos_cursor_filename;
94
95   program.cookie_prefix = cookie_prefix;
96   program.filename_prefix = filename_prefix;
97
98   program.version_major = VERSION_MAJOR(program_version);
99   program.version_minor = VERSION_MINOR(program_version);
100   program.version_patch = VERSION_PATCH(program_version);
101
102   program.error_filename = getErrorFilename(ERROR_BASENAME);
103   program.error_file = stderr;
104 }
105
106 void InitExitFunction(void (*exit_function)(int))
107 {
108   program.exit_function = exit_function;
109
110   /* set signal handlers to custom exit function */
111   signal(SIGINT, exit_function);
112   signal(SIGTERM, exit_function);
113
114 #if defined(TARGET_SDL)
115   /* set exit function to automatically cleanup SDL stuff after exit() */
116   atexit(SDL_Quit);
117 #endif
118 }
119
120 void InitPlatformDependentStuff(void)
121 {
122 #if defined(PLATFORM_MSDOS)
123   _fmode = O_BINARY;
124 #endif
125
126 #if defined(PLATFORM_MACOSX)
127   updateUserGameDataDir();
128 #endif
129
130 #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX)
131   openErrorFile();
132 #endif
133
134 #if defined(TARGET_SDL)
135   if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
136     Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
137
138   SDLNet_Init();
139 #endif
140 }
141
142 void ClosePlatformDependentStuff(void)
143 {
144 #if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS)
145   closeErrorFile();
146 #endif
147
148 #if defined(PLATFORM_MSDOS)
149   dumpErrorFile();
150 #endif
151 }
152
153 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
154                       int real_sx, int real_sy,
155                       int full_sxsize, int full_sysize,
156                       Bitmap *field_save_buffer)
157 {
158   gfx.sx = sx;
159   gfx.sy = sy;
160   gfx.sxsize = sxsize;
161   gfx.sysize = sysize;
162   gfx.real_sx = real_sx;
163   gfx.real_sy = real_sy;
164   gfx.full_sxsize = full_sxsize;
165   gfx.full_sysize = full_sysize;
166
167   gfx.field_save_buffer = field_save_buffer;
168
169   gfx.background_bitmap = NULL;
170   gfx.background_bitmap_mask = REDRAW_NONE;
171
172   SetDrawDeactivationMask(REDRAW_NONE);         /* do not deactivate drawing */
173   SetDrawBackgroundMask(REDRAW_NONE);           /* deactivate masked drawing */
174 }
175
176 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
177 {
178   gfx.dx = dx;
179   gfx.dy = dy;
180   gfx.dxsize = dxsize;
181   gfx.dysize = dysize;
182 }
183
184 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
185 {
186   gfx.vx = vx;
187   gfx.vy = vy;
188   gfx.vxsize = vxsize;
189   gfx.vysize = vysize;
190 }
191
192 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
193 {
194   /* currently only used by MSDOS code to alloc VRAM buffer, if available */
195   gfx.scrollbuffer_width = scrollbuffer_width;
196   gfx.scrollbuffer_height = scrollbuffer_height;
197 }
198
199 void SetDrawDeactivationMask(int draw_deactivation_mask)
200 {
201   gfx.draw_deactivation_mask = draw_deactivation_mask;
202 }
203
204 void SetDrawBackgroundMask(int draw_background_mask)
205 {
206   gfx.draw_background_mask = draw_background_mask;
207 }
208
209 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
210                                int dest_x, int dest_y, int width, int height)
211 {
212   int bitmap_xsize = width;
213   int bitmap_ysize = height;
214   int tile_xsize = tile->width;
215   int tile_ysize = tile->height;
216   int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
217   int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
218   int x, y;
219
220   for (y = 0; y < tile_ysteps; y++)
221   {
222     for (x = 0; x < tile_xsteps; x++)
223     {
224       int draw_x = dest_x + x * tile_xsize;
225       int draw_y = dest_y + y * tile_ysize;
226       int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
227       int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
228
229       BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
230     }
231   }
232 }
233
234 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
235 {
236   if (background_bitmap_tile != NULL)
237     gfx.background_bitmap_mask |= mask;
238   else
239     gfx.background_bitmap_mask &= ~mask;
240
241   if (gfx.background_bitmap == NULL)
242     gfx.background_bitmap = CreateBitmap(video.width, video.height,
243                                          DEFAULT_DEPTH);
244
245   if (background_bitmap_tile == NULL)   /* empty background requested */
246     return;
247
248   if (mask == REDRAW_FIELD)
249     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
250                        gfx.real_sx, gfx.real_sy,
251                        gfx.full_sxsize, gfx.full_sysize);
252   else if (mask == REDRAW_DOOR_1)
253   {
254     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
255                        gfx.dx, gfx.dy,
256                        gfx.dxsize, gfx.dysize);
257   }
258 }
259
260 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
261 {
262   SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
263 }
264
265 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
266 {
267   SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
268 }
269
270
271 /* ========================================================================= */
272 /* video functions                                                           */
273 /* ========================================================================= */
274
275 inline static int GetRealDepth(int depth)
276 {
277   return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
278 }
279
280 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
281                                int width, int height, Pixel color)
282 {
283 #if defined(TARGET_SDL)
284   SDLFillRectangle(bitmap, x, y, width, height, color);
285 #else
286   X11FillRectangle(bitmap, x, y, width, height, color);
287 #endif
288 }
289
290 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
291                                int src_x, int src_y, int width, int height,
292                                int dst_x, int dst_y, int mask_mode)
293 {
294 #if defined(TARGET_SDL)
295   SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
296               dst_x, dst_y, mask_mode);
297 #else
298   X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
299               dst_x, dst_y, mask_mode);
300 #endif
301 }
302
303 void InitVideoDisplay(void)
304 {
305 #if defined(TARGET_SDL)
306   SDLInitVideoDisplay();
307 #else
308   X11InitVideoDisplay();
309 #endif
310 }
311
312 void CloseVideoDisplay(void)
313 {
314   KeyboardAutoRepeatOn();
315
316 #if defined(TARGET_SDL)
317   SDL_QuitSubSystem(SDL_INIT_VIDEO);
318 #else
319   if (display)
320     XCloseDisplay(display);
321 #endif
322 }
323
324 void InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
325                      int width, int height, int depth, boolean fullscreen)
326 {
327   video.width = width;
328   video.height = height;
329   video.depth = GetRealDepth(depth);
330   video.fullscreen_available = FULLSCREEN_STATUS;
331   video.fullscreen_enabled = FALSE;
332   video.fullscreen_modes = NULL;
333   video.fullscreen_mode_current = NULL;
334
335 #if defined(TARGET_SDL)
336   SDLInitVideoBuffer(backbuffer, window, fullscreen);
337 #else
338   X11InitVideoBuffer(backbuffer, window);
339 #endif
340 }
341
342 Bitmap *CreateBitmapStruct(void)
343 {
344 #if defined(TARGET_SDL)
345   return checked_calloc(sizeof(struct SDLSurfaceInfo));
346 #else
347   return checked_calloc(sizeof(struct X11DrawableInfo));
348 #endif
349 }
350
351 Bitmap *CreateBitmap(int width, int height, int depth)
352 {
353   Bitmap *new_bitmap = CreateBitmapStruct();
354   int real_depth = GetRealDepth(depth);
355
356 #if defined(TARGET_SDL)
357   SDLCreateBitmapContent(new_bitmap, width, height, real_depth);
358 #else
359   X11CreateBitmapContent(new_bitmap, width, height, real_depth);
360 #endif
361
362   new_bitmap->width = width;
363   new_bitmap->height = height;
364
365   return new_bitmap;
366 }
367
368 inline static void FreeBitmapPointers(Bitmap *bitmap)
369 {
370   if (bitmap == NULL)
371     return;
372
373 #if defined(TARGET_SDL)
374   SDLFreeBitmapPointers(bitmap);
375 #else
376   X11FreeBitmapPointers(bitmap);
377 #endif
378
379   checked_free(bitmap->source_filename);
380   bitmap->source_filename = NULL;
381 }
382
383 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
384                                           Bitmap *dst_bitmap)
385 {
386   if (src_bitmap == NULL || dst_bitmap == NULL)
387     return;
388
389   FreeBitmapPointers(dst_bitmap);
390
391   *dst_bitmap = *src_bitmap;
392 }
393
394 void FreeBitmap(Bitmap *bitmap)
395 {
396   if (bitmap == NULL)
397     return;
398
399   FreeBitmapPointers(bitmap);
400
401   free(bitmap);
402 }
403
404 void CloseWindow(DrawWindow *window)
405 {
406 #if defined(TARGET_X11)
407   if (window->drawable)
408   {
409     XUnmapWindow(display, window->drawable);
410     XDestroyWindow(display, window->drawable);
411   }
412   if (window->gc)
413     XFreeGC(display, window->gc);
414 #endif
415 }
416
417 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
418                                        int draw_mask)
419 {
420   if (draw_mask == REDRAW_NONE)
421     return FALSE;
422
423   if (draw_mask & REDRAW_ALL)
424     return TRUE;
425
426   if ((draw_mask & REDRAW_FIELD) && x < gfx.real_sx + gfx.full_sxsize)
427     return TRUE;
428
429   if ((draw_mask & REDRAW_DOOR_1) && x >= gfx.dx && y < gfx.dy + gfx.dysize)
430     return TRUE;
431
432   if ((draw_mask & REDRAW_DOOR_2) && x >= gfx.dx && y >= gfx.vy)
433     return TRUE;
434
435   return FALSE;
436 }
437
438 boolean DrawingDeactivated(int x, int y, int width, int height)
439 {
440   return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
441 }
442
443 boolean DrawingOnBackground(int x, int y)
444 {
445   return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
446           CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
447 }
448
449 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
450                 int src_x, int src_y, int width, int height,
451                 int dst_x, int dst_y)
452 {
453   if (DrawingDeactivated(dst_x, dst_y, width, height))
454     return;
455
456   sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
457               dst_x, dst_y, BLIT_OPAQUE);
458 }
459
460 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
461                    int fade_mode, int fade_delay, int post_delay)
462 {
463 #if defined(TARGET_SDL)
464   SDLFadeRectangle(bitmap_cross, x, y, width, height,
465                    fade_mode, fade_delay, post_delay);
466 #else
467   X11FadeRectangle(bitmap_cross, x, y, width, height,
468                    fade_mode, fade_delay, post_delay);
469 #endif
470 }
471
472 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
473                    Pixel color)
474 {
475   if (DrawingDeactivated(x, y, width, height))
476     return;
477
478   sysFillRectangle(bitmap, x, y, width, height, color);
479 }
480
481 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
482 {
483   FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
484 }
485
486 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
487                                 int width, int height)
488 {
489   if (DrawingOnBackground(x, y))
490     BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
491   else
492     ClearRectangle(bitmap, x, y, width, height);
493 }
494
495 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
496 {
497 #if defined(TARGET_X11)
498   if (clip_gc)
499   {
500     bitmap->clip_gc = clip_gc;
501     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
502   }
503 #endif
504 }
505
506 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
507 {
508 #if defined(TARGET_X11)
509   if (clip_gc)
510   {
511     bitmap->clip_gc = clip_gc;
512     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
513   }
514 #endif
515 }
516
517 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
518                       int src_x, int src_y, int width, int height,
519                       int dst_x, int dst_y)
520 {
521   if (DrawingDeactivated(dst_x, dst_y, width, height))
522     return;
523
524   sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
525               dst_x, dst_y, BLIT_MASKED);
526 }
527
528 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
529                             int src_x, int src_y, int width, int height,
530                             int dst_x, int dst_y)
531 {
532   if (DrawingOnBackground(dst_x, dst_y))
533   {
534     /* draw background */
535     BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
536                dst_x, dst_y);
537
538     /* draw foreground */
539     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
540                   dst_x - src_x, dst_y - src_y);
541     BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
542                      dst_x, dst_y);
543   }
544   else
545     BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
546                dst_x, dst_y);
547 }
548
549 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
550                          int to_x, int to_y)
551 {
552 #if defined(TARGET_SDL)
553   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
554 #else
555   X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
556 #endif
557 }
558
559 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
560                          int to_x, int to_y)
561 {
562 #if defined(TARGET_SDL)
563   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
564 #else
565   X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
566 #endif
567 }
568
569 #if !defined(TARGET_X11_NATIVE)
570 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
571               int to_x, int to_y, Pixel pixel, int line_width)
572 {
573   int x, y;
574
575   for (x = 0; x < line_width; x++)
576   {
577     for (y = 0; y < line_width; y++)
578     {
579       int dx = x - line_width / 2;
580       int dy = y - line_width / 2;
581
582       if ((x == 0 && y == 0) ||
583           (x == 0 && y == line_width - 1) ||
584           (x == line_width - 1 && y == 0) ||
585           (x == line_width - 1 && y == line_width - 1))
586         continue;
587
588 #if defined(TARGET_SDL)
589       SDLDrawLine(bitmap,
590                   from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
591 #elif defined(TARGET_ALLEGRO)
592       AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
593                       to_x + dx, to_y + dy, pixel);
594 #endif
595     }
596   }
597 }
598 #endif
599
600 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
601 {
602 #if !defined(TARGET_X11_NATIVE)
603   int line_width = 4;
604   int i;
605
606   for (i = 0; i < num_points - 1; i++)
607     DrawLine(bitmap, points[i].x, points[i].y,
608              points[i + 1].x, points[i + 1].y, pixel, line_width);
609
610   /*
611   SDLDrawLines(bitmap->surface, points, num_points, pixel);
612   */
613 #else
614   XSetForeground(display, bitmap->line_gc[1], pixel);
615   XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
616              (XPoint *)points, num_points, CoordModeOrigin);
617 #endif
618 }
619
620 Pixel GetPixel(Bitmap *bitmap, int x, int y)
621 {
622   if (x < 0 || x >= bitmap->width ||
623       y < 0 || y >= bitmap->height)
624     return BLACK_PIXEL;
625
626 #if defined(TARGET_SDL)
627   return SDLGetPixel(bitmap, x, y);
628 #elif defined(TARGET_ALLEGRO)
629   return AllegroGetPixel(bitmap->drawable, x, y);
630 #else
631   return X11GetPixel(bitmap, x, y);
632 #endif
633 }
634
635 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
636                       unsigned int color_g, unsigned int color_b)
637 {
638 #if defined(TARGET_SDL)
639   return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
640 #elif defined(TARGET_ALLEGRO)
641   return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
642 #else
643   return X11GetPixelFromRGB(color_r, color_g, color_b);
644 #endif
645 }
646
647 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
648 {
649   unsigned int color_r = (color >> 16) & 0xff;
650   unsigned int color_g = (color >>  8) & 0xff;
651   unsigned int color_b = (color >>  0) & 0xff;
652
653   return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
654 }
655
656 /* execute all pending screen drawing operations */
657 void FlushDisplay(void)
658 {
659 #ifndef TARGET_SDL
660   XFlush(display);
661 #endif
662 }
663
664 /* execute and wait for all pending screen drawing operations */
665 void SyncDisplay(void)
666 {
667 #ifndef TARGET_SDL
668   XSync(display, FALSE);
669 #endif
670 }
671
672 void KeyboardAutoRepeatOn(void)
673 {
674 #if defined(TARGET_SDL)
675   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
676                       SDL_DEFAULT_REPEAT_INTERVAL / 2);
677   SDL_EnableUNICODE(1);
678 #else
679   if (display)
680     XAutoRepeatOn(display);
681 #endif
682 }
683
684 void KeyboardAutoRepeatOff(void)
685 {
686 #if defined(TARGET_SDL)
687   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
688   SDL_EnableUNICODE(0);
689 #else
690   if (display)
691     XAutoRepeatOff(display);
692 #endif
693 }
694
695 boolean PointerInWindow(DrawWindow *window)
696 {
697 #if defined(TARGET_SDL)
698   return TRUE;
699 #else
700   Window root, child;
701   int root_x, root_y;
702   unsigned int mask;
703   int win_x, win_y;
704
705   /* if XQueryPointer() returns False, the pointer
706      is not on the same screen as the specified window */
707   return XQueryPointer(display, window->drawable, &root, &child,
708                        &root_x, &root_y, &win_x, &win_y, &mask);
709 #endif
710 }
711
712 boolean SetVideoMode(boolean fullscreen)
713 {
714 #if defined(TARGET_SDL)
715   return SDLSetVideoMode(&backbuffer, fullscreen);
716 #else
717   boolean success = TRUE;
718
719   if (fullscreen && video.fullscreen_available)
720   {
721     Error(ERR_WARN, "fullscreen not available in X11 version");
722
723     /* display error message only once */
724     video.fullscreen_available = FALSE;
725
726     success = FALSE;
727   }
728
729   return success;
730 #endif
731 }
732
733 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
734 {
735 #if defined(TARGET_SDL)
736   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
737       (!fullscreen && video.fullscreen_enabled))
738     fullscreen = SetVideoMode(fullscreen);
739 #endif
740
741   return fullscreen;
742 }
743
744 Bitmap *LoadImage(char *filename)
745 {
746   Bitmap *new_bitmap;
747
748 #if defined(TARGET_SDL)
749   new_bitmap = SDLLoadImage(filename);
750 #else
751   new_bitmap = X11LoadImage(filename);
752 #endif
753
754   if (new_bitmap)
755     new_bitmap->source_filename = getStringCopy(filename);
756
757   return new_bitmap;
758 }
759
760 Bitmap *LoadCustomImage(char *basename)
761 {
762   char *filename = getCustomImageFilename(basename);
763   Bitmap *new_bitmap;
764
765   if (filename == NULL)
766     Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
767
768   if ((new_bitmap = LoadImage(filename)) == NULL)
769     Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
770
771   return new_bitmap;
772 }
773
774 void ReloadCustomImage(Bitmap *bitmap, char *basename)
775 {
776   char *filename = getCustomImageFilename(basename);
777   Bitmap *new_bitmap;
778
779   if (filename == NULL)         /* (should never happen) */
780   {
781     Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
782     return;
783   }
784
785   if (strEqual(filename, bitmap->source_filename))
786   {
787     /* The old and new image are the same (have the same filename and path).
788        This usually means that this image does not exist in this graphic set
789        and a fallback to the existing image is done. */
790
791     return;
792   }
793
794   if ((new_bitmap = LoadImage(filename)) == NULL)
795   {
796     Error(ERR_WARN, "LoadImage() failed: %s", GetError());
797     return;
798   }
799
800   if (bitmap->width != new_bitmap->width ||
801       bitmap->height != new_bitmap->height)
802   {
803     Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
804           filename);
805     FreeBitmap(new_bitmap);
806     return;
807   }
808
809   TransferBitmapPointers(new_bitmap, bitmap);
810   free(new_bitmap);
811 }
812
813 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
814 {
815   Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
816
817 #if defined(TARGET_SDL)
818   SDLZoomBitmap(src_bitmap, dst_bitmap);
819 #else
820   X11ZoomBitmap(src_bitmap, dst_bitmap);
821 #endif
822
823   return dst_bitmap;
824 }
825
826 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
827                                 boolean create_small_bitmaps)
828 {
829   Bitmap swap_bitmap;
830   Bitmap *new_bitmap, *tmp_bitmap_1, *tmp_bitmap_2, *tmp_bitmap_4,*tmp_bitmap_8;
831   int width_1, height_1, width_2, height_2, width_4, height_4, width_8,height_8;
832   int new_width, new_height;
833
834   /* calculate new image dimensions for normal sized image */
835   width_1  = old_bitmap->width  * zoom_factor;
836   height_1 = old_bitmap->height * zoom_factor;
837
838   /* get image with normal size (this might require scaling up) */
839   if (zoom_factor != 1)
840     tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
841   else
842     tmp_bitmap_1 = old_bitmap;
843
844   /* this is only needed to make compilers happy */
845   tmp_bitmap_2 = tmp_bitmap_4 = tmp_bitmap_8 = NULL;
846
847   if (create_small_bitmaps)
848   {
849     /* calculate new image dimensions for small images */
850     width_2  = width_1  / 2;
851     height_2 = height_1 / 2;
852     width_4  = width_1  / 4;
853     height_4 = height_1 / 4;
854     width_8  = width_1  / 8;
855     height_8 = height_1 / 8;
856
857     /* get image with 1/2 of normal size (for use in the level editor) */
858     if (zoom_factor != 2)
859       tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
860     else
861       tmp_bitmap_2 = old_bitmap;
862
863     /* get image with 1/4 of normal size (for use in the level editor) */
864     if (zoom_factor != 4)
865       tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
866     else
867       tmp_bitmap_4 = old_bitmap;
868
869     /* get image with 1/8 of normal size (for use on the preview screen) */
870     if (zoom_factor != 8)
871       tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
872     else
873       tmp_bitmap_8 = old_bitmap;
874   }
875
876   /* if image was scaled up, create new clipmask for normal size image */
877   if (zoom_factor != 1)
878   {
879 #if defined(TARGET_X11)
880     if (old_bitmap->clip_mask)
881       XFreePixmap(display, old_bitmap->clip_mask);
882
883     old_bitmap->clip_mask =
884       Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
885
886     XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
887 #else
888     SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
889
890     if (old_bitmap->surface_masked)
891       SDL_FreeSurface(old_bitmap->surface_masked);
892
893     SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
894                     SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
895     if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
896       Error(ERR_EXIT, "SDL_DisplayFormat() failed");
897     SDL_SetColorKey(tmp_surface_1, 0, 0);       /* reset transparent pixel */
898 #endif
899   }
900
901   if (create_small_bitmaps)
902   {
903     new_width  = width_1;
904     new_height = height_1 + (height_1 + 1) / 2;     /* prevent odd height */
905
906     new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
907
908     BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
909     BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
910                0, height_1);
911     BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
912                width_1 / 2, height_1);
913     BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
914                3 * width_1 / 4, height_1);
915   }
916   else
917   {
918     new_width  = width_1;
919     new_height = height_1;
920
921     new_bitmap = tmp_bitmap_1;  /* directly use tmp_bitmap_1 as new bitmap */
922   }
923
924   if (create_small_bitmaps)
925   {
926     /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
927     if (zoom_factor != 1)
928       FreeBitmap(tmp_bitmap_1);
929
930     if (zoom_factor != 2)
931       FreeBitmap(tmp_bitmap_2);
932
933     if (zoom_factor != 4)
934       FreeBitmap(tmp_bitmap_4);
935
936     if (zoom_factor != 8)
937       FreeBitmap(tmp_bitmap_8);
938   }
939
940   /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
941 #if defined(TARGET_SDL)
942   swap_bitmap.surface = old_bitmap->surface;
943   old_bitmap->surface = new_bitmap->surface;
944   new_bitmap->surface = swap_bitmap.surface;
945 #else
946   swap_bitmap.drawable = old_bitmap->drawable;
947   old_bitmap->drawable = new_bitmap->drawable;
948   new_bitmap->drawable = swap_bitmap.drawable;
949 #endif
950
951   old_bitmap->width  = new_bitmap->width;
952   old_bitmap->height = new_bitmap->height;
953
954   FreeBitmap(new_bitmap);       /* this actually frees the _old_ bitmap now */
955 }
956
957 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
958 {
959   CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
960 }
961
962 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
963 {
964   CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
965 }
966
967
968 /* ------------------------------------------------------------------------- */
969 /* mouse pointer functions                                                   */
970 /* ------------------------------------------------------------------------- */
971
972 #if !defined(PLATFORM_MSDOS)
973 /* XPM */
974 static const char *cursor_image_playfield[] =
975 {
976   /* width height num_colors chars_per_pixel */
977   "    16    16        3            1",
978
979   /* colors */
980   "X c #000000",
981   ". c #ffffff",
982   "  c None",
983
984 #if 1
985   /* some people complained about a "white dot" on the screen and thought it
986      was a graphical error... OK, let's just remove the whole pointer :-) */
987
988   /* pixels */
989   "                ",
990   "                ",
991   "                ",
992   "                ",
993   "                ",
994   "                ",
995   "                ",
996   "                ",
997   "                ",
998   "                ",
999   "                ",
1000   "                ",
1001   "                ",
1002   "                ",
1003   "                ",
1004   "                ",
1005
1006   /* hot spot */
1007   "0,0"
1008
1009 #else
1010
1011   /* pixels */
1012   " X              ",
1013   "X.X             ",
1014   " X              ",
1015   "                ",
1016   "                ",
1017   "                ",
1018   "                ",
1019   "                ",
1020   "                ",
1021   "                ",
1022   "                ",
1023   "                ",
1024   "                ",
1025   "                ",
1026   "                ",
1027   "                ",
1028
1029   /* hot spot */
1030   "1,1"
1031 #endif
1032 };
1033
1034 #if defined(TARGET_SDL)
1035 static const int cursor_bit_order = BIT_ORDER_MSB;
1036 #elif defined(TARGET_X11_NATIVE)
1037 static const int cursor_bit_order = BIT_ORDER_LSB;
1038 #endif
1039
1040 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1041 {
1042   struct MouseCursorInfo *cursor;
1043   boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1044   int header_lines = 4;
1045   int x, y, i;
1046
1047   cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1048
1049   sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1050
1051   i = -1;
1052   for (y = 0; y < cursor->width; y++)
1053   {
1054     for (x = 0; x < cursor->height; x++)
1055     {
1056       int bit_nr = x % 8;
1057       int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1058
1059       if (bit_nr == 0)
1060       {
1061         i++;
1062         cursor->data[i] = cursor->mask[i] = 0;
1063       }
1064
1065       switch (image[header_lines + y][x])
1066       {
1067         case 'X':
1068           cursor->data[i] |= bit_mask;
1069           cursor->mask[i] |= bit_mask;
1070           break;
1071
1072         case '.':
1073           cursor->mask[i] |= bit_mask;
1074           break;
1075
1076         case ' ':
1077           break;
1078       }
1079     }
1080   }
1081
1082   sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1083
1084   return cursor;
1085 }
1086 #endif  /* !PLATFORM_MSDOS */
1087
1088 void SetMouseCursor(int mode)
1089 {
1090 #if !defined(PLATFORM_MSDOS)
1091   static struct MouseCursorInfo *cursor_playfield = NULL;
1092
1093   if (cursor_playfield == NULL)
1094     cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1095
1096 #if defined(TARGET_SDL)
1097   SDLSetMouseCursor(mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1098 #elif defined(TARGET_X11_NATIVE)
1099   X11SetMouseCursor(mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1100 #endif
1101 #endif
1102 }
1103
1104
1105 /* ========================================================================= */
1106 /* audio functions                                                           */
1107 /* ========================================================================= */
1108
1109 void OpenAudio(void)
1110 {
1111   /* always start with reliable default values */
1112   audio.sound_available = FALSE;
1113   audio.music_available = FALSE;
1114   audio.loops_available = FALSE;
1115
1116   audio.sound_enabled = FALSE;
1117   audio.sound_deactivated = FALSE;
1118
1119   audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1120   audio.mixer_pid = 0;
1121   audio.device_name = NULL;
1122   audio.device_fd = -1;
1123
1124   audio.num_channels = 0;
1125   audio.music_channel = 0;
1126   audio.first_sound_channel = 0;
1127
1128 #if defined(TARGET_SDL)
1129   SDLOpenAudio();
1130 #elif defined(PLATFORM_UNIX)
1131   UnixOpenAudio();
1132 #elif defined(PLATFORM_MSDOS)
1133   MSDOSOpenAudio();
1134 #endif
1135 }
1136
1137 void CloseAudio(void)
1138 {
1139 #if defined(TARGET_SDL)
1140   SDLCloseAudio();
1141 #elif defined(PLATFORM_UNIX)
1142   UnixCloseAudio();
1143 #elif defined(PLATFORM_MSDOS)
1144   MSDOSCloseAudio();
1145 #endif
1146
1147   audio.sound_enabled = FALSE;
1148 }
1149
1150 void SetAudioMode(boolean enabled)
1151 {
1152   if (!audio.sound_available)
1153     return;
1154
1155   audio.sound_enabled = enabled;
1156 }
1157
1158
1159 /* ========================================================================= */
1160 /* event functions                                                           */
1161 /* ========================================================================= */
1162
1163 void InitEventFilter(EventFilter filter_function)
1164 {
1165 #if defined(TARGET_SDL)
1166   /* set event filter to filter out certain events */
1167   SDL_SetEventFilter(filter_function);
1168 #endif
1169 }
1170
1171 boolean PendingEvent(void)
1172 {
1173 #if defined(TARGET_SDL)
1174   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1175 #else
1176   return (XPending(display) ? TRUE : FALSE);
1177 #endif
1178 }
1179
1180 void NextEvent(Event *event)
1181 {
1182 #if defined(TARGET_SDL)
1183   SDLNextEvent(event);
1184 #else
1185   XNextEvent(display, event);
1186 #endif
1187 }
1188
1189 void PeekEvent(Event *event)
1190 {
1191 #if defined(TARGET_SDL)
1192   SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1193 #else
1194   XPeekEvent(display, event);
1195 #endif
1196 }
1197
1198 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1199 {
1200 #if defined(TARGET_SDL)
1201
1202 #if 0
1203   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1204          (int)event->keysym.unicode,
1205          (int)event->keysym.sym,
1206          (int)SDL_GetModState());
1207 #endif
1208
1209   if (with_modifiers &&
1210       event->keysym.unicode > 0x0000 &&
1211       event->keysym.unicode < 0x2000)
1212     return event->keysym.unicode;
1213   else
1214     return event->keysym.sym;
1215
1216 #else
1217
1218 #if 0
1219   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1220          (int)XLookupKeysym(event, event->state),
1221          (int)XLookupKeysym(event, 0));
1222 #endif
1223
1224   if (with_modifiers)
1225     return XLookupKeysym(event, event->state);
1226   else
1227     return XLookupKeysym(event, 0);
1228 #endif
1229 }
1230
1231 KeyMod HandleKeyModState(Key key, int key_status)
1232 {
1233   static KeyMod current_modifiers = KMOD_None;
1234
1235   if (key != KSYM_UNDEFINED)    /* new key => check for modifier key change */
1236   {
1237     KeyMod new_modifier = KMOD_None;
1238
1239     switch(key)
1240     {
1241       case KSYM_Shift_L:
1242         new_modifier = KMOD_Shift_L;
1243         break;
1244       case KSYM_Shift_R:
1245         new_modifier = KMOD_Shift_R;
1246         break;
1247       case KSYM_Control_L:
1248         new_modifier = KMOD_Control_L;
1249         break;
1250       case KSYM_Control_R:
1251         new_modifier = KMOD_Control_R;
1252         break;
1253       case KSYM_Meta_L:
1254         new_modifier = KMOD_Meta_L;
1255         break;
1256       case KSYM_Meta_R:
1257         new_modifier = KMOD_Meta_R;
1258         break;
1259       case KSYM_Alt_L:
1260         new_modifier = KMOD_Alt_L;
1261         break;
1262       case KSYM_Alt_R:
1263         new_modifier = KMOD_Alt_R;
1264         break;
1265       default:
1266         break;
1267     }
1268
1269     if (key_status == KEY_PRESSED)
1270       current_modifiers |= new_modifier;
1271     else
1272       current_modifiers &= ~new_modifier;
1273   }
1274
1275   return current_modifiers;
1276 }
1277
1278 KeyMod GetKeyModState()
1279 {
1280 #if defined(TARGET_SDL)
1281   return (KeyMod)SDL_GetModState();
1282 #else
1283   return HandleKeyModState(KSYM_UNDEFINED, 0);
1284 #endif
1285 }
1286
1287 KeyMod GetKeyModStateFromEvents()
1288 {
1289   /* always use key modifier state as tracked from key events (this is needed
1290      if the modifier key event was injected into the event queue, but the key
1291      was not really pressed on keyboard -- SDL_GetModState() seems to directly
1292      query the keys as held pressed on the keyboard) -- this case is currently
1293      only used to filter out clipboard insert events from "True X-Mouse" tool */
1294
1295   return HandleKeyModState(KSYM_UNDEFINED, 0);
1296 }
1297
1298 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1299 {
1300   if (event->type != EVENT_CLIENTMESSAGE)
1301     return FALSE;
1302
1303 #if defined(TARGET_SDL)
1304   return TRUE;          /* the only possible message here is SDL_QUIT */
1305 #elif defined(PLATFORM_UNIX)
1306   if ((event->window == window->drawable) &&
1307       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1308     return TRUE;
1309 #endif
1310
1311   return FALSE;
1312 }
1313
1314
1315 /* ========================================================================= */
1316 /* joystick functions                                                        */
1317 /* ========================================================================= */
1318
1319 void InitJoysticks()
1320 {
1321   int i;
1322
1323 #if defined(NO_JOYSTICK)
1324   return;       /* joysticks generally deactivated by compile-time directive */
1325 #endif
1326
1327   /* always start with reliable default values */
1328   joystick.status = JOYSTICK_NOT_AVAILABLE;
1329   for (i = 0; i < MAX_PLAYERS; i++)
1330     joystick.fd[i] = -1;                /* joystick device closed */
1331
1332 #if defined(TARGET_SDL)
1333   SDLInitJoysticks();
1334 #elif defined(PLATFORM_UNIX)
1335   UnixInitJoysticks();
1336 #elif defined(PLATFORM_MSDOS)
1337   MSDOSInitJoysticks();
1338 #endif
1339
1340 #if 0
1341   for (i = 0; i < MAX_PLAYERS; i++)
1342     printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1343 #endif
1344 }
1345
1346 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1347 {
1348 #if defined(TARGET_SDL)
1349   return SDLReadJoystick(nr, x, y, b1, b2);
1350 #elif defined(PLATFORM_UNIX)
1351   return UnixReadJoystick(nr, x, y, b1, b2);
1352 #elif defined(PLATFORM_MSDOS)
1353   return MSDOSReadJoystick(nr, x, y, b1, b2);
1354 #endif
1355 }