Logo Search packages:      
Sourcecode: allegro4.2 version File versions  Download package

xwin.c

/*         ______   ___    ___
 *        /\  _  \ /\_ \  /\_ \
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Wrappers for Xlib functions.
 *
 *      By Michael Bukin.
 *
 *      Video mode switching by Peter Wang and Benjamin Stover.
 *
 *      X icon selection by Evert Glebbeek
 *
 *      See readme.txt for copyright information.
 */


#include "allegro.h"
#include "allegro/internal/aintern.h"
#include "allegro/platform/aintunix.h"
#include "xwin.h"

#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>

#ifdef ALLEGRO_XWINDOWS_WITH_SHM
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#endif

#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
#include <X11/extensions/xf86vmode.h>
#endif

#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
#include <X11/Xcursor/Xcursor.h>
#endif


#ifdef ALLEGRO_XWINDOWS_WITH_XPM
#include <X11/xpm.h>
#endif
#include "alex.xpm"


#define XWIN_DEFAULT_WINDOW_TITLE "Allegro application"
#define XWIN_DEFAULT_APPLICATION_NAME "allegro"
#define XWIN_DEFAULT_APPLICATION_CLASS "Allegro"


struct _xwin_type _xwin =
{
   0,           /* display */
   0,           /* lock count */
   0,           /* screen */
   None,        /* window */
   None,        /* gc */
   0,           /* visual */
   None,        /* colormap */
   0,           /* ximage */
#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
   None,        /* ARGB cursor image */
   XcursorFalse,/* Are ARGB cursors supported? */
#endif
   None,        /* cursor */
   XC_heart,    /* cursor_shape */
   1,           /* hw_cursor_ok */

   0,           /* screen_to_buffer */
   0,           /* set_colors */

   0,           /* screen_data */
   0,           /* screen_line */
   0,           /* buffer_line */

   0,           /* scroll_x */
   0,           /* scroll_y */

   320,         /* window_width */
   200,         /* window_height */
   8,           /* window_depth */

   320,         /* screen_width */
   200,         /* screen_height */
   8,           /* screen_depth */

   320,         /* virtual width */
   200,         /* virtual_height */

   0,           /* mouse_warped */
   { 0 },       /* keycode_to_scancode */

   0,           /* matching formats */
   0,           /* fast_visual_depth */
   0,           /* visual_is_truecolor */

   1,           /* rsize */
   1,           /* gsize */
   1,           /* bsize */
   0,           /* rshift */
   0,           /* gshift */
   0,           /* bshift */

   { 0 },       /* cmap */
   { 0 },       /* rmap */
   { 0 },       /* gmap */
   { 0 },       /* bmap */

#ifdef ALLEGRO_XWINDOWS_WITH_SHM
   { 0, 0, 0, 0 },  /* shminfo */
#endif
   0,           /* use_shm */

   0,           /* in_dga_mode */

   0,           /* keyboard_grabbed */
   0,           /* mouse_grabbed */

#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
   0,           /* modesinfo */
   0,           /* num_modes */
   0,           /* mode_switched */
   0,           /* override_redirected */
#endif

   XWIN_DEFAULT_WINDOW_TITLE,           /* window_title */
   XWIN_DEFAULT_APPLICATION_NAME,       /* application_name */
   XWIN_DEFAULT_APPLICATION_CLASS,      /* application_class */

   FALSE,       /* drawing_mode_ok */

#ifdef ALLEGRO_MULTITHREADED
   NULL,        /* mutex */
#endif

   NULL         /* window close hook */
};

void *allegro_icon = alex_xpm;

int _xwin_last_line = -1;
int _xwin_in_gfx_call = 0;

static COLORCONV_BLITTER_FUNC *blitter_func = NULL;
static int use_bgr_palette_hack = FALSE; /* use BGR hack for color conversion palette? */

#ifndef ALLEGRO_MULTITHREADED
int _xwin_missed_input;
#endif

#define X_MAX_EVENTS   5
#define MOUSE_WARP_DELAY   200

static char _xwin_driver_desc[256] = EMPTY_STRING;

/* This is used to intercept window closing requests.  */
static Atom wm_delete_window;

#define PREFIX_I                "al-xwin INFO: "
#define PREFIX_W                "al-xwin WARNING: "
#define PREFIX_E                "al-xwin ERROR: "


/* Forward declarations for private functions.  */
static int _xwin_private_open_display(char *name);
static int _xwin_private_create_window(void);
static void _xwin_private_destroy_window(void);
static void _xwin_private_select_screen_to_buffer_function(void);
static void _xwin_private_select_set_colors_function(void);
static void _xwin_private_setup_driver_desc(GFX_DRIVER *drv);
static BITMAP *_xwin_private_create_screen(GFX_DRIVER *drv, int w, int h,
                                 int vw, int vh, int depth, int fullscreen);
static void _xwin_private_destroy_screen(void);
static BITMAP *_xwin_private_create_screen_bitmap(GFX_DRIVER *drv,
                                      unsigned char *frame_buffer,
                                      int bytes_per_buffer_line);
static void _xwin_private_create_mapping_tables(void);
static void _xwin_private_create_mapping(unsigned long *map, int ssize, int dsize, int dshift);
static int _xwin_private_display_is_local(void);
static int _xwin_private_create_ximage(int w, int h);
static void _xwin_private_destroy_ximage(void);
static void _xwin_private_prepare_visual(void);
static int _xwin_private_matching_formats(void);
static void _xwin_private_hack_shifts(void);
static int _xwin_private_colorconv_usable(void);
static int _xwin_private_fast_visual_depth(void);
static void _xwin_private_set_matching_colors(AL_CONST PALETTE p, int from, int to);
static void _xwin_private_set_truecolor_colors(AL_CONST PALETTE p, int from, int to);
static void _xwin_private_set_palette_colors(AL_CONST PALETTE p, int from, int to);
static void _xwin_private_set_palette_range(AL_CONST PALETTE p, int from, int to);
static void _xwin_private_set_window_defaults(void);
static void _xwin_private_flush_buffers(void);
static void _xwin_private_resize_window(int w, int h);
static void _xwin_private_process_event(XEvent *event);
static void _xwin_private_set_warped_mouse_mode(int permanent);
static void _xwin_private_redraw_window(int x, int y, int w, int h);
static int _xwin_private_scroll_screen(int x, int y);
static void _xwin_private_update_screen(int x, int y, int w, int h);
static void _xwin_private_set_window_title(AL_CONST char *name);
static void _xwin_private_set_window_name(AL_CONST char *name, AL_CONST char *group);
static int _xwin_private_get_pointer_mapping(unsigned char map[], int nmap);

static void _xwin_private_fast_colorconv(int sx, int sy, int sw, int sh);

