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