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