static void _xwin_private_fast_truecolor_8_to_8(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_8_to_16(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_8_to_24(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_8_to_32(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_15_to_8(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_15_to_16(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_15_to_24(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_15_to_32(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_16_to_8(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_16_to_16(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_16_to_24(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_16_to_32(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_24_to_8(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_24_to_16(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_24_to_24(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_24_to_32(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_32_to_8(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_32_to_16(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_32_to_24(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_truecolor_32_to_32(int sx, int sy, int sw, int sh);

static void _xwin_private_slow_truecolor_8(int sx, int sy, int sw, int sh);
static void _xwin_private_slow_truecolor_15(int sx, int sy, int sw, int sh);
static void _xwin_private_slow_truecolor_16(int sx, int sy, int sw, int sh);
static void _xwin_private_slow_truecolor_24(int sx, int sy, int sw, int sh);
static void _xwin_private_slow_truecolor_32(int sx, int sy, int sw, int sh);

static void _xwin_private_fast_palette_8_to_8(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_8_to_16(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_8_to_32(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_15_to_8(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_15_to_16(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_15_to_32(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_16_to_8(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_16_to_16(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_16_to_32(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_24_to_8(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_24_to_16(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_24_to_32(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_32_to_8(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_32_to_16(int sx, int sy, int sw, int sh);
static void _xwin_private_fast_palette_32_to_32(int sx, int sy, int sw, int sh);

static void _xwin_private_slow_palette_8(int sx, int sy, int sw, int sh);
static void _xwin_private_slow_palette_15(int sx, int sy, int sw, int sh);
static void _xwin_private_slow_palette_16(int sx, int sy, int sw, int sh);
static void _xwin_private_slow_palette_24(int sx, int sy, int sw, int sh);
static void _xwin_private_slow_palette_32(int sx, int sy, int sw, int sh);

#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
static int _xvidmode_private_set_fullscreen(int w, int h);
static void _xvidmode_private_unset_fullscreen(void);
#endif

uintptr_t _xwin_write_line (BITMAP *bmp, int line);
void _xwin_unwrite_line (BITMAP *bmp);
#ifndef ALLEGRO_NO_ASM
uintptr_t _xwin_write_line_asm (BITMAP *bmp, int line);
void _xwin_unwrite_line_asm (BITMAP *bmp);
#endif



/* _xwin_open_display:
 *  Wrapper for XOpenDisplay.
 */
static int _xwin_private_open_display(char *name)
{
   if (_xwin.display != 0)
      return -1;

   _xwin.display = XOpenDisplay(name);
   _xwin.screen = ((_xwin.display == 0) ? 0 : XDefaultScreen(_xwin.display));

   return ((_xwin.display != 0) ? 0 : -1);
}

int _xwin_open_display(char *name)
{
   int result;
   XLOCK();
   result = _xwin_private_open_display(name);
   XUNLOCK();
   return result;
}



/* _xwin_close_display:
 *  Wrapper for XCloseDisplay.
 */
void _xwin_close_display(void)
{
   Display *dpy;

   if (!_unix_bg_man->multi_threaded) {
      XLOCK();
   }

   if (_xwin.display != 0) {
      _xwin_destroy_window();
      dpy = _xwin.display;
      _xwin.display = 0;
      XCloseDisplay(dpy);
   }

   if (!_unix_bg_man->multi_threaded) {
      XUNLOCK();
   }
}



/* _xwin_hide_x_mouse:
 * Create invisible X cursor
 */
static void _xwin_hide_x_mouse(void)
{
   unsigned long gcmask;
   XGCValues gcvalues;
   Pixmap pixmap;

   XUndefineCursor(_xwin.display, _xwin.window);

   if (_xwin.cursor != None) {
      XFreeCursor(_xwin.display, _xwin.cursor);
      _xwin.cursor = None;
   }

#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
   if (_xwin.xcursor_image != None) {
      XcursorImageDestroy(_xwin.xcursor_image);
      _xwin.xcursor_image = None;
   }
#endif

   pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
   if (pixmap != None) {
      GC temp_gc;
      XColor color;

      gcmask = GCFunction | GCForeground | GCBackground;
      gcvalues.function = GXcopy;
      gcvalues.foreground = 0;
      gcvalues.background = 0;
      temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
      XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
      XFreeGC(_xwin.display, temp_gc);
      color.pixel = 0;
      color.red = color.green = color.blue = 0;
      color.flags = DoRed | DoGreen | DoBlue;
      _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap, &color, &color, 0, 0);
      XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
      XFreePixmap(_xwin.display, pixmap);
   }
   else {
      _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
      XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
   }
}



/* _xwin_create_window:
 *  Wrapper for XCreateWindow.
 */
static int _xwin_private_create_window(void)
{
   unsigned long gcmask;
   XGCValues gcvalues;
   XSetWindowAttributes setattr;
   XWindowAttributes getattr;

   if (_xwin.display == 0)
      return -1;

   _mouse_on = FALSE;

   /* Create window.  */
   setattr.border_pixel = XBlackPixel(_xwin.display, _xwin.screen);
   setattr.event_mask = (KeyPressMask | KeyReleaseMask
                   | EnterWindowMask | LeaveWindowMask
                   | FocusChangeMask | ExposureMask | PropertyChangeMask
                   | ButtonPressMask | ButtonReleaseMask | PointerMotionMask
                   /*| MappingNotifyMask (SubstructureRedirectMask?)*/);
   _xwin.window = XCreateWindow(_xwin.display, XDefaultRootWindow(_xwin.display),
                        0, 0, 320, 200, 0,
                        CopyFromParent, InputOutput, CopyFromParent,
                        CWBorderPixel | CWEventMask, &setattr);


   /* Get associated visual and window depth (bits per pixel).  */
   XGetWindowAttributes(_xwin.display, _xwin.window, &getattr);
   _xwin.visual = getattr.visual;
   _xwin.window_depth = getattr.depth;

   /* Create and install colormap.  */
   if ((_xwin.visual->class == PseudoColor)
       || (_xwin.visual->class == GrayScale)
       || (_xwin.visual->class == DirectColor))
      _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window, _xwin.visual, AllocAll);
   else
      _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window, _xwin.visual, AllocNone);
   XSetWindowColormap(_xwin.display, _xwin.window, _xwin.colormap);
   XInstallColormap(_xwin.display, _xwin.colormap);

   /* Set WM_DELETE_WINDOW atom in WM_PROTOCOLS property (to get window_delete requests).  */
   wm_delete_window = XInternAtom (_xwin.display, "WM_DELETE_WINDOW", False);
   XSetWMProtocols (_xwin.display, _xwin.window, &wm_delete_window, 1);

   /* Set default window parameters.  */
   (*_xwin_window_defaultor)();

   /* Create graphics context.  */
   gcmask = GCFunction | GCForeground | GCBackground | GCFillStyle | GCPlaneMask;
   gcvalues.function = GXcopy;
   gcvalues.foreground = setattr.border_pixel;
   gcvalues.background = setattr.border_pixel;
   gcvalues.fill_style = FillSolid;
   gcvalues.plane_mask = AllPlanes;
   _xwin.gc = XCreateGC(_xwin.display, _xwin.window, gcmask, &gcvalues);

   /* Create invisible X cursor.  */
   _xwin_hide_x_mouse();

#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
   /* Detect if ARGB cursors are supported */
   _xwin.support_argb_cursor = XcursorSupportsARGB(_xwin.display);
#endif
   _xwin.hw_cursor_ok = 0;

   return 0;
}

int _xwin_create_window(void)
{
   int result;
   XLOCK();
   result = (*_xwin_window_creator)();
   XUNLOCK();
   return result;
}



/* _xwin_destroy_window:
 *  Wrapper for XDestroyWindow.
 */
static void _xwin_private_destroy_window(void)
{
   _xwin_private_destroy_screen();

   if (_xwin.cursor != None) {
      XUndefineCursor(_xwin.display, _xwin.window);
      XFreeCursor(_xwin.display, _xwin.cursor);
      _xwin.cursor = None;
   }

#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
   if (_xwin.xcursor_image != None) {
      XcursorImageDestroy(_xwin.xcursor_image);
      _xwin.xcursor_image = None;
   }
#endif

   _xwin.visual = 0;

   if (_xwin.gc != None) {
      XFreeGC(_xwin.display, _xwin.gc);
      _xwin.gc = None;
   }

   if (_xwin.colormap != None) {
      XUninstallColormap(_xwin.display, _xwin.colormap);
      XFreeColormap(_xwin.display, _xwin.colormap);
      _xwin.colormap = None;
   }

   if (_xwin.window != None) {
      XUnmapWindow(_xwin.display, _xwin.window);
      XDestroyWindow(_xwin.display, _xwin.window);
      _xwin.window = None;
   }
}

void _xwin_destroy_window(void)
{
   XLOCK();
   _xwin_private_destroy_window();
   XUNLOCK();
}



typedef void (*_XWIN_SCREEN_TO_BUFFER)(int x, int y, int w, int h);
static _XWIN_SCREEN_TO_BUFFER _xwin_screen_to_buffer_function[5][10] =
{
   {
      _xwin_private_slow_truecolor_8,
      _xwin_private_fast_truecolor_8_to_8,
      _xwin_private_fast_truecolor_8_to_16,
      _xwin_private_fast_truecolor_8_to_24,
      _xwin_private_fast_truecolor_8_to_32,
      _xwin_private_slow_palette_8,
      _xwin_private_fast_palette_8_to_8,
      _xwin_private_fast_palette_8_to_16,
      0,
      _xwin_private_fast_palette_8_to_32
   },
   {
      _xwin_private_slow_truecolor_15,
      _xwin_private_fast_truecolor_15_to_8,
      _xwin_private_fast_truecolor_15_to_16,
      _xwin_private_fast_truecolor_15_to_24,
      _xwin_private_fast_truecolor_15_to_32,
      _xwin_private_slow_palette_15,
      _xwin_private_fast_palette_15_to_8,
      _xwin_private_fast_palette_15_to_16,
      0,
      _xwin_private_fast_palette_15_to_32
   },
   {
      _xwin_private_slow_truecolor_16,
      _xwin_private_fast_truecolor_16_to_8,
      _xwin_private_fast_truecolor_16_to_16,
      _xwin_private_fast_truecolor_16_to_24,
      _xwin_private_fast_truecolor_16_to_32,
      _xwin_private_slow_palette_16,
      _xwin_private_fast_palette_16_to_8,
      _xwin_private_fast_palette_16_to_16,
      0,
      _xwin_private_fast_palette_16_to_32
   },
   {
      _xwin_private_slow_truecolor_24,
      _xwin_private_fast_truecolor_24_to_8,
      _xwin_private_fast_truecolor_24_to_16,
      _xwin_private_fast_truecolor_24_to_24,
      _xwin_private_fast_truecolor_24_to_32,
      _xwin_private_slow_palette_24,
      _xwin_private_fast_palette_24_to_8,
      _xwin_private_fast_palette_24_to_16,
      0,
      _xwin_private_fast_palette_24_to_32
   },
   {
      _xwin_private_slow_truecolor_32,
      _xwin_private_fast_truecolor_32_to_8,
      _xwin_private_fast_truecolor_32_to_16,
      _xwin_private_fast_truecolor_32_to_24,
      _xwin_private_fast_truecolor_32_to_32,
      _xwin_private_slow_palette_32,
      _xwin_private_fast_palette_32_to_8,
      _xwin_private_fast_palette_32_to_16,
      0,
      _xwin_private_fast_palette_32_to_32
   },
};



/* _xwin_select_screen_to_buffer_function:
 *  Select which function should be used for updating frame buffer with screen data.
 */
static void _xwin_private_select_screen_to_buffer_function(void)
{
   int i, j;

   if (_xwin.matching_formats) {
      _xwin.screen_to_buffer = 0;
   }
   else {
      switch (_xwin.screen_depth) {
       case 8: i = 0; break;
       case 15: i = 1; break;
       case 16: i = 2; break;
       case 24: i = 3; break;
       case 32: i = 4; break;
       default: i = 0; break;
      }
      switch (_xwin.fast_visual_depth) {
       case 0: j = 0; break;
       case 8: j = 1; break;
       case 16: j = 2; break;
       case 24: j = 3; break;
       case 32: j = 4; break;
       default: j = 0; break;
      }
      if (!_xwin.visual_is_truecolor)
       j += 5;

      if (_xwin_private_colorconv_usable()) {
       TRACE(PREFIX_I "Using generic color conversion blitter (%u, %u).\n",
             _xwin.screen_depth, _xwin.fast_visual_depth);
       blitter_func = _get_colorconv_blitter(_xwin.screen_depth,
                                     _xwin.fast_visual_depth);
       _xwin.screen_to_buffer = _xwin_private_fast_colorconv;
      }
      else {
       _xwin.screen_to_buffer = _xwin_screen_to_buffer_function[i][j];
      }
   }
}



/* _xwin_select_set_colors_function:
 *  Select which function should be used for setting hardware colors.
 */
static void _xwin_private_select_set_colors_function(void)
{
   if (_xwin.screen_depth != 8) {
      _xwin.set_colors = 0;
   }
   else {
      if (_xwin.matching_formats) {
       _xwin.set_colors = _xwin_private_set_matching_colors;
      }
      else if (_xwin.visual_is_truecolor) {
       _xwin.set_colors = _xwin_private_set_truecolor_colors;
      }
      else {
       _xwin.set_colors = _xwin_private_set_palette_colors;
      }
   }
}



/* _xwin_setup_driver_desc:
 *  Sets up the X-Windows driver description string.
 */
static void _xwin_private_setup_driver_desc(GFX_DRIVER *drv)
{
   char tmp1[256], tmp2[128], tmp3[128], tmp4[128];

   /* Prepare driver description.  */
   if (_xwin.matching_formats) {
      uszprintf(_xwin_driver_desc, sizeof(_xwin_driver_desc),
              uconvert_ascii("X-Windows graphics, in matching, %d bpp %s", tmp1),
              _xwin.window_depth,
              uconvert_ascii("real depth", tmp2));
   }
   else {
      uszprintf(_xwin_driver_desc, sizeof(_xwin_driver_desc),
              uconvert_ascii("X-Windows graphics, in %s %s, %d bpp %s", tmp1),
              uconvert_ascii((_xwin.fast_visual_depth ? "fast" : "slow"), tmp2),
              uconvert_ascii((_xwin.visual_is_truecolor ? "truecolor" : "paletted"), tmp3),
              _xwin.window_depth,
              uconvert_ascii("real depth", tmp4));
   }
   drv->desc = _xwin_driver_desc;
}



/* _xwin_create_screen:
 *  Creates screen data and other resources.
 */
static BITMAP *_xwin_private_create_screen(GFX_DRIVER *drv, int w, int h,
                                 int vw, int vh, int depth, int fullscreen)
{
#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
   XSetWindowAttributes setattr;
#endif

   if (_xwin.window == None) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("No window"));
      return 0;
   }

   /* Choose convenient size.  */
   if ((w == 0) && (h == 0)) {
      w = 320;
      h = 200;
   }

   if (vw < w)
      vw = w;
   if (vh < h)
      vh = h;

   if (1
#ifdef ALLEGRO_COLOR8
       && (depth != 8)
#endif
#ifdef ALLEGRO_COLOR16
       && (depth != 15)
       && (depth != 16)
#endif
#ifdef ALLEGRO_COLOR24
       && (depth != 24)
#endif
#ifdef ALLEGRO_COLOR32
       && (depth != 32)
#endif
       ) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported color depth"));
      return 0;
   }

#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
   /* If we are going fullscreen, disable window decorations.  */
   if (fullscreen) {
      setattr.override_redirect = True;
      XChangeWindowAttributes(_xwin.display, _xwin.window,
                        CWOverrideRedirect, &setattr);
      _xwin.override_redirected = 1;
   }
#endif

   /* Set window size and save dimensions.  */
   _xwin_private_resize_window(w, h);
   _xwin.screen_width = w;
   _xwin.screen_height = h;
   _xwin.screen_depth = depth;
   _xwin.virtual_width = vw;
   _xwin.virtual_height = vh;

#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
   if (fullscreen) {
      AL_CONST char *fc;
      char tmp1[64], tmp2[128];
      int i;

      /* Switch video mode.  */
      if (!_xvidmode_private_set_fullscreen(w, h)) {
       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not set video mode"));
       return 0;
      }

      /* Hack: make the window fully visible and center cursor.  */
      XMoveWindow(_xwin.display, _xwin.window, 0, 0);
      XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);

      /* This chunk is disabled by default because of problems on KDE desktops.  */
      fc = get_config_string(uconvert_ascii("graphics", tmp1),
                       uconvert_ascii("force_centering", tmp2),
                       NULL);

      if ((fc) && ((i = ugetc(fc)) != 0) && ((i == 'y') || (i == 'Y') || (i == '1'))) {
       XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0, 0);
       XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w - 1, 0);
       XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0, h - 1);
       XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w - 1, h - 1);
      }

      XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w / 2, h / 2);
      XSync(_xwin.display, False);

      /* Grab the keyboard and mouse.  */
      if (XGrabKeyboard(_xwin.display, XDefaultRootWindow(_xwin.display), False,
                  GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) {
       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not grab keyboard"));
       return 0;
      }
      _xwin.keyboard_grabbed = 1;
      if (XGrabPointer(_xwin.display, _xwin.window, False,
                   PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
                   GrabModeAsync, GrabModeAsync, _xwin.window, None, CurrentTime) != GrabSuccess) {
       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not grab mouse"));
       return 0;
      }
      _xwin.mouse_grabbed = 1;
   }
#endif

   /* Create XImage with the size of virtual screen.  */
   if (_xwin_private_create_ximage(vw, vh) != 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not create XImage"));
      return 0;
   }

   /* Prepare visual for further use.  */
   _xwin_private_prepare_visual();

   /* Test that frame buffer is fast (can be accessed directly).  */
   _xwin.fast_visual_depth = _xwin_private_fast_visual_depth();

   /* Create screen bitmap from frame buffer.  */
   return _xwin_private_create_screen_bitmap(drv,
                                   (unsigned char *)_xwin.ximage->data + _xwin.ximage->xoffset,
                                   _xwin.ximage->bytes_per_line);
}

BITMAP *_xwin_create_screen(GFX_DRIVER *drv, int w, int h,
                      int vw, int vh, int depth, int fullscreen)
{
   BITMAP *bmp;
   XLOCK();
   bmp = _xwin_private_create_screen(drv, w, h, vw, vh, depth, fullscreen);
   if (bmp == 0) {
      _xwin_private_destroy_screen();
      /* Work around a weird bug with some window managers (KWin, Window Maker).  */
      if (fullscreen) {
       bmp = _xwin_private_create_screen(drv, w, h, vw, vh, depth, fullscreen);
       if (bmp == 0)
          _xwin_private_destroy_screen();
      }
   }
   XUNLOCK();
   return bmp;
}



/* _xwin_destroy_screen:
 *  Destroys screen resources.
 */
static void _xwin_private_destroy_screen(void)
{
#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
   XSetWindowAttributes setattr;
#endif

   if (_xwin.buffer_line != 0) {
      free(_xwin.buffer_line);
      _xwin.buffer_line = 0;
   }

   if (_xwin.screen_line != 0) {
      free(_xwin.screen_line);
      _xwin.screen_line = 0;
   }

   if (_xwin.screen_data != 0) {
      free(_xwin.screen_data);
      _xwin.screen_data = 0;
   }

   _xwin_private_destroy_ximage();

#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
   if (_xwin.mouse_grabbed) {
      XUngrabPointer(_xwin.display, CurrentTime);
      _xwin.mouse_grabbed = 0;
   }

   if (_xwin.keyboard_grabbed) {
      XUngrabKeyboard(_xwin.display, CurrentTime);
      _xwin.keyboard_grabbed = 0;
   }

   _xvidmode_private_unset_fullscreen();

   if (_xwin.override_redirected) {
      setattr.override_redirect = False;
      XChangeWindowAttributes(_xwin.display, _xwin.window,
                        CWOverrideRedirect, &setattr);
      _xwin.override_redirected = 0;
   }
#endif

   /* whack color-conversion blitter */
   if (blitter_func) {
      _release_colorconv_blitter(blitter_func);
      blitter_func = NULL;
   }

   XUnmapWindow (_xwin.display, _xwin.window);

   (*_xwin_window_defaultor)();
}

void _xwin_destroy_screen(void)
{
   XLOCK();
   _xwin_private_destroy_screen();
   XUNLOCK();
}



/* _xwin_create_screen_bitmap:
 *  Create screen bitmap from frame buffer.
 */
static BITMAP *_xwin_private_create_screen_bitmap(GFX_DRIVER *drv,
                                      unsigned char *frame_buffer,
                                      int bytes_per_buffer_line)
{
   int line;
   int bytes_per_screen_line;
   BITMAP *bmp;

   /* Test that Allegro and X-Windows pixel formats are the same.  */
   _xwin.matching_formats = _xwin_private_matching_formats();

   /* Create mapping tables for color components.  */
   _xwin_private_create_mapping_tables();

   /* Determine how to update frame buffer with screen data.  */
   _xwin_private_select_screen_to_buffer_function();

   /* Determine how to set colors in "hardware".  */
   _xwin_private_select_set_colors_function();

   /* Create line accelerators for screen data.  */
   _xwin.screen_line = malloc(_xwin.virtual_height * sizeof(unsigned char*));
   if (_xwin.screen_line == 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory"));
      return 0;
   }

   /* If formats match, then use frame buffer as screen data, otherwise malloc.  */
   if (_xwin.matching_formats) {
      bytes_per_screen_line = bytes_per_buffer_line;
      _xwin.screen_data = 0;
      _xwin.screen_line[0] = frame_buffer;
   }
   else {
      bytes_per_screen_line = _xwin.virtual_width * BYTES_PER_PIXEL(_xwin.screen_depth);
      _xwin.screen_data = malloc(_xwin.virtual_height * bytes_per_screen_line);
      if (_xwin.screen_data == 0) {
       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory"));
       return 0;
      }
      _xwin.screen_line[0] = _xwin.screen_data;
   }

   /* Initialize line starts.  */
   for (line = 1; line < _xwin.virtual_height; line++)
      _xwin.screen_line[line] = _xwin.screen_line[line - 1] + bytes_per_screen_line;

   /* Create line accelerators for frame buffer.  */
   if (!_xwin.matching_formats && _xwin.fast_visual_depth) {
      _xwin.buffer_line = malloc(_xwin.virtual_height * sizeof(unsigned char*));
      if (_xwin.buffer_line == 0) {
       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory"));
       return 0;
      }

      _xwin.buffer_line[0] = frame_buffer;
      for (line = 1; line < _xwin.virtual_height; line++)
       _xwin.buffer_line[line] = _xwin.buffer_line[line - 1] + bytes_per_buffer_line;
   }

   /* Create bitmap.  */
   bmp = _make_bitmap(_xwin.virtual_width, _xwin.virtual_height,
                  (uintptr_t) (_xwin.screen_line[0]), drv,
                  _xwin.screen_depth, bytes_per_screen_line);
   if (bmp == 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory"));
      return 0;
   }

   /* Fixup bitmap fields.  */
   drv->w = bmp->cr = _xwin.screen_width;
   drv->h = bmp->cb = _xwin.screen_height;
   drv->vid_mem = _xwin.virtual_width * _xwin.virtual_height * BYTES_PER_PIXEL(_xwin.screen_depth);

   /* Need some magic for updating frame buffer.  */
#ifndef ALLEGRO_NO_ASM
   bmp->write_bank = _xwin_write_line_asm;
   bmp->vtable->unwrite_bank = _xwin_unwrite_line_asm;
#else
   bmp->write_bank = _xwin_write_line;
   bmp->vtable->unwrite_bank = _xwin_unwrite_line;
#endif

   /* Replace entries in vtable with magical wrappers.  */
   _xwin_replace_vtable(bmp->vtable);

   /* The drawing mode may not be ok for direct updates anymore. */
   _xwin_drawing_mode();

   /* Initialize other fields in _xwin structure.  */
   _xwin_last_line = -1;
   _xwin_in_gfx_call = 0;
   _xwin.scroll_x = 0;
   _xwin.scroll_y = 0;

   /* Setup driver description string.  */
   _xwin_private_setup_driver_desc(drv);

   return bmp;
}



/* _xwin_create_mapping_tables:
 *  Create mapping between Allegro color component and X-Windows color component.
 */
static void _xwin_private_create_mapping_tables(void)
{
   if (!_xwin.matching_formats) {
      if (_xwin.visual_is_truecolor) {
       switch (_xwin.screen_depth) {
          case 8:
             /* Will be modified later in set_palette.  */
             _xwin_private_create_mapping(_xwin.rmap, 256, 0, 0);
             _xwin_private_create_mapping(_xwin.gmap, 256, 0, 0);
             _xwin_private_create_mapping(_xwin.bmap, 256, 0, 0);
             break;
          case 15:
             _xwin_private_create_mapping(_xwin.rmap, 32, _xwin.rsize, _xwin.rshift);
             _xwin_private_create_mapping(_xwin.gmap, 32, _xwin.gsize, _xwin.gshift);
             _xwin_private_create_mapping(_xwin.bmap, 32, _xwin.bsize, _xwin.bshift);
             break;
          case 16:
             _xwin_private_create_mapping(_xwin.rmap, 32, _xwin.rsize, _xwin.rshift);
             _xwin_private_create_mapping(_xwin.gmap, 64, _xwin.gsize, _xwin.gshift);
             _xwin_private_create_mapping(_xwin.bmap, 32, _xwin.bsize, _xwin.bshift);
             break;
          case 24:
          case 32:
             _xwin_private_create_mapping(_xwin.rmap, 256, _xwin.rsize, _xwin.rshift);
             _xwin_private_create_mapping(_xwin.gmap, 256, _xwin.gsize, _xwin.gshift);
             _xwin_private_create_mapping(_xwin.bmap, 256, _xwin.bsize, _xwin.bshift);
             break;
       }
      }
      else {
       int i;

       /* Might be modified later in set_palette.  */
       for (i = 0; i < 256; i++)
          _xwin.rmap[i] = _xwin.gmap[i] = _xwin.bmap[i] = 0;
      }
   }
}



/* _xwin_create_mapping:
 *  Create mapping between Allegro color component and X-Windows color component.
 */
static void _xwin_private_create_mapping(unsigned long *map, int ssize, int dsize, int dshift)
{
   int i, smax, dmax;

   smax = ssize - 1;
   dmax = dsize - 1;
   for (i = 0; i < ssize; i++)
      map[i] = ((dmax * i) / smax) << dshift;
   for (; i < 256; i++)
      map[i] = map[i % ssize];
}



/* _xwin_display_is_local:
 *  Tests that display connection is local.
 *  (Note: this is duplicated in xdga2.c).
 */
static int _xwin_private_display_is_local(void)
{
   char *name;

   if (_xwin.display == 0)
      return 0;

   /* Get display name and test for local display.  */
   name = XDisplayName(0);

   return (((name == 0) || (name[0] == ':') || (strncmp(name, "unix:", 5) == 0)) ? 1 : 0);
}



/* _xwin_create_ximage:
 *  Create XImage for accessing window.
 */
static int _xwin_private_create_ximage(int w, int h)
{
   XImage *image = 0; /* I'm mage or I'm old?  */

   if (_xwin.display == 0)
      return -1;

#ifdef ALLEGRO_XWINDOWS_WITH_SHM
   if (_xwin_private_display_is_local() && XShmQueryExtension(_xwin.display))
      _xwin.use_shm = 1;
   else
      _xwin.use_shm = 0;
#else
   _xwin.use_shm = 0;
#endif

#ifdef ALLEGRO_XWINDOWS_WITH_SHM
   if (_xwin.use_shm) {
      /* Try to create shared memory XImage.  */
      image = XShmCreateImage(_xwin.display, _xwin.visual, _xwin.window_depth,
                        ZPixmap, 0, &_xwin.shminfo, w, h);
      do {
       if (image != 0) {
          /* Create shared memory segment.  */
          _xwin.shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height,
                               IPC_CREAT | 0777);
          if (_xwin.shminfo.shmid != -1) {
             /* Attach shared memory to our address space.  */
             _xwin.shminfo.shmaddr = image->data = shmat(_xwin.shminfo.shmid, 0, 0);
             if (_xwin.shminfo.shmaddr != (char*) -1) {
              _xwin.shminfo.readOnly = True;

              /* Attach shared memory to the X-server address space.  */
              if (XShmAttach(_xwin.display, &_xwin.shminfo)) {
                 XSync(_xwin.display, False);
                 break;
               }

              shmdt(_xwin.shminfo.shmaddr);
             }
             shmctl(_xwin.shminfo.shmid, IPC_RMID, 0);
          }
          XDestroyImage(image);
          image = 0;
       }
       _xwin.use_shm = 0;
      } while (0);
   }
#endif

   if (image == 0) {
      /* Try to create ordinary XImage.  */
#if 0
      Pixmap pixmap;

      pixmap = XCreatePixmap(_xwin.display, _xwin.window, w, h, _xwin.window_depth);
      if (pixmap != None) {
       image = XGetImage(_xwin.display, pixmap, 0, 0, w, h, AllPlanes, ZPixmap);
       XFreePixmap(_xwin.display, pixmap);
      }
#else
      image = XCreateImage(_xwin.display, _xwin.visual, _xwin.window_depth,
                     ZPixmap, 0, 0, w, h, 32, 0);
      if (image != 0) {
       image->data = malloc(image->bytes_per_line * image->height);
       if (image->data == 0) {
          XDestroyImage(image);
          image = 0;
       }
      }
#endif
   }

   _xwin.ximage = image;

   return ((image != 0) ? 0 : -1);
}



/* _xwin_destroy_ximage:
 *  Destroy XImage.
 */
static void _xwin_private_destroy_ximage(void)
{
   if (_xwin.ximage != 0) {
#ifdef ALLEGRO_XWINDOWS_WITH_SHM
      if (_xwin.use_shm) {
       XShmDetach(_xwin.display, &_xwin.shminfo);
       shmdt(_xwin.shminfo.shmaddr);
       shmctl(_xwin.shminfo.shmid, IPC_RMID, 0);
      }
#endif
      XDestroyImage(_xwin.ximage);
      _xwin.ximage = 0;
   }
}



/* _xwin_prepare_visual:
 *  Prepare visual for further use.
 */
static void _xwin_private_prepare_visual(void)
{
   int i, r, g, b;
   int rmax, gmax, bmax;
   unsigned long mask;
   XColor color;

   if ((_xwin.visual->class == TrueColor)
       || (_xwin.visual->class == DirectColor)) {
      /* Use TrueColor and DirectColor visuals as truecolor.  */

      /* Red shift and size.  */
      for (mask = _xwin.visual->red_mask, i = 0; (mask & 1) != 1; mask >>= 1)
       i++;
      _xwin.rshift = i;
      for (i = 0; mask != 0; mask >>= 1)
       i++;
      _xwin.rsize = 1 << i;

      /* Green shift and size.  */
      for (mask = _xwin.visual->green_mask, i = 0; (mask & 1) != 1; mask >>= 1)
       i++;
      _xwin.gshift = i;
      for (i = 0; mask != 0; mask >>= 1)
       i++;
      _xwin.gsize = 1 << i;

      /* Blue shift and size.  */
      for (mask = _xwin.visual->blue_mask, i = 0; (mask & 1) != 1; mask >>= 1)
       i++;
      _xwin.bshift = i;
      for (i = 0; mask != 0; mask >>= 1)
       i++;
      _xwin.bsize = 1 << i;

      /* Convert DirectColor visual into true color visual.  */
      if (_xwin.visual->class == DirectColor) {
       color.flags = DoRed;
       rmax = _xwin.rsize - 1;
       gmax = _xwin.gsize - 1;
       bmax = _xwin.bsize - 1;
       for (i = 0; i < _xwin.rsize; i++) {
          color.pixel = i << _xwin.rshift;
          color.red = ((rmax <= 0) ? 0 : ((i * 65535L) / rmax));
          XStoreColor(_xwin.display, _xwin.colormap, &color);
       }
       color.flags = DoGreen;
       for (i = 0; i < _xwin.gsize; i++) {
          color.pixel = i << _xwin.gshift;
          color.green = ((gmax <= 0) ? 0 : ((i * 65535L) / gmax));
          XStoreColor(_xwin.display, _xwin.colormap, &color);
       }
       color.flags = DoBlue;
       for (i = 0; i < _xwin.bsize; i++) {
          color.pixel = i << _xwin.bshift;
          color.blue = ((bmax <= 0) ? 0 : ((i * 65535L) / bmax));
          XStoreColor(_xwin.display, _xwin.colormap, &color);
       }
      }

      _xwin.visual_is_truecolor = 1;
   }
   else if ((_xwin.visual->class == PseudoColor)
          || (_xwin.visual->class == GrayScale)) {
      /* Convert read-write palette visual into true color visual.  */
      b = _xwin.window_depth / 3;
      r = (_xwin.window_depth - b) / 2;
      g = _xwin.window_depth - r - b;

      _xwin.rsize = 1 << r;
      _xwin.gsize = 1 << g;
      _xwin.bsize = 1 << b;
      _xwin.rshift = g + b;
      _xwin.gshift = b;
      _xwin.bshift = 0;

      _xwin.visual_is_truecolor = 1;

      rmax = _xwin.rsize - 1;
      gmax = _xwin.gsize - 1;
      bmax = _xwin.bsize - 1;

      color.flags = DoRed | DoGreen | DoBlue;
      for (r = 0; r < _xwin.rsize; r++) {
       for (g = 0; g < _xwin.gsize; g++) {
          for (b = 0; b < _xwin.bsize; b++) {
             color.pixel = (r << _xwin.rshift) | (g << _xwin.gshift) | (b << _xwin.bshift);
             color.red = ((rmax <= 0) ? 0 : ((r * 65535L) / rmax));
             color.green = ((gmax <= 0) ? 0 : ((g * 65535L) / gmax));
             color.blue = ((bmax <= 0) ? 0 : ((b * 65535L) / bmax));
             XStoreColor(_xwin.display, _xwin.colormap, &color);
          }
       }
      }
   }
   else {
      /* All other visual types are paletted.  */
      _xwin.rsize = 1;
      _xwin.bsize = 1;
      _xwin.gsize = 1;
      _xwin.rshift = 0;
      _xwin.gshift = 0;
      _xwin.bshift = 0;

      _xwin.visual_is_truecolor = 0;

      /* Make fixed palette and create mapping RRRRGGGGBBBB -> palette index.  */
      for (r = 0; r < 16; r++) {
       for (g = 0; g < 16; g++) {
          for (b = 0; b < 16; b++) {
             color.red = (r * 65535L) / 15;
             color.green = (g * 65535L) / 15;
             color.blue = (b * 65535L) / 15;
             XAllocColor(_xwin.display, _xwin.colormap, &color);
             _xwin.cmap[(r << 8) | (g << 4) | b] = color.pixel;
          }
       }
      }
   }
}



/* _xwin_matching_formats:
 *  Find if color formats match.
 */
static int _xwin_private_matching_formats(void)
{
   if (_xwin.fast_visual_depth == 0)
      return 0;

   if (_xwin.screen_depth == 8) {
      /* For matching 8 bpp modes visual must be PseudoColor or GrayScale.  */
      if (((_xwin.visual->class != PseudoColor)
         && (_xwin.visual->class != GrayScale))
        || (_xwin.fast_visual_depth != 8)
        || (_xwin.window_depth != 8))
       return 0;
   }
   else if ((_xwin.visual->class != TrueColor)
          && (_xwin.visual->class != DirectColor)) {
      /* For matching true color modes visual must be TrueColor or DirectColor.  */
      return 0;
   }
   else if (_xwin.screen_depth == 15) {
      if ((_xwin.fast_visual_depth != 16)
        || (_xwin.rsize != 32) || (_xwin.gsize != 32) || (_xwin.bsize != 32)
        || ((_xwin.rshift != 0) && (_xwin.rshift != 10))
        || ((_xwin.bshift != 0) && (_xwin.bshift != 10))
        || (_xwin.gshift != 5))
       return 0;
      _rgb_r_shift_15 = _xwin.rshift;
      _rgb_g_shift_15 = _xwin.gshift;
      _rgb_b_shift_15 = _xwin.bshift;
   }
   else if (_xwin.screen_depth == 16) {
      if ((_xwin.fast_visual_depth != 16)
        || (_xwin.rsize != 32) || (_xwin.gsize != 64) || (_xwin.bsize != 32)
        || ((_xwin.rshift != 0) && (_xwin.rshift != 11))
        || ((_xwin.bshift != 0) && (_xwin.bshift != 11))
        || (_xwin.gshift != 5))
       return 0;
      _rgb_r_shift_16 = _xwin.rshift;
      _rgb_g_shift_16 = _xwin.gshift;
      _rgb_b_shift_16 = _xwin.bshift;
   }
   else if (_xwin.screen_depth == 24){
      if ((_xwin.fast_visual_depth != 24)
        || (_xwin.rsize != 256) || (_xwin.gsize != 256) || (_xwin.bsize != 256)
        || ((_xwin.rshift != 0) && (_xwin.rshift != 16))
        || ((_xwin.bshift != 0) && (_xwin.bshift != 16))
        || (_xwin.gshift != 8))
       return 0;
      _rgb_r_shift_24 = _xwin.rshift;
      _rgb_g_shift_24 = _xwin.gshift;
      _rgb_b_shift_24 = _xwin.bshift;
   }
   else if (_xwin.screen_depth == 32) {
      if ((_xwin.fast_visual_depth != 32)
        || (_xwin.rsize != 256) || (_xwin.gsize != 256) || (_xwin.bsize != 256)
        || ((_xwin.rshift != 0) && (_xwin.rshift != 16))
        || ((_xwin.bshift != 0) && (_xwin.bshift != 16))
        || (_xwin.gshift != 8))
       return 0;
      _rgb_r_shift_32 = _xwin.rshift;
      _rgb_g_shift_32 = _xwin.gshift;
      _rgb_b_shift_32 = _xwin.bshift;
   }
   else {
      /* How did you get in here?  */
      return 0;
   }

   return 1;
}



/* _xwin_private_hack_shifts:
 *  Make Allegro draw in BGR format if X uses BGR instead of RGB.
 */
static void _xwin_private_hack_shifts(void)
{
   switch(_xwin.screen_depth) {
      case 8:
         use_bgr_palette_hack = TRUE;
         break;
      case 15:
         _rgb_r_shift_15 = 10;
         _rgb_g_shift_15 = 5;
         _rgb_b_shift_15 = 0;
         break;
      case 16:
         _rgb_r_shift_16 = 11;
         _rgb_g_shift_16 = 5;
         _rgb_b_shift_16 = 0;
         break;
      case 24:
         _rgb_r_shift_24 = 16;
         _rgb_g_shift_24 = 8;
         _rgb_b_shift_24 = 0;
         break;
      case 32:
         _rgb_r_shift_32 = 16;
         _rgb_g_shift_32 = 8;
         _rgb_b_shift_32 = 0;
         break;
   }
}



/* _xwin_private_colorconv_usable:
 *  Find out if generic color conversion blitter can be used.
 */
static int _xwin_private_colorconv_usable(void)
{
   use_bgr_palette_hack = FALSE; /* make sure this is initialized */

   if (_xwin.fast_visual_depth == 0) {
      return 0;
   }
   else if (_xwin.fast_visual_depth == 8) {
#if 0
      /* TODO: check this out later. */

      /* For usable 8 bpp modes visual must be PseudoColor or GrayScale.  */
      if ((_xwin.visual->class == PseudoColor)
         || (_xwin.visual->class == GrayScale))
       return 1;
#else
      return 0;
#endif
   }
   else if ((_xwin.visual->class != TrueColor)
          && (_xwin.visual->class != DirectColor)) {
      /* For usable true color modes visual must be TrueColor or DirectColor.  */
      return 0;
   }
   else if ((_xwin.fast_visual_depth == 16)
       && (_xwin.rsize == 32) && ((_xwin.gsize == 32) || (_xwin.gsize == 64)) && (_xwin.bsize == 32)
       && ((_xwin.rshift == 0) || (_xwin.rshift == 10) || (_xwin.rshift == 11))
       && ((_xwin.bshift == 0) || (_xwin.bshift == 10) || (_xwin.bshift == 11))
       && (_xwin.gshift == 5)) {
      if (_xwin.bshift == 0)
       _xwin_private_hack_shifts();
      return 1;
   }
   else if ((_xwin.fast_visual_depth == 24)
       && (_xwin.rsize == 256) && (_xwin.gsize == 256) && (_xwin.bsize == 256)
       && ((_xwin.rshift == 0) || (_xwin.rshift == 16))
       && ((_xwin.bshift == 0) || (_xwin.bshift == 16))
       && (_xwin.gshift == 8)) {
      if (_xwin.bshift == 0)
       _xwin_private_hack_shifts();
      return 1;
   }
   else if ((_xwin.fast_visual_depth == 32)
       && (_xwin.rsize == 256) && (_xwin.gsize == 256) && (_xwin.bsize == 256)
       && ((_xwin.rshift == 0) || (_xwin.rshift == 16))
       && ((_xwin.bshift == 0) || (_xwin.bshift == 16))
       && (_xwin.gshift == 8)) {
      if (_xwin.bshift == 0)
       _xwin_private_hack_shifts();
      return 1;
   }

   /* Too bad... Muahahaha! */
   return 0;
}



/* _xwin_fast_visual_depth:
 *  Find which depth is fast (when XImage can be accessed directly).
 */
static int _xwin_private_fast_visual_depth(void)
{
   int ok, x, sizex;
   int test_depth;
   uint8_t *p8;
   uint16_t *p16;
   uint32_t *p32;

   if (_xwin.ximage == 0)
      return 0;

   /* Use first line of XImage for test.  */
   p8 = (uint8_t *) _xwin.ximage->data + _xwin.ximage->xoffset;
   p16 = (uint16_t*) p8;
   p32 = (uint32_t*) p8;

   sizex = _xwin.ximage->bytes_per_line - _xwin.ximage->xoffset;

   if ((_xwin.window_depth < 1) || (_xwin.window_depth > 32)) {
      return 0;
   }
   else if (_xwin.window_depth > 16) {
      test_depth = 32;
      sizex /= sizeof (uint32_t);
   }
   else if (_xwin.window_depth > 8) {
      test_depth = 16;
      sizex /= sizeof (uint16_t);
   }
   else {
      test_depth = 8;
   }
   if (sizex > _xwin.ximage->width)
      sizex = _xwin.ximage->width;

   /* Need at least two pixels wide line for test.  */
   if (sizex < 2)
      return 0;

   ok = 1;
   for (x = 0; x < sizex; x++) {
      int bit;

      for (bit = -1; bit < _xwin.window_depth; bit++) {
       unsigned long color = ((bit < 0) ? 0 : ((unsigned long) 1 << bit));

       /* Write color through XImage API.  */
       XPutPixel(_xwin.ximage, x, 0, color);

       /* Read color with direct access.  */
       switch (test_depth) {
          case 8:
             if (p8[x] != color)
              ok = 0;
             break;
          case 16:
             if (p16[x] != color)
              ok = 0;
             break;
          case 32:
             if (p32[x] != color)
              ok = 0;
             break;
          default:
             ok = 0;
             break;
       }
       XPutPixel(_xwin.ximage, x, 0, 0);

       if (!ok)
          return 0;
      }
   }

   return test_depth;
}



/* _xwin_enable_hardware_cursor:
 *  enable the hardware cursor; this disables the mouse mickey warping hack
 */
void _xwin_enable_hardware_cursor(int mode)
{
#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
   if (_xwin.support_argb_cursor)
      _xwin.hw_cursor_ok = mode;
   else
#endif
      _xwin.hw_cursor_ok = 0;

   /* Switch to non-warped mode */
   if (_xwin.hw_cursor_ok) {
      _xwin.mouse_warped = 0;
      /* Move X-cursor to Allegro cursor.  */
      XLOCK();
      XWarpPointer(_xwin.display, _xwin.window, _xwin.window,
               0, 0, _xwin.window_width, _xwin.window_height,
               _mouse_x - (_xwin_mouse_extended_range ? _xwin.scroll_x : 0),
               _mouse_y - (_xwin_mouse_extended_range ? _xwin.scroll_y : 0));
      XUNLOCK();
   }
}



#ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR

/* _xwin_set_mouse_sprite:
 *  Set custom X cursor (if supported).
 */
int _xwin_set_mouse_sprite(struct BITMAP *sprite, int xfocus, int yfocus)
{
#define GET_PIXEL_DATA(depth, getpix)                                \
               case depth:                                           \
                  c = 0;                                             \
                  for (iy = 0; iy < sprite->h; iy++) {               \
                     for(ix = 0; ix < sprite->w; ix++) {             \
                        col = getpix(sprite, ix, iy);                \
                        if (col == (MASK_COLOR_ ## depth)) {         \
                           r = g = b = a = 0;                        \
                        }                                            \
                        else {                                       \
                           r = getr ## depth(col);                   \
                           g = getg ## depth(col);                   \
                           b = getb ## depth(col);                   \
                           a = 255;                                  \
                        }                                            \
                        _xwin.xcursor_image->pixels[c++] =           \
                                    (a<<24)|(r<<16)|(g<<8)|(b);      \
                     }                                               \
                  }

   if (!_xwin.support_argb_cursor) {
      return -1;
   }

   if (_xwin.xcursor_image != None) {
      XLOCK();
      XcursorImageDestroy(_xwin.xcursor_image);
      XUNLOCK();
      _xwin.xcursor_image = None;
   }

   if (sprite) {
      int ix, iy;
      int r = 0, g = 0, b = 0, a = 0, c, col;

      _xwin.xcursor_image = XcursorImageCreate(sprite->w, sprite->h);
      if (_xwin.xcursor_image == None) {
         return -1;
      }

      switch (bitmap_color_depth(sprite)) {
         GET_PIXEL_DATA(8, _getpixel)
            break;

         GET_PIXEL_DATA(15, _getpixel15)
            break;

         GET_PIXEL_DATA(16, _getpixel16)
            break;

         GET_PIXEL_DATA(24, _getpixel24)
            break;

         GET_PIXEL_DATA(32, _getpixel32)
            break;
      } /* End switch */

      _xwin.xcursor_image->xhot = xfocus;
      _xwin.xcursor_image->yhot = yfocus;

      return 0;
   }

   return -1;

#undef GET_PIXEL_DATA
}



/* _xwin_show_mouse:
 *  Show the custom X cursor (if supported)
 */
int _xwin_show_mouse(struct BITMAP *bmp, int x, int y)
{
   /* Only draw on screen */
   if (!is_same_bitmap(bmp, screen))
      return -1;

   if (!_xwin.support_argb_cursor) {
      return -1;
   }

   if (_xwin.xcursor_image == None) {
      return -1;
   }

   /* Hardware cursor is disabled (mickey mode) */
   if (!_xwin.hw_cursor_ok) {
      return -1;
   }

   XLOCK();
   if (_xwin.cursor != None) {
      XUndefineCursor(_xwin.display, _xwin.window);
      XFreeCursor(_xwin.display, _xwin.cursor);
   }

   _xwin.cursor = XcursorImageLoadCursor(_xwin.display, _xwin.xcursor_image);
   XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);

   XUNLOCK();
   return 0;
}



/* _xwin_hide_mouse:
 *  Hide the custom X cursor (if supported)
 */
void _xwin_hide_mouse(void)
{
   if (_xwin.support_argb_cursor) {
      XLOCK();
      _xwin_hide_x_mouse();
      XUNLOCK();
   }
   return;
}



/* _xwin_move_mouse:
 *  Get mouse move notification. Not that we need it...
 */
void _xwin_move_mouse(int x, int y)
{
}

#endif   /* ALLEGRO_XWINDOWS_WITH_XCURSOR */



/*
 * Functions for copying screen data to frame buffer.
 */
static void _xwin_private_fast_colorconv(int sx, int sy, int sw, int sh)
{
   GRAPHICS_RECT src_rect, dest_rect;

   /* set up source and destination rectangles */
   src_rect.height = sh;
   src_rect.width  = sw;
   src_rect.pitch  = _xwin.screen_line[1] - _xwin.screen_line[0];
   src_rect.data   = _xwin.screen_line[sy] + sx * BYTES_PER_PIXEL(_xwin.screen_depth);

   dest_rect.height = sh;
   dest_rect.width  = sw;
   dest_rect.pitch  = _xwin.buffer_line[1] - _xwin.buffer_line[0];
   dest_rect.data   = _xwin.buffer_line[sy] + sx * BYTES_PER_PIXEL(_xwin.fast_visual_depth);

   /* Update frame buffer with screen contents.  */
   ASSERT(blitter_func);
   blitter_func(&src_rect, &dest_rect);
}

#ifdef ALLEGRO_LITTLE_ENDIAN
   #define DEFAULT_RGB_R_POS_24  (DEFAULT_RGB_R_SHIFT_24/8)
   #define DEFAULT_RGB_G_POS_24  (DEFAULT_RGB_G_SHIFT_24/8)
   #define DEFAULT_RGB_B_POS_24  (DEFAULT_RGB_B_SHIFT_24/8)
#elif defined ALLEGRO_BIG_ENDIAN
   #define DEFAULT_RGB_R_POS_24  (2-DEFAULT_RGB_R_SHIFT_24/8)
   #define DEFAULT_RGB_G_POS_24  (2-DEFAULT_RGB_G_SHIFT_24/8)
   #define DEFAULT_RGB_B_POS_24  (2-DEFAULT_RGB_B_SHIFT_24/8)
#else
   #error endianess not defined
#endif

#define MAKE_FAST_TRUECOLOR(name,stype,dtype,rshift,gshift,bshift,rmask,gmask,bmask)    \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int y, x;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      stype *s = (stype*) (_xwin.screen_line[y]) + sx;                                  \
      dtype *d = (dtype*) (_xwin.buffer_line[y]) + sx;                                  \
      for (x = sw - 1; x >= 0; x--) {                                                   \
       unsigned long color = *s++;                                                    \
       *d++ = (_xwin.rmap[(color >> (rshift)) & (rmask)]                              \
             | _xwin.gmap[(color >> (gshift)) & (gmask)]                            \
             | _xwin.bmap[(color >> (bshift)) & (bmask)]);                          \
      }                                                                                 \
   }                                                                                    \
}

#define MAKE_FAST_TRUECOLOR24(name,dtype)                                               \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      unsigned char *s = _xwin.screen_line[y] + 3 * sx;                                 \
      dtype *d = (dtype*) (_xwin.buffer_line[y]) + sx;                                  \
      for (x = sw - 1; x >= 0; s += 3, x--) {                                           \
       *d++ = (_xwin.rmap[s[DEFAULT_RGB_R_POS_24]]                                    \
             | _xwin.gmap[s[DEFAULT_RGB_G_POS_24]]                                  \
             | _xwin.bmap[s[DEFAULT_RGB_B_POS_24]]);                                \
      }                                                                                 \
   }                                                                                    \
}

#define MAKE_FAST_TRUECOLOR_TO24(name,stype,rshift,gshift,bshift,rmask,gmask,bmask)     \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      stype *s = (stype*) (_xwin.screen_line[y]) + sx;                                  \
      unsigned char *d = _xwin.buffer_line[y] + 3 * sx;                                 \
      for (x = sw - 1; x >= 0; d += 3, x--) {                                           \
       unsigned long color = *s++;                                                    \
       color = (_xwin.rmap[(color >> (rshift)) & (rmask)]                             \
              | _xwin.gmap[(color >> (gshift)) & (gmask)]                           \
              | _xwin.bmap[(color >> (bshift)) & (bmask)]);                         \
       WRITE3BYTES(d, color);                                                         \
      }                                                                                 \
   }                                                                                    \
}

#define MAKE_FAST_TRUECOLOR24_TO24(name)                                                \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      unsigned char *s = _xwin.screen_line[y] + 3 * sx;                                 \
      unsigned char *d = _xwin.buffer_line[y] + 3 * sx;                                 \
      for (x = sw - 1; x >= 0; s += 3, d += 3, x--) {                                   \
       unsigned long color = _xwin.rmap[s[DEFAULT_RGB_R_POS_24]]                      \
                         | _xwin.gmap[s[DEFAULT_RGB_G_POS_24]]                    \
                         | _xwin.bmap[s[DEFAULT_RGB_B_POS_24]];                   \
       WRITE3BYTES(d, color);                                                         \
      }                                                                                 \
   }                                                                                    \
}

MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_8_to_8,
                unsigned char, unsigned char, 0, 0, 0, 0xFF, 0xFF, 0xFF);
MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_8_to_16,
                unsigned char, unsigned short, 0, 0, 0, 0xFF, 0xFF, 0xFF);
MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_8_to_32,
                unsigned char, uint32_t, 0, 0, 0, 0xFF, 0xFF, 0xFF);

MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_15_to_8,
                unsigned short, unsigned char, 0, 5, 10, 0x1F, 0x1F, 0x1F);
MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_15_to_16,
                unsigned short, unsigned short, 0, 5, 10, 0x1F, 0x1F, 0x1F);
MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_15_to_32,
                unsigned short, uint32_t, 0, 5, 10, 0x1F, 0x1F, 0x1F);

MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_16_to_8,
                unsigned short, unsigned char, 0, 5, 11, 0x1F, 0x3F, 0x1F);
MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_16_to_16,
                unsigned short, unsigned short, 0, 5, 11, 0x1F, 0x3F, 0x1F);
MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_16_to_32,
                unsigned short, uint32_t, 0, 5, 11, 0x1F, 0x3F, 0x1F);

MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_32_to_8,
                uint32_t, unsigned char, 0, 8, 16, 0xFF, 0xFF, 0xFF);
MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_32_to_16,
                uint32_t, unsigned short, 0, 8, 16, 0xFF, 0xFF, 0xFF);
MAKE_FAST_TRUECOLOR(_xwin_private_fast_truecolor_32_to_32,
                uint32_t, uint32_t, 0, 8, 16, 0xFF, 0xFF, 0xFF);

MAKE_FAST_TRUECOLOR24(_xwin_private_fast_truecolor_24_to_8,
                  unsigned char);
MAKE_FAST_TRUECOLOR24(_xwin_private_fast_truecolor_24_to_16,
                  unsigned short);
MAKE_FAST_TRUECOLOR24(_xwin_private_fast_truecolor_24_to_32,
                  uint32_t);

MAKE_FAST_TRUECOLOR_TO24(_xwin_private_fast_truecolor_8_to_24,
                   unsigned char, 0, 0, 0, 0xFF, 0xFF, 0xFF);
MAKE_FAST_TRUECOLOR_TO24(_xwin_private_fast_truecolor_15_to_24,
                   unsigned short, 0, 5, 10, 0x1F, 0x1F, 0x1F);
MAKE_FAST_TRUECOLOR_TO24(_xwin_private_fast_truecolor_16_to_24,
                   unsigned short, 0, 5, 11, 0x1F, 0x3F, 0x1F);
MAKE_FAST_TRUECOLOR_TO24(_xwin_private_fast_truecolor_32_to_24,
                   uint32_t, 0, 8, 16, 0xFF, 0xFF, 0xFF);

MAKE_FAST_TRUECOLOR24_TO24(_xwin_private_fast_truecolor_24_to_24);

#define MAKE_FAST_PALETTE8(name,dtype)                                                  \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      unsigned char *s = _xwin.screen_line[y] + sx;                                     \
      dtype *d = (dtype*) (_xwin.buffer_line[y]) + sx;                                  \
      for (x = sw - 1; x >= 0; x--) {                                                   \
       unsigned long color = *s++;                                                    \
       *d++ = _xwin.cmap[(_xwin.rmap[color]                                           \
                      | _xwin.gmap[color]                                         \
                      | _xwin.bmap[color])];                                      \
      }                                                                                 \
   }                                                                                    \
}

