rnd-20020803-1-src
[rocksndiamonds.git] / src / libgame / system.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * system.c                                                 *
12 ***********************************************************/
13
14 #include <string.h>
15 #include <signal.h>
16
17 #include "platform.h"
18
19 #if defined(PLATFORM_MSDOS)
20 #include <fcntl.h>
21 #endif
22
23 #include "system.h"
24 #include "sound.h"
25 #include "setup.h"
26 #include "joystick.h"
27 #include "misc.h"
28
29
30 /* ========================================================================= */
31 /* exported variables                                                        */
32 /* ========================================================================= */
33
34 struct ProgramInfo      program;
35 struct OptionInfo       options;
36 struct VideoSystemInfo  video;
37 struct AudioSystemInfo  audio;
38 struct GfxInfo          gfx;
39 struct ArtworkInfo      artwork;
40 struct JoystickInfo     joystick;
41 struct SetupInfo        setup;
42
43 LevelDirTree           *leveldir_first = NULL;
44 LevelDirTree           *leveldir_current = NULL;
45 int                     level_nr;
46
47 Display                *display = NULL;
48 Visual                 *visual = NULL;
49 int                     screen = 0;
50 Colormap                cmap = None;
51
52 DrawWindow             *window = NULL;
53 DrawBuffer             *backbuffer = NULL;
54 DrawBuffer             *drawto = NULL;
55
56 int                     button_status = MB_NOT_PRESSED;
57 boolean                 motion_status = FALSE;
58
59 int                     redraw_mask = REDRAW_NONE;
60 int                     redraw_tiles = 0;
61
62 int                     FrameCounter = 0;
63
64
65 /* ========================================================================= */
66 /* init/close functions                                                      */
67 /* ========================================================================= */
68
69 void InitCommandName(char *argv0)
70 {
71   program.command_basename =
72     (strrchr(argv0, '/') ? strrchr(argv0, '/') + 1 : argv0);
73 }
74
75 void InitExitFunction(void (*exit_function)(int))
76 {
77   program.exit_function = exit_function;
78
79   /* set signal handlers to custom exit function */
80   signal(SIGINT, exit_function);
81   signal(SIGTERM, exit_function);
82
83 #if defined(TARGET_SDL)
84   /* set exit function to automatically cleanup SDL stuff after exit() */
85   atexit(SDL_Quit);
86 #endif
87 }
88
89 void InitPlatformDependantStuff(void)
90 {
91 #if defined(PLATFORM_MSDOS)
92   _fmode = O_BINARY;
93 #endif
94
95 #if !defined(PLATFORM_UNIX)
96   program.userdata_directory = "userdata";
97   initErrorFile();
98 #endif
99
100 #if defined(TARGET_SDL)
101   if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
102     Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
103 #endif
104 }
105
106 void ClosePlatformDependantStuff(void)
107 {
108 #if !defined(PLATFORM_UNIX)
109   dumpErrorFile();
110 #endif
111 }
112
113 void InitProgramInfo(char *unix_userdata_directory, char *program_title,
114                      char *window_title, char *icon_title,
115                      char *x11_icon_filename, char *x11_iconmask_filename,
116                      char *msdos_pointer_filename,
117                      char *cookie_prefix, char *filename_prefix,
118                      int program_version)
119 {
120 #if defined(PLATFORM_UNIX)
121   program.userdata_directory = unix_userdata_directory;
122 #else
123   program.userdata_directory = "userdata";
124 #endif
125
126   program.program_title = program_title;
127   program.window_title = window_title;
128   program.icon_title = icon_title;
129   program.x11_icon_filename = x11_icon_filename;
130   program.x11_iconmask_filename = x11_iconmask_filename;
131   program.msdos_pointer_filename = msdos_pointer_filename;
132
133   program.cookie_prefix = cookie_prefix;
134   program.filename_prefix = filename_prefix;
135
136   program.version_major = VERSION_MAJOR(program_version);
137   program.version_minor = VERSION_MINOR(program_version);
138   program.version_patch = VERSION_PATCH(program_version);
139 }
140
141 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
142                       int real_sx, int real_sy,
143                       int full_sxsize, int full_sysize)
144 {
145   gfx.sx = sx;
146   gfx.sy = sy;
147   gfx.sxsize = sxsize;
148   gfx.sysize = sysize;
149   gfx.real_sx = real_sx;
150   gfx.real_sy = real_sy;
151   gfx.full_sxsize = full_sxsize;
152   gfx.full_sysize = full_sysize;
153
154   SetDrawDeactivationMask(REDRAW_NONE);         /* do not deactivate drawing */
155 }
156
157 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
158 {
159   gfx.dx = dx;
160   gfx.dy = dy;
161   gfx.dxsize = dxsize;
162   gfx.dysize = dysize;
163 }
164
165 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
166 {
167   gfx.vx = vx;
168   gfx.vy = vy;
169   gfx.vxsize = vxsize;
170   gfx.vysize = vysize;
171 }
172
173 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
174 {
175   /* currently only used by MSDOS code to alloc VRAM buffer, if available */
176   gfx.scrollbuffer_width = scrollbuffer_width;
177   gfx.scrollbuffer_height = scrollbuffer_height;
178 }
179
180 void SetDrawDeactivationMask(int draw_deactivation_mask)
181 {
182   gfx.draw_deactivation_mask = draw_deactivation_mask;
183 }
184
185
186 /* ========================================================================= */
187 /* video functions                                                           */
188 /* ========================================================================= */
189
190 inline static int GetRealDepth(int depth)
191 {
192   return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
193 }
194
195 inline void InitVideoDisplay(void)
196 {
197 #if defined(TARGET_SDL)
198   SDLInitVideoDisplay();
199 #else
200   X11InitVideoDisplay();
201 #endif
202 }
203
204 inline void CloseVideoDisplay(void)
205 {
206   KeyboardAutoRepeatOn();
207
208 #if defined(TARGET_SDL)
209   SDL_QuitSubSystem(SDL_INIT_VIDEO);
210 #else
211
212   if (display)
213     XCloseDisplay(display);
214 #endif
215 }
216
217 inline void InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
218                             int width, int height, int depth,
219                             boolean fullscreen)
220 {
221   video.width = width;
222   video.height = height;
223   video.depth = GetRealDepth(depth);
224   video.fullscreen_available = FULLSCREEN_STATUS;
225   video.fullscreen_enabled = FALSE;
226
227 #ifdef TARGET_SDL
228   SDLInitVideoBuffer(backbuffer, window, fullscreen);
229 #else
230   X11InitVideoBuffer(backbuffer, window);
231 #endif
232 }
233
234 inline Bitmap *CreateBitmapStruct(void)
235 {
236 #ifdef TARGET_SDL
237   return checked_calloc(sizeof(struct SDLSurfaceInfo));
238 #else
239   return checked_calloc(sizeof(struct X11DrawableInfo));
240 #endif
241 }
242
243 inline Bitmap *CreateBitmap(int width, int height, int depth)
244 {
245   Bitmap *new_bitmap = CreateBitmapStruct();
246   int real_depth = GetRealDepth(depth);
247
248 #ifdef TARGET_SDL
249   SDL_Surface *surface_tmp, *surface_native;
250
251   if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height,
252                                           real_depth, 0, 0, 0, 0))
253       == NULL)
254     Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
255
256   if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
257     Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
258
259   SDL_FreeSurface(surface_tmp);
260
261   new_bitmap->surface = surface_native;
262 #else
263   Pixmap pixmap;
264
265   if ((pixmap = XCreatePixmap(display, window->drawable,
266                               width, height, real_depth))
267       == None)
268     Error(ERR_EXIT, "cannot create pixmap");
269
270   new_bitmap->drawable = pixmap;
271
272   if (window == NULL)
273     Error(ERR_EXIT, "Window GC needed for Bitmap -- create Window first");
274
275   new_bitmap->gc = window->gc;
276
277   new_bitmap->line_gc[0] = window->line_gc[0];
278   new_bitmap->line_gc[1] = window->line_gc[1];
279 #endif
280
281   return new_bitmap;
282 }
283
284 inline static void FreeBitmapPointers(Bitmap *bitmap)
285 {
286   if (bitmap == NULL)
287     return;
288
289 #ifdef TARGET_SDL
290   if (bitmap->surface)
291     SDL_FreeSurface(bitmap->surface);
292   if (bitmap->surface_masked)
293     SDL_FreeSurface(bitmap->surface_masked);
294   bitmap->surface = NULL;
295   bitmap->surface_masked = NULL;
296 #else
297   /* The X11 version seems to have a memory leak here -- although
298      "XFreePixmap()" is called, the correspondig memory seems not
299      to be freed (according to "ps"). The SDL version apparently
300      does not have this problem. */
301
302   if (bitmap->drawable)
303     XFreePixmap(display, bitmap->drawable);
304   if (bitmap->clip_mask)
305     XFreePixmap(display, bitmap->clip_mask);
306   if (bitmap->stored_clip_gc)
307     XFreeGC(display, bitmap->stored_clip_gc);
308   /* the other GCs are only pointers to GCs used elsewhere */
309   bitmap->drawable = None;
310   bitmap->clip_mask = None;
311   bitmap->stored_clip_gc = None;
312 #endif
313
314   if (bitmap->source_filename)
315     free(bitmap->source_filename);
316   bitmap->source_filename = NULL;
317 }
318
319 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
320                                           Bitmap *dst_bitmap)
321 {
322   if (src_bitmap == NULL || dst_bitmap == NULL)
323     return;
324
325   FreeBitmapPointers(dst_bitmap);
326
327   *dst_bitmap = *src_bitmap;
328 }
329
330 inline void FreeBitmap(Bitmap *bitmap)
331 {
332   if (bitmap == NULL)
333     return;
334
335   FreeBitmapPointers(bitmap);
336
337   free(bitmap);
338 }
339
340 inline void CloseWindow(DrawWindow *window)
341 {
342 #ifdef TARGET_X11
343   if (window->drawable)
344   {
345     XUnmapWindow(display, window->drawable);
346     XDestroyWindow(display, window->drawable);
347   }
348   if (window->gc)
349     XFreeGC(display, window->gc);
350 #endif
351 }
352
353 inline boolean DrawingDeactivated(int x, int y, int width, int height)
354 {
355   if (gfx.draw_deactivation_mask != REDRAW_NONE)
356   {
357     if ((gfx.draw_deactivation_mask & REDRAW_FIELD) &&
358         x < gfx.sx + gfx.sxsize)
359       return TRUE;
360     else if ((gfx.draw_deactivation_mask & REDRAW_DOORS) &&
361              x > gfx.dx)
362     {
363       if ((gfx.draw_deactivation_mask & REDRAW_DOOR_1) &&
364           y < gfx.dy + gfx.dysize)
365         return TRUE;
366       else if ((gfx.draw_deactivation_mask & REDRAW_DOOR_2) &&
367                y > gfx.vy)
368         return TRUE;
369     }
370   }
371
372   return FALSE;
373 }
374
375 inline void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
376                        int src_x, int src_y,
377                        int width, int height,
378                        int dst_x, int dst_y)
379 {
380   if (DrawingDeactivated(dst_x, dst_y, width, height))
381     return;
382
383 #ifdef TARGET_SDL
384   SDLCopyArea(src_bitmap, dst_bitmap,
385               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_OPAQUE);
386 #else
387   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
388             dst_bitmap->gc, src_x, src_y, width, height, dst_x, dst_y);
389 #endif
390 }
391
392 inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
393 {
394   if (DrawingDeactivated(x, y, width, height))
395     return;
396
397 #ifdef TARGET_SDL
398   SDLFillRectangle(bitmap, x, y, width, height, 0x000000);
399 #else
400   XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
401 #endif
402 }
403
404 #if 0
405 #ifndef TARGET_SDL
406 static GC last_clip_gc = 0;     /* needed for XCopyArea() through clip mask */
407 #endif
408 #endif
409
410 inline void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
411 {
412 #ifdef TARGET_X11
413   if (clip_gc)
414   {
415     bitmap->clip_gc = clip_gc;
416     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
417   }
418 #if 0
419   last_clip_gc = clip_gc;
420 #endif
421 #endif
422 }
423
424 inline void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
425 {
426 #ifdef TARGET_X11
427   if (clip_gc)
428   {
429     bitmap->clip_gc = clip_gc;
430     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
431   }
432 #if 0
433   last_clip_gc = clip_gc;
434 #endif
435 #endif
436 }
437
438 inline void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
439                              int src_x, int src_y,
440                              int width, int height,
441                              int dst_x, int dst_y)
442 {
443   if (DrawingDeactivated(dst_x, dst_y, width, height))
444     return;
445
446 #ifdef TARGET_SDL
447   SDLCopyArea(src_bitmap, dst_bitmap,
448               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_MASKED);
449 #else
450   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
451             src_bitmap->clip_gc, src_x, src_y, width, height, dst_x, dst_y);
452 #endif
453 }
454
455 inline void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
456                                 int to_x, int to_y)
457 {
458 #ifdef TARGET_SDL
459   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, 0xffffff);
460 #else
461   XSetForeground(display, bitmap->gc, WhitePixel(display, screen));
462   XDrawLine(display, bitmap->drawable, bitmap->gc, from_x, from_y, to_x, to_y);
463   XSetForeground(display, bitmap->gc, BlackPixel(display, screen));
464 #endif
465 }
466
467 #if !defined(TARGET_X11_NATIVE)
468 inline void DrawLine(Bitmap *bitmap, int from_x, int from_y,
469                      int to_x, int to_y, Pixel pixel, int line_width)
470 {
471   int x, y;
472
473   for (x=0; x<line_width; x++)
474   {
475     for (y=0; y<line_width; y++)
476     {
477       int dx = x - line_width / 2;
478       int dy = y - line_width / 2;
479
480       if ((x == 0 && y == 0) ||
481           (x == 0 && y == line_width - 1) ||
482           (x == line_width - 1 && y == 0) ||
483           (x == line_width - 1 && y == line_width - 1))
484         continue;
485
486 #if defined(TARGET_SDL)
487       SDLDrawLine(bitmap,
488                   from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
489 #elif defined(TARGET_ALLEGRO)
490       AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
491                       to_x + dx, to_y + dy, pixel);
492 #endif
493     }
494   }
495 }
496 #endif
497
498 inline void DrawLines(Bitmap *bitmap, struct XY *points, int num_points,
499                       Pixel pixel)
500 {
501 #if !defined(TARGET_X11_NATIVE)
502   int line_width = 4;
503   int i;
504
505   for (i=0; i<num_points - 1; i++)
506     DrawLine(bitmap, points[i].x, points[i].y,
507              points[i + 1].x, points[i + 1].y, pixel, line_width);
508
509   /*
510   SDLDrawLines(bitmap->surface, points, num_points, pixel);
511   */
512 #else
513   XSetForeground(display, bitmap->line_gc[1], pixel);
514   XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
515              (XPoint *)points, num_points, CoordModeOrigin);
516   /*
517   XSetForeground(display, gc, BlackPixel(display, screen));
518   */
519 #endif
520 }
521
522 inline Pixel GetPixel(Bitmap *bitmap, int x, int y)
523 {
524 #if defined(TARGET_SDL)
525   return SDLGetPixel(bitmap, x, y);
526 #elif defined(TARGET_ALLEGRO)
527   return AllegroGetPixel(bitmap->drawable, x, y);
528 #else
529   unsigned long pixel_value;
530   XImage *pixel_image;
531
532   pixel_image = XGetImage(display, bitmap->drawable, x, y, 1, 1,
533                           AllPlanes, ZPixmap);
534   pixel_value = XGetPixel(pixel_image, 0, 0);
535
536   XDestroyImage(pixel_image);
537
538   return pixel_value;
539 #endif
540 }
541
542 inline Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
543                              unsigned int color_g, unsigned int color_b)
544 {
545   Pixel pixel;
546
547 #if defined(TARGET_SDL)
548   pixel = SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
549 #elif defined(TARGET_ALLEGRO)
550   pixel = AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
551 #elif defined(TARGET_X11_NATIVE)
552   XColor xcolor;
553
554   xcolor.flags = DoRed | DoGreen | DoBlue;
555   xcolor.red = (color_r << 8);
556   xcolor.green = (color_g << 8);
557   xcolor.blue = (color_b << 8);
558   XAllocColor(display, cmap, &xcolor);
559   pixel = xcolor.pixel;
560 #endif
561
562   return pixel;
563 }
564
565 inline Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
566 {
567   unsigned int color_r = (color >> 16) & 0xff;
568   unsigned int color_g = (color >>  8) & 0xff;
569   unsigned int color_b = (color >>  0) & 0xff;
570
571   return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
572 }
573
574 /* execute all pending screen drawing operations */
575 inline void FlushDisplay(void)
576 {
577 #ifndef TARGET_SDL
578   XFlush(display);
579 #endif
580 }
581
582 /* execute and wait for all pending screen drawing operations */
583 inline void SyncDisplay(void)
584 {
585 #ifndef TARGET_SDL
586   XSync(display, FALSE);
587 #endif
588 }
589
590 inline void KeyboardAutoRepeatOn(void)
591 {
592 #ifdef TARGET_SDL
593   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
594                       SDL_DEFAULT_REPEAT_INTERVAL / 2);
595   SDL_EnableUNICODE(1);
596 #else
597   if (display)
598     XAutoRepeatOn(display);
599 #endif
600 }
601
602 inline void KeyboardAutoRepeatOff(void)
603 {
604 #ifdef TARGET_SDL
605   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
606   SDL_EnableUNICODE(0);
607 #else
608   if (display)
609     XAutoRepeatOff(display);
610 #endif
611 }
612
613 inline boolean PointerInWindow(DrawWindow *window)
614 {
615 #ifdef TARGET_SDL
616   return TRUE;
617 #else
618   Window root, child;
619   int root_x, root_y;
620   unsigned int mask;
621   int win_x, win_y;
622
623   /* if XQueryPointer() returns False, the pointer
624      is not on the same screen as the specified window */
625   return XQueryPointer(display, window->drawable, &root, &child,
626                        &root_x, &root_y, &win_x, &win_y, &mask);
627 #endif
628 }
629
630 inline boolean SetVideoMode(boolean fullscreen)
631 {
632 #ifdef TARGET_SDL
633   return SDLSetVideoMode(&backbuffer, fullscreen);
634 #else
635   boolean success = TRUE;
636
637   if (fullscreen && video.fullscreen_available)
638   {
639     Error(ERR_WARN, "fullscreen not available in X11 version");
640
641     /* display error message only once */
642     video.fullscreen_available = FALSE;
643
644     success = FALSE;
645   }
646
647   return success;
648 #endif
649 }
650
651 inline boolean ChangeVideoModeIfNeeded(boolean fullscreen)
652 {
653 #ifdef TARGET_SDL
654   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
655       (!fullscreen && video.fullscreen_enabled))
656     fullscreen = SetVideoMode(fullscreen);
657 #endif
658
659   return fullscreen;
660 }
661
662 Bitmap *LoadImage(char *filename)
663 {
664   Bitmap *new_bitmap;
665
666 #if defined(TARGET_SDL)
667   new_bitmap = SDLLoadImage(filename);
668 #else
669   new_bitmap = X11LoadImage(filename);
670 #endif
671
672   if (new_bitmap)
673     new_bitmap->source_filename = getStringCopy(filename);
674
675   return new_bitmap;
676 }
677
678 Bitmap *LoadCustomImage(char *basename)
679 {
680   char *filename = getCustomImageFilename(basename);
681   Bitmap *new_bitmap;
682
683   if (filename == NULL)
684     Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
685
686   if ((new_bitmap = LoadImage(filename)) == NULL)
687     Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
688
689   return new_bitmap;
690 }
691
692 void ReloadCustomImage(Bitmap *bitmap, char *basename)
693 {
694   char *filename = getCustomImageFilename(basename);
695   Bitmap *new_bitmap;
696
697   if (filename == NULL)         /* (should never happen) */
698   {
699     Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
700     return;
701   }
702
703   if (strcmp(filename, bitmap->source_filename) == 0)
704   {
705     /* The old and new image are the same (have the same filename and path).
706        This usually means that this image does not exist in this graphic set
707        and a fallback to the existing image is done. */
708
709     return;
710   }
711
712   if ((new_bitmap = LoadImage(filename)) == NULL)
713   {
714     Error(ERR_WARN, "LoadImage() failed: %s", GetError());
715     return;
716   }
717
718   if (bitmap->width != new_bitmap->width ||
719       bitmap->height != new_bitmap->height)
720   {
721     Error(ERR_WARN, "ReloadCustomImage: new image has wrong dimensions");
722     FreeBitmap(new_bitmap);
723     return;
724   }
725
726   TransferBitmapPointers(new_bitmap, bitmap);
727   free(new_bitmap);
728 }
729
730
731 /* ========================================================================= */
732 /* audio functions                                                           */
733 /* ========================================================================= */
734
735 inline void OpenAudio(void)
736 {
737   /* always start with reliable default values */
738   audio.sound_available = FALSE;
739   audio.music_available = FALSE;
740   audio.loops_available = FALSE;
741
742   audio.sound_enabled = FALSE;
743   audio.sound_deactivated = FALSE;
744
745   audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
746   audio.mixer_pid = -1;
747   audio.device_name = NULL;
748   audio.device_fd = -1;
749
750   audio.num_channels = 0;
751   audio.music_channel = 0;
752   audio.first_sound_channel = 0;
753
754 #if defined(TARGET_SDL)
755   SDLOpenAudio();
756 #elif defined(PLATFORM_UNIX)
757   UnixOpenAudio();
758 #elif defined(PLATFORM_MSDOS)
759   MSDOSOpenAudio();
760 #endif
761 }
762
763 inline void CloseAudio(void)
764 {
765 #if defined(TARGET_SDL)
766   SDLCloseAudio();
767 #elif defined(PLATFORM_UNIX)
768   UnixCloseAudio();
769 #elif defined(PLATFORM_MSDOS)
770   MSDOSCloseAudio();
771 #endif
772
773   audio.sound_enabled = FALSE;
774 }
775
776 inline void SetAudioMode(boolean enabled)
777 {
778   if (!audio.sound_available)
779     return;
780
781   audio.sound_enabled = enabled;
782 }
783
784
785 /* ========================================================================= */
786 /* event functions                                                           */
787 /* ========================================================================= */
788
789 inline void InitEventFilter(EventFilter filter_function)
790 {
791 #ifdef TARGET_SDL
792   /* set event filter to filter out certain events */
793   SDL_SetEventFilter(filter_function);
794 #endif
795 }
796
797 inline boolean PendingEvent(void)
798 {
799 #ifdef TARGET_SDL
800   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
801 #else
802   return (XPending(display) ? TRUE : FALSE);
803 #endif
804 }
805
806 inline void NextEvent(Event *event)
807 {
808 #ifdef TARGET_SDL
809   SDLNextEvent(event);
810 #else
811   XNextEvent(display, event);
812 #endif
813 }
814
815 inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
816 {
817 #ifdef TARGET_SDL
818 #if 0
819   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
820          (int)event->keysym.unicode,
821          (int)event->keysym.sym,
822          (int)SDL_GetModState());
823 #endif
824
825   if (with_modifiers &&
826       event->keysym.unicode > 0x0000 &&
827       event->keysym.unicode < 0x2000)
828     return event->keysym.unicode;
829   else
830     return event->keysym.sym;
831 #else
832 #if 0
833   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
834          (int)XLookupKeysym(event, event->state),
835          (int)XLookupKeysym(event, 0));
836 #endif
837
838   if (with_modifiers)
839     return XLookupKeysym(event, event->state);
840   else
841     return XLookupKeysym(event, 0);
842 #endif
843 }
844
845 inline boolean CheckCloseWindowEvent(ClientMessageEvent *event)
846 {
847   if (event->type != EVENT_CLIENTMESSAGE)
848     return FALSE;
849
850 #if defined(TARGET_SDL)
851   return TRUE;          /* the only possible message here is SDL_QUIT */
852 #elif defined(PLATFORM_UNIX)
853   if ((event->window == window->drawable) &&
854       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
855     return TRUE;
856 #endif
857
858   return FALSE;
859 }
860
861
862 /* ========================================================================= */
863 /* joystick functions                                                        */
864 /* ========================================================================= */
865
866 inline void InitJoysticks()
867 {
868   int i;
869
870 #ifdef NO_JOYSTICK
871   return;       /* joysticks generally deactivated by compile-time directive */
872 #endif
873
874   /* always start with reliable default values */
875   joystick.status = JOYSTICK_NOT_AVAILABLE;
876   for (i=0; i<MAX_PLAYERS; i++)
877     joystick.fd[i] = -1;                /* joystick device closed */
878
879 #if defined(TARGET_SDL)
880   SDLInitJoysticks();
881 #elif defined(PLATFORM_UNIX)
882   UnixInitJoysticks();
883 #elif defined(PLATFORM_MSDOS)
884   MSDOSInitJoysticks();
885 #endif
886 }
887
888 inline boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
889 {
890 #if defined(TARGET_SDL)
891   return SDLReadJoystick(nr, x, y, b1, b2);
892 #elif defined(PLATFORM_UNIX)
893   return UnixReadJoystick(nr, x, y, b1, b2);
894 #elif defined(PLATFORM_MSDOS)
895   return MSDOSReadJoystick(nr, x, y, b1, b2);
896 #endif
897 }