1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
27 /* ========================================================================= */
28 /* exported variables */
29 /* ========================================================================= */
31 struct ProgramInfo program;
32 struct OptionInfo options;
33 struct VideoSystemInfo video;
34 struct AudioSystemInfo audio;
36 struct ArtworkInfo artwork;
37 struct JoystickInfo joystick;
38 struct SetupInfo setup;
40 LevelDirTree *leveldir_first_all = NULL;
41 LevelDirTree *leveldir_first = NULL;
42 LevelDirTree *leveldir_current = NULL;
45 struct LevelStats level_stats[MAX_LEVELS];
47 Display *display = NULL;
48 Visual *visual = NULL;
52 DrawWindow *window = NULL;
53 DrawBuffer *backbuffer = NULL;
54 DrawBuffer *drawto = NULL;
56 int button_status = MB_NOT_PRESSED;
57 boolean motion_status = FALSE;
58 #if defined(TARGET_SDL2)
59 boolean keyrepeat_status = TRUE;
62 int redraw_mask = REDRAW_NONE;
68 /* ========================================================================= */
69 /* init/close functions */
70 /* ========================================================================= */
72 void InitProgramInfo(char *argv0,
73 char *userdata_subdir, char *userdata_subdir_unix,
79 char *x11_icon_filename, char *x11_iconmask_filename,
80 char *sdl_icon_filename,
81 char *cookie_prefix, char *filename_prefix,
84 program.command_basepath = getBasePath(argv0);
85 program.command_basename = getBaseName(argv0);
87 program.userdata_subdir = userdata_subdir;
88 program.userdata_subdir_unix = userdata_subdir_unix;
89 program.userdata_path = getUserGameDataDir();
91 program.program_title = program_title;
93 program.window_title = "(undefined)";
95 program.window_title = window_title;
97 program.icon_title = icon_title;
99 program.x11_icon_filename = x11_icon_filename;
100 program.x11_iconmask_filename = x11_iconmask_filename;
101 program.sdl_icon_filename = sdl_icon_filename;
103 program.cookie_prefix = cookie_prefix;
104 program.filename_prefix = filename_prefix;
106 program.version_major = VERSION_MAJOR(program_version);
107 program.version_minor = VERSION_MINOR(program_version);
108 program.version_patch = VERSION_PATCH(program_version);
110 program.error_filename = getErrorFilename(ERROR_BASENAME);
111 program.error_file = stderr;
114 void SetWindowTitle()
116 program.window_title = program.window_title_function();
118 #if defined(TARGET_SDL)
123 void InitWindowTitleFunction(char *(*window_title_function)(void))
125 program.window_title_function = window_title_function;
128 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
130 program.exit_message_function = exit_message_function;
133 void InitExitFunction(void (*exit_function)(int))
135 program.exit_function = exit_function;
137 /* set signal handlers to custom exit function */
138 signal(SIGINT, exit_function);
139 signal(SIGTERM, exit_function);
141 #if defined(TARGET_SDL)
142 /* set exit function to automatically cleanup SDL stuff after exit() */
147 void InitPlatformDependentStuff(void)
149 // this is initialized in GetOptions(), but may already be used before
150 options.verbose = TRUE;
152 #if defined(PLATFORM_MACOSX)
153 updateUserGameDataDir();
159 #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX)
164 #if defined(TARGET_SDL)
165 #if defined(TARGET_SDL2)
166 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
168 int sdl_init_flags = SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE;
171 if (SDL_Init(sdl_init_flags) < 0)
172 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
178 void ClosePlatformDependentStuff(void)
180 #if defined(PLATFORM_WIN32)
185 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
186 int real_sx, int real_sy,
187 int full_sxsize, int full_sysize,
188 Bitmap *field_save_buffer)
194 gfx.real_sx = real_sx;
195 gfx.real_sy = real_sy;
196 gfx.full_sxsize = full_sxsize;
197 gfx.full_sysize = full_sysize;
199 gfx.field_save_buffer = field_save_buffer;
202 gfx.background_bitmap = NULL;
203 gfx.background_bitmap_mask = REDRAW_NONE;
206 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
207 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
210 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
218 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
226 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
234 void InitGfxWindowInfo(int win_xsize, int win_ysize)
236 gfx.win_xsize = win_xsize;
237 gfx.win_ysize = win_ysize;
240 gfx.background_bitmap_mask = REDRAW_NONE;
242 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
246 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
248 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
249 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
250 gfx.scrollbuffer_width = scrollbuffer_width;
251 gfx.scrollbuffer_height = scrollbuffer_height;
254 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
256 gfx.clipping_enabled = enabled;
259 gfx.clip_width = width;
260 gfx.clip_height = height;
263 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
265 gfx.draw_busy_anim_function = draw_busy_anim_function;
268 void InitGfxCustomArtworkInfo()
270 gfx.override_level_graphics = FALSE;
271 gfx.override_level_sounds = FALSE;
272 gfx.override_level_music = FALSE;
274 gfx.draw_init_text = TRUE;
277 void SetDrawDeactivationMask(int draw_deactivation_mask)
279 gfx.draw_deactivation_mask = draw_deactivation_mask;
282 void SetDrawBackgroundMask(int draw_background_mask)
284 gfx.draw_background_mask = draw_background_mask;
289 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
290 int dest_x, int dest_y, int width, int height)
292 int bitmap_xsize = width;
293 int bitmap_ysize = height;
294 int tile_xsize = tile->width;
295 int tile_ysize = tile->height;
296 int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
297 int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
300 for (y = 0; y < tile_ysteps; y++)
302 for (x = 0; x < tile_xsteps; x++)
304 int draw_x = dest_x + x * tile_xsize;
305 int draw_y = dest_y + y * tile_ysize;
306 int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
307 int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
309 BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
314 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
316 if (background_bitmap_tile != NULL)
317 gfx.background_bitmap_mask |= mask;
319 gfx.background_bitmap_mask &= ~mask;
322 if (gfx.background_bitmap == NULL)
323 gfx.background_bitmap = CreateBitmap(video.width, video.height,
327 if (background_bitmap_tile == NULL) /* empty background requested */
330 if (mask == REDRAW_ALL)
331 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
332 0, 0, video.width, video.height);
333 else if (mask == REDRAW_FIELD)
334 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
335 gfx.real_sx, gfx.real_sy,
336 gfx.full_sxsize, gfx.full_sysize);
337 else if (mask == REDRAW_DOOR_1)
338 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
340 gfx.dxsize, gfx.dysize);
345 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
347 if (background_bitmap_tile != NULL)
348 gfx.background_bitmap_mask |= mask;
350 gfx.background_bitmap_mask &= ~mask;
353 if (gfx.background_bitmap == NULL)
354 gfx.background_bitmap = CreateBitmap(video.width, video.height,
358 if (background_bitmap_tile == NULL) /* empty background requested */
361 if (mask == REDRAW_ALL)
362 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
363 0, 0, video.width, video.height);
364 else if (mask == REDRAW_FIELD)
365 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
366 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
367 else if (mask == REDRAW_DOOR_1)
368 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
369 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
374 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
376 /* remove every mask before setting mask for window */
377 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
378 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
379 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
382 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
384 /* remove window area mask before setting mask for main area */
385 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
386 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
387 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
390 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
392 /* remove window area mask before setting mask for door area */
393 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
394 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
395 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
399 /* ========================================================================= */
400 /* video functions */
401 /* ========================================================================= */
403 inline static int GetRealDepth(int depth)
405 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
408 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
409 int width, int height, Pixel color)
411 #if defined(TARGET_SDL)
412 SDLFillRectangle(bitmap, x, y, width, height, color);
414 X11FillRectangle(bitmap, x, y, width, height, color);
418 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
419 int src_x, int src_y, int width, int height,
420 int dst_x, int dst_y, int mask_mode)
422 #if defined(TARGET_SDL)
423 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
424 dst_x, dst_y, mask_mode);
426 X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
427 dst_x, dst_y, mask_mode);
431 void LimitScreenUpdates(boolean enable)
433 #if defined(TARGET_SDL)
434 SDLLimitScreenUpdates(enable);
438 void InitVideoDisplay(void)
440 #if defined(TARGET_SDL)
441 SDLInitVideoDisplay();
443 X11InitVideoDisplay();
447 void CloseVideoDisplay(void)
449 KeyboardAutoRepeatOn();
451 #if defined(TARGET_SDL)
452 SDL_QuitSubSystem(SDL_INIT_VIDEO);
455 XCloseDisplay(display);
459 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
462 printf("::: InitVideoBuffer\n");
466 video.height = height;
467 video.depth = GetRealDepth(depth);
469 video.fullscreen_available = FULLSCREEN_STATUS;
470 video.fullscreen_enabled = FALSE;
471 // video.fullscreen_initial = FALSE;
473 video.fullscreen_mode_current = NULL;
474 video.fullscreen_modes = NULL;
477 video.window_scaling_available = WINDOW_SCALING_STATUS;
479 #if defined(TARGET_SDL)
480 SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
482 X11InitVideoBuffer(&backbuffer, &window);
488 inline static void FreeBitmapPointers(Bitmap *bitmap)
493 #if defined(TARGET_SDL)
494 SDLFreeBitmapPointers(bitmap);
496 X11FreeBitmapPointers(bitmap);
499 checked_free(bitmap->source_filename);
500 bitmap->source_filename = NULL;
503 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
506 if (src_bitmap == NULL || dst_bitmap == NULL)
509 FreeBitmapPointers(dst_bitmap);
511 *dst_bitmap = *src_bitmap;
514 void FreeBitmap(Bitmap *bitmap)
519 FreeBitmapPointers(bitmap);
524 Bitmap *CreateBitmapStruct(void)
526 #if defined(TARGET_SDL)
527 return checked_calloc(sizeof(struct SDLSurfaceInfo));
529 return checked_calloc(sizeof(struct X11DrawableInfo));
533 Bitmap *CreateBitmap(int width, int height, int depth)
535 Bitmap *new_bitmap = CreateBitmapStruct();
536 int real_width = MAX(1, width); /* prevent zero bitmap width */
537 int real_height = MAX(1, height); /* prevent zero bitmap height */
538 int real_depth = GetRealDepth(depth);
540 #if defined(TARGET_SDL)
541 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
543 X11CreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
546 new_bitmap->width = real_width;
547 new_bitmap->height = real_height;
552 void ReCreateBitmap(Bitmap **bitmap, int width, int height, int depth)
554 Bitmap *new_bitmap = CreateBitmap(width, height, depth);
558 *bitmap = new_bitmap;
562 TransferBitmapPointers(new_bitmap, *bitmap);
567 void CloseWindow(DrawWindow *window)
569 #if defined(TARGET_X11)
570 X11CloseWindow(window);
574 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
577 if (draw_mask == REDRAW_NONE)
580 if (draw_mask & REDRAW_ALL)
584 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
587 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
590 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
593 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
596 if ((draw_mask & REDRAW_FIELD) &&
597 x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize)
600 if ((draw_mask & REDRAW_DOOR_1) &&
601 x >= gfx.dx && y < gfx.dy + gfx.dysize)
604 if ((draw_mask & REDRAW_DOOR_2) &&
605 x >= gfx.dx && y >= gfx.vy)
612 boolean DrawingDeactivated(int x, int y, int width, int height)
614 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
617 boolean DrawingOnBackground(int x, int y)
619 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
620 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
623 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
624 int *width, int *height, boolean is_dest)
627 int clip_x, clip_y, clip_width, clip_height;
629 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
631 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
632 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
633 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
634 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
640 clip_width = bitmap->width;
641 clip_height = bitmap->height;
644 /* skip if rectangle completely outside bitmap */
646 if (*x + *width <= clip_x ||
647 *y + *height <= clip_y ||
648 *x >= clip_x + clip_width ||
649 *y >= clip_y + clip_height)
652 /* clip if rectangle overlaps bitmap */
656 *width -= clip_x - *x;
659 else if (*x + *width > clip_x + clip_width)
661 *width = clip_x + clip_width - *x;
666 *height -= clip_y - *y;
669 else if (*y + *height > clip_y + clip_height)
671 *height = clip_y + clip_height - *y;
678 /* skip if rectangle completely outside bitmap */
680 if (*x + *width <= 0 ||
682 *x >= bitmap->width ||
683 *y >= bitmap->height)
686 /* clip if rectangle overlaps bitmap */
693 else if (*x + *width > bitmap->width)
695 *width = bitmap->width - *x;
703 else if (*y + *height > bitmap->height)
705 *height = bitmap->height - *y;
712 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
713 int src_x, int src_y, int width, int height,
714 int dst_x, int dst_y)
716 int dst_x_unclipped = dst_x;
717 int dst_y_unclipped = dst_y;
719 if (src_bitmap == NULL || dst_bitmap == NULL)
722 if (DrawingDeactivated(dst_x, dst_y, width, height))
726 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
727 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
730 /* source x/y might need adjustment if destination x/y was clipped top/left */
731 src_x += dst_x - dst_x_unclipped;
732 src_y += dst_y - dst_y_unclipped;
735 /* skip if rectangle starts outside bitmap */
736 if (src_x >= src_bitmap->width ||
737 src_y >= src_bitmap->height ||
738 dst_x >= dst_bitmap->width ||
739 dst_y >= dst_bitmap->height)
742 /* clip if rectangle overlaps bitmap */
743 if (src_x + width > src_bitmap->width)
744 width = src_bitmap->width - src_x;
745 if (src_y + height > src_bitmap->height)
746 height = src_bitmap->height - src_y;
747 if (dst_x + width > dst_bitmap->width)
748 width = dst_bitmap->width - dst_x;
749 if (dst_y + height > dst_bitmap->height)
750 height = dst_bitmap->height - dst_y;
754 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
756 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
757 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
758 but is already fixed in SVN and should therefore finally be fixed with
759 the next official SDL release, which is probably version 1.2.14.) */
761 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
762 //#if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
763 #if defined(TARGET_SDL2)
764 if (src_bitmap == dst_bitmap)
766 /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
768 /* needed when blitting directly to same bitmap -- should not be needed with
769 recent SDL libraries, but apparently does not work in 1.2.11 directly */
771 static Bitmap *tmp_bitmap = NULL;
772 static int tmp_bitmap_xsize = 0;
773 static int tmp_bitmap_ysize = 0;
775 /* start with largest static bitmaps for initial bitmap size ... */
776 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
778 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
779 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
782 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
783 if (src_bitmap->width > tmp_bitmap_xsize ||
784 src_bitmap->height > tmp_bitmap_ysize)
786 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
787 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
789 FreeBitmap(tmp_bitmap);
794 if (tmp_bitmap == NULL)
795 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
798 sysCopyArea(src_bitmap, tmp_bitmap,
799 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
800 sysCopyArea(tmp_bitmap, dst_bitmap,
801 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
811 if (dst_x < gfx.sx + gfx.sxsize)
812 printf("::: %d: BlitBitmap(%d, %d, %d, %d)\n",
813 FrameCounter, dst_x, dst_y, width, height);
816 sysCopyArea(src_bitmap, dst_bitmap,
817 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
820 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
821 int src_x, int src_y, int src_width, int src_height,
822 int dst_x, int dst_y, int dst_width, int dst_height)
824 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
825 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
826 int dst_xsize = dst_width;
827 int dst_ysize = dst_height;
828 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
829 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
832 for (y = 0; y < src_ysteps; y++)
834 for (x = 0; x < src_xsteps; x++)
836 int draw_x = dst_x + x * src_xsize;
837 int draw_y = dst_y + y * src_ysize;
838 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
839 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
841 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
847 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
848 int fade_mode, int fade_delay, int post_delay,
849 void (*draw_border_function)(void))
852 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
853 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
857 #if defined(TARGET_SDL)
858 SDLFadeRectangle(bitmap_cross, x, y, width, height,
859 fade_mode, fade_delay, post_delay, draw_border_function);
861 X11FadeRectangle(bitmap_cross, x, y, width, height,
862 fade_mode, fade_delay, post_delay, draw_border_function);
866 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
869 if (DrawingDeactivated(x, y, width, height))
873 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
876 /* skip if rectangle starts outside bitmap */
877 if (x >= bitmap->width ||
881 /* clip if rectangle overlaps bitmap */
882 if (x + width > bitmap->width)
883 width = bitmap->width - x;
884 if (y + height > bitmap->height)
885 height = bitmap->height - y;
888 sysFillRectangle(bitmap, x, y, width, height, color);
891 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
893 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
896 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
897 int width, int height)
899 if (DrawingOnBackground(x, y))
900 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
902 ClearRectangle(bitmap, x, y, width, height);
905 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
907 #if defined(TARGET_X11)
910 bitmap->clip_gc = clip_gc;
911 XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
916 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
918 #if defined(TARGET_X11)
921 bitmap->clip_gc = clip_gc;
922 XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
927 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
928 int src_x, int src_y, int width, int height,
929 int dst_x, int dst_y)
931 if (DrawingDeactivated(dst_x, dst_y, width, height))
934 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
935 dst_x, dst_y, BLIT_MASKED);
938 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
939 int src_x, int src_y, int width, int height,
940 int dst_x, int dst_y)
942 if (DrawingOnBackground(dst_x, dst_y))
944 /* draw background */
945 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
948 /* draw foreground */
949 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
950 dst_x - src_x, dst_y - src_y);
951 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
955 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
959 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
962 #if defined(TARGET_SDL)
963 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
965 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
969 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
972 #if defined(TARGET_SDL)
973 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
975 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
979 #if !defined(TARGET_X11_NATIVE)
980 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
981 int to_x, int to_y, Pixel pixel, int line_width)
985 for (x = 0; x < line_width; x++)
987 for (y = 0; y < line_width; y++)
989 int dx = x - line_width / 2;
990 int dy = y - line_width / 2;
992 if ((x == 0 && y == 0) ||
993 (x == 0 && y == line_width - 1) ||
994 (x == line_width - 1 && y == 0) ||
995 (x == line_width - 1 && y == line_width - 1))
998 #if defined(TARGET_SDL)
1000 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1001 #elif defined(TARGET_ALLEGRO)
1002 AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
1003 to_x + dx, to_y + dy, pixel);
1010 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1012 #if !defined(TARGET_X11_NATIVE)
1016 for (i = 0; i < num_points - 1; i++)
1017 DrawLine(bitmap, points[i].x, points[i].y,
1018 points[i + 1].x, points[i + 1].y, pixel, line_width);
1021 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1024 XSetForeground(display, bitmap->line_gc[1], pixel);
1025 XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
1026 (XPoint *)points, num_points, CoordModeOrigin);
1030 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1032 if (x < 0 || x >= bitmap->width ||
1033 y < 0 || y >= bitmap->height)
1036 #if defined(TARGET_SDL)
1037 return SDLGetPixel(bitmap, x, y);
1038 #elif defined(TARGET_ALLEGRO)
1039 return AllegroGetPixel(bitmap->drawable, x, y);
1041 return X11GetPixel(bitmap, x, y);
1045 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1046 unsigned int color_g, unsigned int color_b)
1048 #if defined(TARGET_SDL)
1049 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1050 #elif defined(TARGET_ALLEGRO)
1051 return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
1053 return X11GetPixelFromRGB(color_r, color_g, color_b);
1057 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1059 unsigned int color_r = (color >> 16) & 0xff;
1060 unsigned int color_g = (color >> 8) & 0xff;
1061 unsigned int color_b = (color >> 0) & 0xff;
1063 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1066 /* execute all pending screen drawing operations */
1067 void FlushDisplay(void)
1069 #if !defined(TARGET_SDL)
1074 /* execute and wait for all pending screen drawing operations */
1075 void SyncDisplay(void)
1077 #if !defined(TARGET_SDL)
1078 XSync(display, FALSE);
1082 void KeyboardAutoRepeatOn(void)
1084 #if defined(TARGET_SDL)
1085 #if defined(TARGET_SDL2)
1086 keyrepeat_status = TRUE;
1088 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1089 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1090 SDL_EnableUNICODE(1);
1094 XAutoRepeatOn(display);
1098 void KeyboardAutoRepeatOff(void)
1100 #if defined(TARGET_SDL)
1101 #if defined(TARGET_SDL2)
1102 keyrepeat_status = FALSE;
1104 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1105 SDL_EnableUNICODE(0);
1109 XAutoRepeatOff(display);
1113 boolean PointerInWindow(DrawWindow *window)
1115 #if defined(TARGET_SDL)
1123 /* if XQueryPointer() returns False, the pointer
1124 is not on the same screen as the specified window */
1125 return XQueryPointer(display, window->drawable, &root, &child,
1126 &root_x, &root_y, &win_x, &win_y, &mask);
1130 boolean SetVideoMode(boolean fullscreen)
1132 #if defined(TARGET_SDL)
1133 return SDLSetVideoMode(&backbuffer, fullscreen);
1135 boolean success = TRUE;
1137 if (fullscreen && video.fullscreen_available)
1139 Error(ERR_WARN, "fullscreen not available in X11 version");
1141 /* display error message only once */
1142 video.fullscreen_available = FALSE;
1151 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1153 #if defined(TARGET_SDL)
1154 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1155 (!fullscreen && video.fullscreen_enabled))
1156 fullscreen = SetVideoMode(fullscreen);
1162 Bitmap *LoadImage(char *filename)
1166 #if defined(TARGET_SDL)
1167 new_bitmap = SDLLoadImage(filename);
1169 new_bitmap = X11LoadImage(filename);
1173 new_bitmap->source_filename = getStringCopy(filename);
1178 Bitmap *LoadCustomImage(char *basename)
1180 char *filename = getCustomImageFilename(basename);
1183 if (filename == NULL)
1184 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1186 if ((new_bitmap = LoadImage(filename)) == NULL)
1187 Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
1192 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1194 char *filename = getCustomImageFilename(basename);
1197 if (filename == NULL) /* (should never happen) */
1199 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1203 if (strEqual(filename, bitmap->source_filename))
1205 /* The old and new image are the same (have the same filename and path).
1206 This usually means that this image does not exist in this graphic set
1207 and a fallback to the existing image is done. */
1212 if ((new_bitmap = LoadImage(filename)) == NULL)
1214 Error(ERR_WARN, "LoadImage() failed: %s", GetError());
1218 if (bitmap->width != new_bitmap->width ||
1219 bitmap->height != new_bitmap->height)
1221 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1223 FreeBitmap(new_bitmap);
1227 TransferBitmapPointers(new_bitmap, bitmap);
1231 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1233 Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
1235 #if defined(TARGET_SDL)
1236 SDLZoomBitmap(src_bitmap, dst_bitmap);
1238 X11ZoomBitmap(src_bitmap, dst_bitmap);
1244 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
1245 boolean create_small_bitmaps)
1249 Bitmap *tmp_bitmap_1;
1250 Bitmap *tmp_bitmap_2;
1251 Bitmap *tmp_bitmap_4;
1252 Bitmap *tmp_bitmap_8;
1253 Bitmap *tmp_bitmap_16;
1254 Bitmap *tmp_bitmap_32;
1255 int width_1, height_1;
1256 int width_2, height_2;
1257 int width_4, height_4;
1258 int width_8, height_8;
1259 int width_16, height_16;
1261 int width_32, height_32;
1263 int new_width, new_height;
1265 /* calculate new image dimensions for normal sized image */
1266 width_1 = old_bitmap->width * zoom_factor;
1267 height_1 = old_bitmap->height * zoom_factor;
1269 /* get image with normal size (this might require scaling up) */
1270 if (zoom_factor != 1)
1271 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1273 tmp_bitmap_1 = old_bitmap;
1275 /* this is only needed to make compilers happy */
1276 tmp_bitmap_2 = NULL;
1277 tmp_bitmap_4 = NULL;
1278 tmp_bitmap_8 = NULL;
1279 tmp_bitmap_16 = NULL;
1280 tmp_bitmap_32 = NULL;
1282 if (create_small_bitmaps)
1284 /* calculate new image dimensions for small images */
1285 width_2 = width_1 / 2;
1286 height_2 = height_1 / 2;
1287 width_4 = width_1 / 4;
1288 height_4 = height_1 / 4;
1289 width_8 = width_1 / 8;
1290 height_8 = height_1 / 8;
1291 width_16 = width_1 / 16;
1292 height_16 = height_1 / 16;
1294 width_32 = width_1 / 32;
1295 height_32 = height_1 / 32;
1298 UPDATE_BUSY_STATE();
1300 /* get image with 1/2 of normal size (for use in the level editor) */
1301 if (zoom_factor != 2)
1302 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
1304 tmp_bitmap_2 = old_bitmap;
1306 UPDATE_BUSY_STATE();
1308 /* get image with 1/4 of normal size (for use in the level editor) */
1309 if (zoom_factor != 4)
1310 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
1312 tmp_bitmap_4 = old_bitmap;
1314 UPDATE_BUSY_STATE();
1316 /* get image with 1/8 of normal size (for use on the preview screen) */
1317 if (zoom_factor != 8)
1318 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
1320 tmp_bitmap_8 = old_bitmap;
1322 UPDATE_BUSY_STATE();
1324 /* get image with 1/16 of normal size (for use on the preview screen) */
1325 if (zoom_factor != 16)
1326 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1328 tmp_bitmap_16 = old_bitmap;
1330 UPDATE_BUSY_STATE();
1332 /* get image with 1/32 of normal size (for use on the preview screen) */
1333 if (zoom_factor != 32)
1334 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1336 tmp_bitmap_32 = old_bitmap;
1338 UPDATE_BUSY_STATE();
1342 /* if image was scaled up, create new clipmask for normal size image */
1343 if (zoom_factor != 1)
1345 #if defined(TARGET_X11)
1346 if (old_bitmap->clip_mask)
1347 XFreePixmap(display, old_bitmap->clip_mask);
1349 old_bitmap->clip_mask =
1350 Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
1352 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1354 SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1356 if (old_bitmap->surface_masked)
1357 SDL_FreeSurface(old_bitmap->surface_masked);
1359 SDL_SetColorKey(tmp_surface_1, SET_TRANSPARENT_PIXEL,
1360 SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1361 if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1362 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1363 SDL_SetColorKey(tmp_surface_1, UNSET_TRANSPARENT_PIXEL, 0);
1368 if (create_small_bitmaps)
1370 new_width = width_1;
1371 new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */
1373 new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1375 BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1376 BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1378 BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1379 width_1 / 2, height_1);
1380 BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1381 3 * width_1 / 4, height_1);
1382 BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1383 7 * width_1 / 8, height_1);
1384 BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1385 15 * width_1 / 16, height_1);
1387 UPDATE_BUSY_STATE();
1391 new_width = width_1;
1392 new_height = height_1;
1394 new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
1397 if (create_small_bitmaps)
1399 /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1400 if (zoom_factor != 1)
1401 FreeBitmap(tmp_bitmap_1);
1403 if (zoom_factor != 2)
1404 FreeBitmap(tmp_bitmap_2);
1406 if (zoom_factor != 4)
1407 FreeBitmap(tmp_bitmap_4);
1409 if (zoom_factor != 8)
1410 FreeBitmap(tmp_bitmap_8);
1412 if (zoom_factor != 16)
1413 FreeBitmap(tmp_bitmap_16);
1415 if (zoom_factor != 32)
1416 FreeBitmap(tmp_bitmap_32);
1419 /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1420 #if defined(TARGET_SDL)
1421 swap_bitmap.surface = old_bitmap->surface;
1422 old_bitmap->surface = new_bitmap->surface;
1423 new_bitmap->surface = swap_bitmap.surface;
1425 swap_bitmap.drawable = old_bitmap->drawable;
1426 old_bitmap->drawable = new_bitmap->drawable;
1427 new_bitmap->drawable = swap_bitmap.drawable;
1430 old_bitmap->width = new_bitmap->width;
1431 old_bitmap->height = new_bitmap->height;
1434 /* this replaces all blit masks created when loading -- maybe optimize this */
1436 #if defined(TARGET_X11)
1437 if (old_bitmap->clip_mask)
1438 XFreePixmap(display, old_bitmap->clip_mask);
1440 old_bitmap->clip_mask =
1441 Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1443 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1445 SDL_Surface *old_surface = old_bitmap->surface;
1447 if (old_bitmap->surface_masked)
1448 SDL_FreeSurface(old_bitmap->surface_masked);
1450 SDL_SetColorKey(old_surface, SET_TRANSPARENT_PIXEL,
1451 SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1452 if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1453 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1454 SDL_SetColorKey(old_surface, UNSET_TRANSPARENT_PIXEL, 0);
1459 UPDATE_BUSY_STATE();
1461 FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */
1464 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1466 CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1469 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1471 CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1475 /* ------------------------------------------------------------------------- */
1476 /* mouse pointer functions */
1477 /* ------------------------------------------------------------------------- */
1479 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1481 /* XPM image definitions */
1482 static const char *cursor_image_none[] =
1484 /* width height num_colors chars_per_pixel */
1514 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1515 static const char *cursor_image_dot[] =
1517 /* width height num_colors chars_per_pixel */
1546 static const char **cursor_image_playfield = cursor_image_dot;
1548 /* some people complained about a "white dot" on the screen and thought it
1549 was a graphical error... OK, let's just remove the whole pointer :-) */
1550 static const char **cursor_image_playfield = cursor_image_none;
1553 #if defined(TARGET_SDL)
1554 static const int cursor_bit_order = BIT_ORDER_MSB;
1555 #elif defined(TARGET_X11_NATIVE)
1556 static const int cursor_bit_order = BIT_ORDER_LSB;
1559 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1561 struct MouseCursorInfo *cursor;
1562 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1563 int header_lines = 4;
1566 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1568 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1571 for (y = 0; y < cursor->width; y++)
1573 for (x = 0; x < cursor->height; x++)
1576 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1581 cursor->data[i] = cursor->mask[i] = 0;
1584 switch (image[header_lines + y][x])
1587 cursor->data[i] |= bit_mask;
1588 cursor->mask[i] |= bit_mask;
1592 cursor->mask[i] |= bit_mask;
1601 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1606 void SetMouseCursor(int mode)
1608 static struct MouseCursorInfo *cursor_none = NULL;
1609 static struct MouseCursorInfo *cursor_playfield = NULL;
1610 struct MouseCursorInfo *cursor_new;
1612 if (cursor_none == NULL)
1613 cursor_none = get_cursor_from_image(cursor_image_none);
1615 if (cursor_playfield == NULL)
1616 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1618 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1619 mode == CURSOR_NONE ? cursor_none :
1620 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1622 #if defined(TARGET_SDL)
1623 SDLSetMouseCursor(cursor_new);
1624 #elif defined(TARGET_X11_NATIVE)
1625 X11SetMouseCursor(cursor_new);
1630 /* ========================================================================= */
1631 /* audio functions */
1632 /* ========================================================================= */
1634 void OpenAudio(void)
1636 /* always start with reliable default values */
1637 audio.sound_available = FALSE;
1638 audio.music_available = FALSE;
1639 audio.loops_available = FALSE;
1641 audio.sound_enabled = FALSE;
1642 audio.sound_deactivated = FALSE;
1644 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1645 audio.mixer_pid = 0;
1646 audio.device_name = NULL;
1647 audio.device_fd = -1;
1649 audio.num_channels = 0;
1650 audio.music_channel = 0;
1651 audio.first_sound_channel = 0;
1653 #if defined(TARGET_SDL)
1655 #elif defined(PLATFORM_UNIX)
1660 void CloseAudio(void)
1662 #if defined(TARGET_SDL)
1664 #elif defined(PLATFORM_UNIX)
1668 audio.sound_enabled = FALSE;
1671 void SetAudioMode(boolean enabled)
1673 if (!audio.sound_available)
1676 audio.sound_enabled = enabled;
1680 /* ========================================================================= */
1681 /* event functions */
1682 /* ========================================================================= */
1684 void InitEventFilter(EventFilter filter_function)
1686 /* set event filter to filter out certain events */
1687 #if defined(TARGET_SDL)
1688 #if defined(TARGET_SDL2)
1689 SDL_SetEventFilter(filter_function, NULL);
1691 SDL_SetEventFilter(filter_function);
1696 boolean PendingEvent(void)
1698 #if defined(TARGET_SDL)
1699 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1701 return (XPending(display) ? TRUE : FALSE);
1705 void NextEvent(Event *event)
1707 #if defined(TARGET_SDL)
1708 SDLNextEvent(event);
1710 XNextEvent(display, event);
1714 void PeekEvent(Event *event)
1716 #if defined(TARGET_SDL)
1717 #if defined(TARGET_SDL2)
1718 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1720 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1723 XPeekEvent(display, event);
1727 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1729 #if defined(TARGET_SDL)
1730 #if defined(TARGET_SDL2)
1731 /* key up/down events in SDL2 do not return text characters anymore */
1732 return event->keysym.sym;
1736 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1737 (int)event->keysym.unicode,
1738 (int)event->keysym.sym,
1739 (int)SDL_GetModState());
1742 if (with_modifiers &&
1743 event->keysym.unicode > 0x0000 &&
1744 event->keysym.unicode < 0x2000)
1745 return event->keysym.unicode;
1747 return event->keysym.sym;
1753 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1754 (int)XLookupKeysym(event, event->state),
1755 (int)XLookupKeysym(event, 0));
1759 return XLookupKeysym(event, event->state);
1761 return XLookupKeysym(event, 0);
1765 KeyMod HandleKeyModState(Key key, int key_status)
1767 static KeyMod current_modifiers = KMOD_None;
1769 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1771 KeyMod new_modifier = KMOD_None;
1776 new_modifier = KMOD_Shift_L;
1779 new_modifier = KMOD_Shift_R;
1781 case KSYM_Control_L:
1782 new_modifier = KMOD_Control_L;
1784 case KSYM_Control_R:
1785 new_modifier = KMOD_Control_R;
1788 new_modifier = KMOD_Meta_L;
1791 new_modifier = KMOD_Meta_R;
1794 new_modifier = KMOD_Alt_L;
1797 new_modifier = KMOD_Alt_R;
1803 if (key_status == KEY_PRESSED)
1804 current_modifiers |= new_modifier;
1806 current_modifiers &= ~new_modifier;
1809 return current_modifiers;
1812 KeyMod GetKeyModState()
1814 #if defined(TARGET_SDL)
1815 return (KeyMod)SDL_GetModState();
1817 return HandleKeyModState(KSYM_UNDEFINED, 0);
1821 KeyMod GetKeyModStateFromEvents()
1823 /* always use key modifier state as tracked from key events (this is needed
1824 if the modifier key event was injected into the event queue, but the key
1825 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1826 query the keys as held pressed on the keyboard) -- this case is currently
1827 only used to filter out clipboard insert events from "True X-Mouse" tool */
1829 return HandleKeyModState(KSYM_UNDEFINED, 0);
1832 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1834 if (event->type != EVENT_CLIENTMESSAGE)
1837 #if defined(TARGET_SDL)
1838 return TRUE; /* the only possible message here is SDL_QUIT */
1839 #elif defined(PLATFORM_UNIX)
1840 if ((event->window == window->drawable) &&
1841 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1849 /* ========================================================================= */
1850 /* joystick functions */
1851 /* ========================================================================= */
1853 void InitJoysticks()
1857 #if defined(NO_JOYSTICK)
1858 return; /* joysticks generally deactivated by compile-time directive */
1861 /* always start with reliable default values */
1862 joystick.status = JOYSTICK_NOT_AVAILABLE;
1863 for (i = 0; i < MAX_PLAYERS; i++)
1864 joystick.fd[i] = -1; /* joystick device closed */
1866 #if defined(TARGET_SDL)
1868 #elif defined(PLATFORM_UNIX)
1869 UnixInitJoysticks();
1873 for (i = 0; i < MAX_PLAYERS; i++)
1874 printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1878 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1880 #if defined(TARGET_SDL)
1881 return SDLReadJoystick(nr, x, y, b1, b2);
1882 #elif defined(PLATFORM_UNIX)
1883 return UnixReadJoystick(nr, x, y, b1, b2);