#define MAKE_FAST_PALETTE(name,stype,dtype,rshift,gshift,bshift)                        \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      stype *s = (stype*) (_xwin.screen_line[y]) + sx;                                  \
      dtype *d = (dtype*) (_xwin.buffer_line[y]) + sx;                                  \
      for (x = sw - 1; x >= 0; x--) {                                                   \
       unsigned long color = *s++;                                                    \
       *d++ = _xwin.cmap[((((color >> (rshift)) & 0x0F) << 8)                         \
                      | (((color >> (gshift)) & 0x0F) << 4)                       \
                      | ((color >> (bshift)) & 0x0F))];                           \
      }                                                                                 \
   }                                                                                    \
}

#define MAKE_FAST_PALETTE24(name,dtype)                                                 \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      unsigned char *s = _xwin.screen_line[y] + 3 * sx;                                 \
      dtype *d = (dtype*) (_xwin.buffer_line[y]) + sx;                                  \
      for (x = sw - 1; x >= 0; s += 3, x--) {                                           \
       *d++ = _xwin.cmap[((((unsigned long) s[DEFAULT_RGB_R_POS_24] << 4) & 0xF00)    \
                      | ((unsigned long) s[DEFAULT_RGB_G_POS_24] & 0xF0)          \
                      | (((unsigned long) s[DEFAULT_RGB_B_POS_24] >> 4) & 0x0F))];\
      }                                                                                 \
   }                                                                                    \
}

