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