MAKE_FAST_PALETTE8(_xwin_private_fast_palette_8_to_8,
               unsigned char);
MAKE_FAST_PALETTE8(_xwin_private_fast_palette_8_to_16,
               unsigned short);
MAKE_FAST_PALETTE8(_xwin_private_fast_palette_8_to_32,
               uint32_t);

MAKE_FAST_PALETTE(_xwin_private_fast_palette_15_to_8,
              unsigned short, unsigned char, 1, 6, 11);
MAKE_FAST_PALETTE(_xwin_private_fast_palette_15_to_16,
              unsigned short, unsigned short, 1, 6, 11);
MAKE_FAST_PALETTE(_xwin_private_fast_palette_15_to_32,
              unsigned short, uint32_t, 1, 6, 11);

MAKE_FAST_PALETTE(_xwin_private_fast_palette_16_to_8,
              unsigned short, unsigned char, 1, 7, 12);
MAKE_FAST_PALETTE(_xwin_private_fast_palette_16_to_16,
              unsigned short, unsigned short, 1, 7, 12);
MAKE_FAST_PALETTE(_xwin_private_fast_palette_16_to_32,
              unsigned short, uint32_t, 1, 7, 12);

MAKE_FAST_PALETTE(_xwin_private_fast_palette_32_to_8,
              uint32_t, unsigned char, 4, 12, 20);
MAKE_FAST_PALETTE(_xwin_private_fast_palette_32_to_16,
              uint32_t, unsigned short, 4, 12, 20);
MAKE_FAST_PALETTE(_xwin_private_fast_palette_32_to_32,
              uint32_t, uint32_t, 4, 12, 20);

MAKE_FAST_PALETTE24(_xwin_private_fast_palette_24_to_8,
                unsigned char);
MAKE_FAST_PALETTE24(_xwin_private_fast_palette_24_to_16,
                unsigned short);
MAKE_FAST_PALETTE24(_xwin_private_fast_palette_24_to_32,
                uint32_t);

#define MAKE_SLOW_TRUECOLOR(name,stype,rshift,gshift,bshift,rmask,gmask,bmask)          \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      stype *s = (stype*) (_xwin.screen_line[y]) + sx;                                  \
      for (x = sx; x < (sx + sw); x++) {                                                \
       unsigned long color = *s++;                                                    \
       XPutPixel (_xwin.ximage, x, y,                                                 \
                (_xwin.rmap[(color >> (rshift)) & (rmask)]                          \
                 | _xwin.gmap[(color >> (gshift)) & (gmask)]                        \
                 | _xwin.bmap[(color >> (bshift)) & (bmask)]));                     \
      }                                                                                 \
   }                                                                                    \
}

#define MAKE_SLOW_TRUECOLOR24(name)                                                     \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      unsigned char *s = _xwin.screen_line[y] + 3 * sx;                                 \
      for (x = sx; x < (sx + sw); s += 3, x++) {                                        \
       XPutPixel(_xwin.ximage, x, y,                                                  \
               (_xwin.rmap[s[DEFAULT_RGB_R_POS_24]]                                 \
                | _xwin.gmap[s[DEFAULT_RGB_G_POS_24]]                               \
                | _xwin.bmap[s[DEFAULT_RGB_B_POS_24]]));                            \
      }                                                                                 \
   }                                                                                    \
}

MAKE_SLOW_TRUECOLOR(_xwin_private_slow_truecolor_8, unsigned char, 0, 0, 0, 0xFF, 0xFF, 0xFF);
MAKE_SLOW_TRUECOLOR(_xwin_private_slow_truecolor_15, unsigned short, 0, 5, 10, 0x1F, 0x1F, 0x1F);
MAKE_SLOW_TRUECOLOR(_xwin_private_slow_truecolor_16, unsigned short, 0, 5, 11, 0x1F, 0x3F, 0x1F);
MAKE_SLOW_TRUECOLOR(_xwin_private_slow_truecolor_32, uint32_t, 0, 8, 16, 0xFF, 0xFF, 0xFF);
MAKE_SLOW_TRUECOLOR24(_xwin_private_slow_truecolor_24);

#define MAKE_SLOW_PALETTE8(name)                                                        \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      unsigned char *s = _xwin.screen_line[y] + sx;                                     \
      for (x = sx; x < (sx + sw); x++) {                                                \
       unsigned long color = *s++;                                                    \
       XPutPixel(_xwin.ximage, x, y,                                                  \
               _xwin.cmap[(_xwin.rmap[color]                                        \
                         | _xwin.gmap[color]                                      \
                         | _xwin.bmap[color])]);                                  \
      }                                                                                 \
   }                                                                                    \
}

#define MAKE_SLOW_PALETTE(name,stype,rshift,gshift,bshift)                              \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      stype *s = (stype*) (_xwin.screen_line[y]) + sx;                                  \
      for (x = sx; x < (sx + sw); x++) {                                                \
       unsigned long color = *s++;                                                    \
       XPutPixel(_xwin.ximage, x, y,                                                  \
               _xwin.cmap[((((color >> (rshift)) & 0x0F) << 8)                      \
                         | (((color >> (gshift)) & 0x0F) << 4)                    \
                         | ((color >> (bshift)) & 0x0F))]);                       \
      }                                                                                 \
   }                                                                                    \
}

#define MAKE_SLOW_PALETTE24(name)                                                       \
static void name(int sx, int sy, int sw, int sh)                                        \
{                                                                                       \
   int x, y;                                                                            \
   for (y = sy; y < (sy + sh); y++) {                                                   \
      unsigned char *s = _xwin.screen_line[y] + 3 * sx;                                 \
      for (x = sx; x < (sx + sw); s += 3, x++) {                                        \
       XPutPixel(_xwin.ximage, x, y,                                                  \
               _xwin.cmap[((((unsigned long) s[DEFAULT_RGB_R_POS_24] << 4) & 0xF00) \
                         | ((unsigned long) s[DEFAULT_RGB_G_POS_24] & 0xF0)       \
                         | (((unsigned long) s[DEFAULT_RGB_B_POS_24] >> 4) & 0x0F))]); \
      }                                                                                 \
   }                                                                                    \
}

MAKE_SLOW_PALETTE8(_xwin_private_slow_palette_8);
MAKE_SLOW_PALETTE(_xwin_private_slow_palette_15, unsigned short, 1, 6, 11);
MAKE_SLOW_PALETTE(_xwin_private_slow_palette_16, unsigned short, 1, 7, 12);
MAKE_SLOW_PALETTE(_xwin_private_slow_palette_32, uint32_t, 4, 12, 20);
MAKE_SLOW_PALETTE24(_xwin_private_slow_palette_24);

/*
 * Functions for setting "hardware" colors in 8bpp modes.
 */
static void _xwin_private_set_matching_colors(AL_CONST PALETTE p, int from, int to)
{
   int i;
   static XColor color[256];

   for (i = from; i <= to; i++) {
      color[i].flags = DoRed | DoGreen | DoBlue;
      color[i].pixel = i;
      color[i].red = ((p[i].r & 0x3F) * 65535L) / 0x3F;
      color[i].green = ((p[i].g & 0x3F) * 65535L) / 0x3F;
      color[i].blue = ((p[i].b & 0x3F) * 65535L) / 0x3F;
   }
   XStoreColors(_xwin.display, _xwin.colormap, color + from, to - from + 1);
}

static void _xwin_private_set_truecolor_colors(AL_CONST PALETTE p, int from, int to)
{
   int i, rmax, gmax, bmax;

   rmax = _xwin.rsize - 1;
   gmax = _xwin.gsize - 1;
   bmax = _xwin.bsize - 1;
   for (i = from; i <= to; i++) {
      _xwin.rmap[i] = (((p[i].r & 0x3F) * rmax) / 0x3F) << _xwin.rshift;
      _xwin.gmap[i] = (((p[i].g & 0x3F) * gmax) / 0x3F) << _xwin.gshift;
      _xwin.bmap[i] = (((p[i].b & 0x3F) * bmax) / 0x3F) << _xwin.bshift;
   }
}

static void _xwin_private_set_palette_colors(AL_CONST PALETTE p, int from, int to)
{
   int i;

   for (i = from; i <= to; i++) {
      _xwin.rmap[i] = (((p[i].r & 0x3F) * 15) / 0x3F) << 8;
      _xwin.gmap[i] = (((p[i].g & 0x3F) * 15) / 0x3F) << 4;
      _xwin.bmap[i] = (((p[i].b & 0x3F) * 15) / 0x3F);
   }
}

static void _xwin_private_set_palette_range(AL_CONST PALETTE p, int from, int to)
{
   RGB *pal;
   int c;
   unsigned char temp;

   if (_xwin.set_colors != 0) {
      if (blitter_func) {
         if (use_bgr_palette_hack && (from >= 0) && (to < 256)) {
            pal = malloc(sizeof(RGB)*256);
            ASSERT(pal);
            ASSERT(p);
            if (!pal || !p)
             return; /* ... in shame and disgrace */
            memcpy(&pal[from], &p[from], sizeof(RGB)*(to-from+1));
            for (c = from; c <= to; c++) {
               temp = pal[c].r;
               pal[c].r = pal[c].b;
               pal[c].b = temp;
            }
            _set_colorconv_palette(pal, from, to);
          free(pal);
         }
         else {
            _set_colorconv_palette(p, from, to);
         }
      }

      /* Set "hardware" colors.  */
      (*(_xwin.set_colors))(p, from, to);

      /* Update XImage and window.  */
      if (!_xwin.matching_formats)
       _xwin_private_update_screen(0, 0, _xwin.virtual_width, _xwin.virtual_height);
   }
}

void _xwin_set_palette_range(AL_CONST PALETTE p, int from, int to, int vsync)
{
   if (vsync) {
      _xwin_vsync();
   }

   XLOCK();
   _xwin_private_set_palette_range(p, from, to);
   XUNLOCK();
}



/* _xwin_set_window_defaults:
 *  Set default window parameters.
 */
static void _xwin_private_set_window_defaults(void)
{
   XClassHint hint;
   XWMHints wm_hints;
#ifdef ALLEGRO_XWINDOWS_WITH_XPM
   XpmAttributes attributes;
#endif

   if (_xwin.window == None)
      return;

   /* Set window title.  */
   XStoreName(_xwin.display, _xwin.window, _xwin.window_title);

   /* Set hints.  */
   hint.res_name = _xwin.application_name;
   hint.res_class = _xwin.application_class;
   XSetClassHint(_xwin.display, _xwin.window, &hint);

   wm_hints.flags = InputHint | StateHint | WindowGroupHint;
   wm_hints.input = True;
   wm_hints.initial_state = NormalState;
   wm_hints.window_group = _xwin.window;

#ifdef ALLEGRO_XWINDOWS_WITH_XPM
   if (allegro_icon) {
      wm_hints.flags |= IconPixmapHint | IconMaskHint;
      attributes.valuemask = XpmReturnAllocPixels | XpmReturnExtensions;
      XpmCreatePixmapFromData(_xwin.display,_xwin.window,allegro_icon,&wm_hints.icon_pixmap,&wm_hints.icon_mask, &attributes);
   }
#endif

   XSetWMHints(_xwin.display, _xwin.window, &wm_hints);
}



/* _xwin_flush_buffers:
 *  Flush input and output X-buffers.
 */
static void _xwin_private_flush_buffers(void)
{
   if (_xwin.display != 0)
      XSync(_xwin.display, False);
}

void _xwin_flush_buffers(void)
{
   XLOCK();
   _xwin_private_flush_buffers();
   XUNLOCK();
}



/* _xwin_vsync:
 *  Emulation of vsync.
 */
void _xwin_vsync(void)
{
   if (_timer_installed) {
      int prev = retrace_count;

      XLOCK();
      XSync(_xwin.display, False);
      XUNLOCK();

      do {
      } while (retrace_count == prev);
   }
   else {
      /* This does not wait for the VBI - but it waits until X11 has
       * synchronized, i.e. until actual changes are visible. So it
       * has a similar effect.
       */
      XLOCK();
      XSync(_xwin.display, False);
      XUNLOCK();
   }
}



/* _xwin_resize_window:
 *  Wrapper for XResizeWindow.
 */
static void _xwin_private_resize_window(int w, int h)
{
   XSizeHints *hints;

   if (_xwin.window == None)
      return;

   /* New window size.  */
   _xwin.window_width = w;
   _xwin.window_height = h;

   /* Resize window.  */
   XUnmapWindow(_xwin.display, _xwin.window);
   XResizeWindow(_xwin.display, _xwin.window, w, h);
   XMapWindow(_xwin.display, _xwin.window);

   hints = XAllocSizeHints();
   if (hints == 0)
      return;

   /* Set size and position hints for Window Manager.  */
   hints->flags = PMinSize | PMaxSize | PBaseSize;
   hints->min_width  = hints->max_width  = hints->base_width  = w;
   hints->min_height = hints->max_height = hints->base_height = h;
   XSetWMNormalHints(_xwin.display, _xwin.window, hints);

   XFree(hints);
}



/* _xwin_process_event:
 *  Process one event.
 */
static void _xwin_private_process_event(XEvent *event)
{
   int dx, dy, dz = 0;
   static int mouse_buttons = 0;
   static int mouse_savedx = 0;
   static int mouse_savedy = 0;
   static int mouse_warp_now = 0;
   static int mouse_was_warped = 0;

   switch (event->type) {
      case KeyPress:
         _xwin_keyboard_handler (&event->xkey, FALSE);
       break;
      case KeyRelease:
         _xwin_keyboard_handler (&event->xkey, FALSE);
       break;
      case FocusIn:
       _switch_in();
         _xwin_keyboard_focus_handler (&event->xfocus);
       break;
      case FocusOut:
       _switch_out();
         _xwin_keyboard_focus_handler (&event->xfocus);
       break;
      case ButtonPress:
       /* Mouse button pressed.  */
       if (event->xbutton.button == Button1)
          mouse_buttons |= 1;
       else if (event->xbutton.button == Button3)
          mouse_buttons |= 2;
       else if (event->xbutton.button == Button2)
          mouse_buttons |= 4;
       else if (event->xbutton.button == Button4)
          dz = 1;
       else if (event->xbutton.button == Button5)
          dz = -1;
       if (_xwin_mouse_interrupt)
          (*_xwin_mouse_interrupt)(0, 0, dz, mouse_buttons);
       break;
      case ButtonRelease:
       /* Mouse button released.  */
       if (event->xbutton.button == Button1)
          mouse_buttons &= ~1;
       else if (event->xbutton.button == Button3)
          mouse_buttons &= ~2;
       else if (event->xbutton.button == Button2)
          mouse_buttons &= ~4;
       if (_xwin_mouse_interrupt)
          (*_xwin_mouse_interrupt)(0, 0, 0, mouse_buttons);
       break;
      case MotionNotify:
       /* Mouse moved.  */
       dx = event->xmotion.x - mouse_savedx;
       dy = event->xmotion.y - mouse_savedy;
       /* Discard some events after warp.  */
       if (mouse_was_warped && ((dx != 0) || (dy != 0)) && (mouse_was_warped++ < 16))
          break;
       mouse_savedx = event->xmotion.x;
       mouse_savedy = event->xmotion.y;
       mouse_was_warped = 0;
       if (!_xwin.mouse_warped) {
          /* Move Allegro cursor to X-cursor.  */
          dx = event->xmotion.x - (_mouse_x - (_xwin_mouse_extended_range ? _xwin.scroll_x : 0));
          dy = event->xmotion.y - (_mouse_y - (_xwin_mouse_extended_range ? _xwin.scroll_y : 0));
       }
       if (((dx != 0) || (dy != 0)) && _xwin_mouse_interrupt) {
          if (_xwin.mouse_warped && (mouse_warp_now++ & 4)) {
             /* Warp X-cursor to the center of the window.  */
             mouse_savedx = _xwin.window_width / 2;
             mouse_savedy = _xwin.window_height / 2;
             mouse_was_warped = 1;
             XWarpPointer(_xwin.display, _xwin.window, _xwin.window,
                      0, 0, _xwin.window_width, _xwin.window_height,
                      mouse_savedx, mouse_savedy);
          }
          /* Move Allegro cursor.  */
          (*_xwin_mouse_interrupt)(dx, dy, 0, mouse_buttons);
       }
       break;
      case EnterNotify:
       /* Mouse entered window.  */
       _mouse_on = TRUE;
       mouse_savedx = event->xcrossing.x;
       mouse_savedy = event->xcrossing.y;
       mouse_was_warped = 0;
       if (!_xwin.mouse_warped) {
          /* Move Allegro cursor to X-cursor.  */
          dx = event->xcrossing.x - (_mouse_x - (_xwin_mouse_extended_range ? _xwin.scroll_x : 0));
          dy = event->xcrossing.y - (_mouse_y - (_xwin_mouse_extended_range ? _xwin.scroll_y : 0));
          if (((dx != 0) || (dy != 0)) && _xwin_mouse_interrupt)
             (*_xwin_mouse_interrupt)(dx, dy, 0, mouse_buttons);
       }
       else if (_xwin_mouse_interrupt)
          (*_xwin_mouse_interrupt)(0, 0, 0, mouse_buttons);
       break;
      case LeaveNotify:
       _mouse_on = FALSE;
       if (_xwin_mouse_interrupt)
          (*_xwin_mouse_interrupt)(0, 0, 0, mouse_buttons);
       break;
      case Expose:
       /* Request to redraw part of the window.  */
       (*_xwin_window_redrawer)(event->xexpose.x, event->xexpose.y,
                             event->xexpose.width, event->xexpose.height);
       break;
      case MappingNotify:
       /* Keyboard mapping changed.  */
       if (event->xmapping.request == MappingKeyboard)
          _xwin_get_keyboard_mapping();
       break;
      case ClientMessage:
         /* Window close request */
         if ((Atom)event->xclient.data.l[0] == wm_delete_window) {
            if (_xwin.close_button_callback)
               _xwin.close_button_callback();
         }
         break;
   }
}



/* _xwin_handle_input:
 *  Handle events from the queue.
 */
void _xwin_private_handle_input(void)
{
   int i, events, events_queued;
   static XEvent event[X_MAX_EVENTS + 1]; /* +1 for possible extra event, see below. */

   if (_xwin.display == 0)
      return;

   /* Switch mouse to non-warped mode if mickeys were not used recently (~2 seconds).  */
   if (_xwin.mouse_warped && (_xwin.mouse_warped++ > MOUSE_WARP_DELAY)) {
      _xwin.mouse_warped = 0;
      /* Move X-cursor to Allegro cursor.  */
      XWarpPointer(_xwin.display, _xwin.window, _xwin.window,
               0, 0, _xwin.window_width, _xwin.window_height,
               _mouse_x - (_xwin_mouse_extended_range ? _xwin.scroll_x : 0),
               _mouse_y - (_xwin_mouse_extended_range ? _xwin.scroll_y : 0));
   }

   /* Flush X-buffers.  */
   _xwin_private_flush_buffers();

   /* How much events are available in the queue.  */
   events = events_queued = XEventsQueued(_xwin.display, QueuedAlready);
   if (events <= 0)
      return;

   /* Limit amount of events we read at once.  */
   if (events > X_MAX_EVENTS)
      events = X_MAX_EVENTS;

   /* Read pending events.  */
   for (i = 0; i < events; i++)
      XNextEvent(_xwin.display, &event[i]);

   /* Can't have a KeyRelease as last event, since it might be only half
    * of a key repeat pair. Also see comment below.
    */
   if (events_queued > events && event[i - 1].type == KeyRelease) {
      XNextEvent(_xwin.display, &event[i]);
      events++;
   }

   /* Process all events.  */
   for (i = 0; i < events; i++) {

      /* Hack to make Allegro's key[] array work despite of key repeat.
       * If a KeyRelease is sent at the same time as a KeyPress following
       * it with the same keycode, we ignore the release event.
       */
      if (event[i].type == KeyRelease && (i + 1) < events) {
       if (event[i + 1].type == KeyPress) {
          if (event[i].xkey.keycode == event[i + 1].xkey.keycode &&
             event[i].xkey.time == event[i + 1].xkey.time)
             continue;
       }
      }

      _xwin_private_process_event(&event[i]);
   }
}

void _xwin_handle_input(void)
{
#ifndef ALLEGRO_MULTITHREADED
   if (_xwin.lock_count) {
      ++_xwin_missed_input;
      return;
   }
#endif

   XLOCK();

   if (_xwin_input_handler)
      _xwin_input_handler();
   else
      _xwin_private_handle_input();

   XUNLOCK();
}



/* _xwin_set_warped_mouse_mode:
 *  Switch mouse handling into warped mode.
 */
static void _xwin_private_set_warped_mouse_mode(int permanent)
{
   /* Don't enable warp mode if the hardware cursor is being displayed */
   if (!_xwin.hw_cursor_ok)
      _xwin.mouse_warped = ((permanent) ? 1 : (MOUSE_WARP_DELAY*7/8));
}

void _xwin_set_warped_mouse_mode(int permanent)
{
   XLOCK();
   _xwin_private_set_warped_mouse_mode(permanent);
   XUNLOCK();
}



/* _xwin_redraw_window:
 *  Redraws part of the window.
 */
static void _xwin_private_redraw_window(int x, int y, int w, int h)
{
   if (_xwin.window == None)
      return;

   /* Clip updated region.  */
   if (x >= _xwin.screen_width)
      return;
   if (x < 0) {
      w += x;
      x = 0;
   }
   if (w >= (_xwin.screen_width - x))
      w = _xwin.screen_width - x;
   if (w <= 0)
      return;

   if (y >= _xwin.screen_height)
      return;
   if (y < 0) {
      h += y;
      y = 0;
   }
   if (h >= (_xwin.screen_height - y))
      h = _xwin.screen_height - y;
   if (h <= 0)
      return;

   if (!_xwin.ximage)
      XFillRectangle(_xwin.display, _xwin.window, _xwin.gc, x, y, w, h);
   else {
#ifdef ALLEGRO_XWINDOWS_WITH_SHM
      if (_xwin.use_shm)
       XShmPutImage(_xwin.display, _xwin.window, _xwin.gc, _xwin.ximage,
                  x + _xwin.scroll_x, y + _xwin.scroll_y, x, y, w, h, False);
      else
#endif
       XPutImage(_xwin.display, _xwin.window, _xwin.gc, _xwin.ximage,
               x + _xwin.scroll_x, y + _xwin.scroll_y, x, y, w, h);
   }
}

void _xwin_redraw_window(int x, int y, int w, int h)
{
   _xwin_lock(NULL);
   (*_xwin_window_redrawer)(x, y, w, h);
   _xwin_unlock(NULL);
}



/* _xwin_scroll_screen:
 *  Scroll visible screen in window.
 */
static int _xwin_private_scroll_screen(int x, int y)
{
   _xwin.scroll_x = x;
   _xwin.scroll_y = y;
   (*_xwin_window_redrawer)(0, 0, _xwin.screen_width, _xwin.screen_height);
   _xwin_private_flush_buffers();

   return 0;
}

int _xwin_scroll_screen(int x, int y)
{
   int result;

   if (x < 0)
      x = 0;
   else if (x >= (_xwin.virtual_width - _xwin.screen_width))
      x = _xwin.virtual_width - _xwin.screen_width;
   if (y < 0)
      y = 0;
   else if (y >= (_xwin.virtual_height - _xwin.screen_height))
      y = _xwin.virtual_height - _xwin.screen_height;
   if ((_xwin.scroll_x == x) && (_xwin.scroll_y == y))
      return 0;

   _xwin_lock(NULL);
   result = _xwin_private_scroll_screen(x, y);
   _xwin_unlock(NULL);
   return result;
}



/* _xwin_update_screen:
 *  Update part of the screen.
 */
static void _xwin_private_update_screen(int x, int y, int w, int h)
{
   /* Update frame buffer with screen contents.  */
   if (_xwin.screen_to_buffer != 0) {
      /* Clip updated region.  */
      if (x >= _xwin.virtual_width)
       return;
      if (x < 0) {
       w += x;
       x = 0;
      }
      if (w >= (_xwin.virtual_width - x))
       w = _xwin.virtual_width - x;
      if (w <= 0)
       return;

      if (y >= _xwin.virtual_height)
       return;
      if (y < 0) {
       h += y;
       y = 0;
      }
      if (h >= (_xwin.virtual_height - y))
       h = _xwin.virtual_height - y;
      if (h <= 0)
       return;

      (*(_xwin.screen_to_buffer))(x, y, w, h);
   }

   /* Update window.  */
   (*_xwin_window_redrawer)(x - _xwin.scroll_x, y - _xwin.scroll_y, w, h);
}

void _xwin_update_screen(int x, int y, int w, int h)
{
   _xwin_lock(NULL);
   _xwin_private_update_screen(x, y, w, h);
   _xwin_unlock(NULL);
}



/* _xwin_set_window_title:
 *  Wrapper for XStoreName.
 */
static void _xwin_private_set_window_title(AL_CONST char *name)
{
   if (!name)
      _al_sane_strncpy(_xwin.window_title, XWIN_DEFAULT_WINDOW_TITLE, sizeof(_xwin.window_title));
   else
      _al_sane_strncpy(_xwin.window_title, name, sizeof(_xwin.window_title));

   if (_xwin.window != None)
      XStoreName(_xwin.display, _xwin.window, _xwin.window_title);
}

void _xwin_set_window_title(AL_CONST char *name)
{
   XLOCK();
   _xwin_private_set_window_title(name);
   XUNLOCK();
}



/* _xwin_sysdrv_set_window_name:
 *  Sets window name and group.
 */
static void _xwin_private_set_window_name(AL_CONST char *name, AL_CONST char *group)
{
   XClassHint hint;

   if (!name)
      _al_sane_strncpy(_xwin.application_name, XWIN_DEFAULT_APPLICATION_NAME, sizeof(_xwin.application_name));
   else
      _al_sane_strncpy(_xwin.application_name, name, sizeof(_xwin.application_name));

   if (!group)
      _al_sane_strncpy(_xwin.application_class, XWIN_DEFAULT_APPLICATION_CLASS, sizeof(_xwin.application_class));
   else
      _al_sane_strncpy(_xwin.application_class, group, sizeof(_xwin.application_class));

   if (_xwin.window != None) {
      hint.res_name = _xwin.application_name;
      hint.res_class = _xwin.application_class;
      XSetClassHint(_xwin.display, _xwin.window, &hint);
   }
}

void xwin_set_window_name(AL_CONST char *name, AL_CONST char *group)
{
   char tmp1[128], tmp2[128];

   do_uconvert(name, U_CURRENT, tmp1, U_ASCII, sizeof(tmp1));
   do_uconvert(group, U_CURRENT, tmp2, U_ASCII, sizeof(tmp2));

   XLOCK();
   _xwin_private_set_window_name(tmp1, tmp2);
   XUNLOCK();
}



/* _xwin_get_pointer_mapping:
 *  Wrapper for XGetPointerMapping.
 */
static int _xwin_private_get_pointer_mapping(unsigned char map[], int nmap)
{
   return ((_xwin.display == 0) ? -1 : XGetPointerMapping(_xwin.display, map, nmap));
}

int _xwin_get_pointer_mapping(unsigned char map[], int nmap)
{
   int num;
   XLOCK();
   num = _xwin_private_get_pointer_mapping(map, nmap);
   XUNLOCK();
   return num;
}



/* _xwin_write_line:
 *  Update last selected line and select new line.
 */
uintptr_t _xwin_write_line(BITMAP *bmp, int line)
{
   int new_line = line + bmp->y_ofs;
   if ((new_line != _xwin_last_line) && (!_xwin_in_gfx_call) && (_xwin_last_line >= 0))
      _xwin_update_screen(0, _xwin_last_line, _xwin.virtual_width, 1);
   _xwin_last_line = new_line;
   return (uintptr_t) (bmp->line[line]);
}



/* _xwin_unwrite_line:
 *  Update last selected line.
 */
void _xwin_unwrite_line(BITMAP *bmp)
{
   if ((!_xwin_in_gfx_call) && (_xwin_last_line >= 0))
      _xwin_update_screen(0, _xwin_last_line, _xwin.virtual_width, 1);
   _xwin_last_line = -1;
}



/*
 * Support for XF86VidMode extension.
 */
#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
/* _xvidmode_private_set_fullscreen:
 *  Attempt to switch video mode and make window fullscreen.
 */
static int _xvidmode_private_set_fullscreen(int w, int h)
{
   int vid_event_base, vid_error_base;
   int vid_major_version, vid_minor_version;
   XF86VidModeModeInfo *mode;
   int i;

   /* Test that display is local.  */
   if (!_xwin_private_display_is_local()) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VidMode extension requires local display"));
      return 0;
   }

   /* Test for presence of VidMode extension.  */
   if (!XF86VidModeQueryExtension(_xwin.display, &vid_event_base, &vid_error_base)
       || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version, &vid_minor_version)) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VidMode extension is not supported"));
      return 0;
   }

   /* Get list of modelines.  */
   if (!XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen,
                           &_xwin.num_modes, &_xwin.modesinfo))
      return 0;

   /* Search for a matching video mode.  */
   for (i = 0; i < _xwin.num_modes; i++) {
      mode = _xwin.modesinfo[i];
      if ((mode->hdisplay == w) && (mode->vdisplay == h)) {
       /* Switch video mode.  */
       if (!XF86VidModeSwitchToMode(_xwin.display, _xwin.screen, mode))
          return 0;

       /* Lock mode switching.  */
       XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, True);

       _xwin.mode_switched = 1;
       return 1;
      }
   }

   return 0;
}



/* free_modelines:
 *  Free mode lines.
 */
static void free_modelines(XF86VidModeModeInfo **modesinfo, int num_modes)
{
   int i;

   for (i = 0; i < num_modes; i++)
      if (modesinfo[i]->privsize > 0)
       XFree(modesinfo[i]->private);
   XFree(modesinfo);
}



/* _xvidmode_private_unset_fullscreen:
 *  Restore original video mode and window attributes.
 */
static void _xvidmode_private_unset_fullscreen(void)
{
   if (_xwin.num_modes > 0) {
      if (_xwin.mode_switched) {
       /* Unlock mode switching.  */
       XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, False);

       /* Restore the original video mode.  */
       XF86VidModeSwitchToMode(_xwin.display, _xwin.screen, _xwin.modesinfo[0]);

       _xwin.mode_switched = 0;
      }

      /* Free modelines.  */
      free_modelines(_xwin.modesinfo, _xwin.num_modes);
      _xwin.num_modes = 0;
      _xwin.modesinfo = 0;
   }
}



/* _xvidmode_private_fetch_mode_list:
 *  Generates a list of valid video modes.
 */
static GFX_MODE_LIST *_xvidmode_private_fetch_mode_list(void)
{
   int vid_event_base, vid_error_base;
   int vid_major_version, vid_minor_version;
   XF86VidModeModeInfo **modesinfo;
   int num_modes, num_bpp;
   GFX_MODE_LIST *mode_list;
   int i, j;

   /* Test that display is local.  */
   if (!_xwin_private_display_is_local())
      return 0;

   /* Test for presence of VidMode extension.  */
   if (!XF86VidModeQueryExtension(_xwin.display, &vid_event_base, &vid_error_base)
       || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version, &vid_minor_version))
      return 0;

   /* Get list of modelines.  */
   if (!XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen, &num_modes, &modesinfo))
      return 0;

   /* Calculate the number of color depths we have to support.  */
   num_bpp = 0;
#ifdef ALLEGRO_COLOR8
   num_bpp++;
#endif
#ifdef ALLEGRO_COLOR16
   num_bpp += 2;     /* 15, 16 */
#endif
#ifdef ALLEGRO_COLOR24
   num_bpp++;
#endif
#ifdef ALLEGRO_COLOR32
   num_bpp++;
#endif
   if (num_bpp == 0) /* ha! */
      return 0;

   /* Allocate space for mode list.  */
   mode_list = malloc(sizeof(GFX_MODE_LIST));
   if (!mode_list) {
      free_modelines(modesinfo, num_modes);
      return 0;
   }

   mode_list->mode = malloc(sizeof(GFX_MODE) * ((num_modes * num_bpp) + 1));
   if (!mode_list->mode) {
      free(mode_list);
      free_modelines(modesinfo, num_modes);
      return 0;
   }

   /* Fill in mode list.  */
   j = 0;
   for (i = 0; i < num_modes; i++) {
#define ADD_MODE(BPP)                               \
      mode_list->mode[j].width = modesinfo[i]->hdisplay;    \
      mode_list->mode[j].height = modesinfo[i]->vdisplay;   \
      mode_list->mode[j].bpp = BPP;                 \
      j++
#ifdef ALLEGRO_COLOR8
      ADD_MODE(8);
#endif
#ifdef ALLEGRO_COLOR16
      ADD_MODE(15);
      ADD_MODE(16);
#endif
#ifdef ALLEGRO_COLOR24
      ADD_MODE(24);
#endif
#ifdef ALLEGRO_COLOR32
      ADD_MODE(32);
#endif
   }

   mode_list->mode[j].width = 0;
   mode_list->mode[j].height = 0;
   mode_list->mode[j].bpp = 0;
   mode_list->num_modes = j;

   free_modelines(modesinfo, num_modes);

   return mode_list;
}
#endif



/* _xwin_fetch_mode_list:
 *  Fetch mode list.
 */
GFX_MODE_LIST *_xwin_fetch_mode_list(void)
{
#ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE
   GFX_MODE_LIST *list;
   XLOCK();
   list = _xvidmode_private_fetch_mode_list();
   XUNLOCK();
   return list;
#else
   return 0;
#endif
}



/* Hook functions */
int (*_xwin_window_creator)(void) = &_xwin_private_create_window;
void (*_xwin_window_defaultor)(void) = &_xwin_private_set_window_defaults;
void (*_xwin_window_redrawer)(int, int, int, int) = &_xwin_private_redraw_window;
void (*_xwin_input_handler)(void) = 0;

void (*_xwin_keyboard_callback)(int, int) = 0;

Generated by  Doxygen 1.6.0   Back to index