src/video/x11/SDL_x11events.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 09 May 2006 07:20:32 +0000
changeset 1789 01313c1a2bbe
parent 1784 45669d4efd02
child 1792 409974dedf2e
permissions -rw-r--r--
Fixed bug #104

If your mouse cursor is not within the SDL frame and you warp the mouse, you
get an enter notify, not a motion notify.
Therefore, SDL does not update its internal mouse state.

What's about calling SDL_PrivateMouseMotion even when getting an EnterNotify?

Regards,
Johannes
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* Handle the event stream, converting X11 events into SDL events */
    25 
    26 #include <setjmp.h>
    27 #include <X11/Xlib.h>
    28 #include <X11/Xutil.h>
    29 #include <X11/keysym.h>
    30 #ifdef __SVR4
    31 #include <X11/Sunkeysym.h>
    32 #endif
    33 #include <sys/types.h>
    34 #include <sys/time.h>
    35 #include <unistd.h>
    36 
    37 #include "SDL_timer.h"
    38 #include "SDL_syswm.h"
    39 #include "../SDL_sysvideo.h"
    40 #include "../../events/SDL_sysevents.h"
    41 #include "../../events/SDL_events_c.h"
    42 #include "SDL_x11video.h"
    43 #include "SDL_x11dga_c.h"
    44 #include "SDL_x11modes_c.h"
    45 #include "SDL_x11image_c.h"
    46 #include "SDL_x11gamma_c.h"
    47 #include "SDL_x11wm_c.h"
    48 #include "SDL_x11mouse_c.h"
    49 #include "SDL_x11events_c.h"
    50 
    51 
    52 /* Define this if you want to debug X11 events */
    53 /*#define DEBUG_XEVENTS*/
    54 
    55 /* The translation tables from an X11 keysym to a SDL keysym */
    56 static SDLKey ODD_keymap[256];
    57 static SDLKey MISC_keymap[256];
    58 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc);
    59 
    60 
    61 #ifdef X_HAVE_UTF8_STRING
    62 Uint32 Utf8ToUcs4(const Uint8 *utf8)
    63 {
    64 	Uint32 c;
    65 	int i = 1;
    66 	int noOctets = 0;
    67 	int firstOctetMask = 0;
    68 	unsigned char firstOctet = utf8[0];
    69 	if (firstOctet < 0x80) {
    70 		/*
    71 		  Characters in the range:
    72 		    00000000 to 01111111 (ASCII Range)
    73 		  are stored in one octet:
    74 		    0xxxxxxx (The same as its ASCII representation)
    75 		  The least 6 significant bits of the first octet is the most 6 significant nonzero bits
    76 		  of the UCS4 representation.
    77 		*/
    78 		noOctets = 1;
    79 		firstOctetMask = 0x7F;  /* 0(1111111) - The most significant bit is ignored */
    80 	} else if ((firstOctet & 0xE0) /* get the most 3 significant bits by AND'ing with 11100000 */
    81 	              == 0xC0 ) {  /* see if those 3 bits are 110. If so, the char is in this range */
    82 		/*
    83 		  Characters in the range:
    84 		    00000000 10000000 to 00000111 11111111
    85 		  are stored in two octets:
    86 		    110xxxxx 10xxxxxx
    87 		  The least 5 significant bits of the first octet is the most 5 significant nonzero bits
    88 		  of the UCS4 representation.
    89 		*/
    90 		noOctets = 2;
    91 		firstOctetMask = 0x1F;  /* 000(11111) - The most 3 significant bits are ignored */
    92 	} else if ((firstOctet & 0xF0) /* get the most 4 significant bits by AND'ing with 11110000 */
    93 	              == 0xE0) {  /* see if those 4 bits are 1110. If so, the char is in this range */
    94 		/*
    95 		  Characters in the range:
    96 		    00001000 00000000 to 11111111 11111111
    97 		  are stored in three octets:
    98 		    1110xxxx 10xxxxxx 10xxxxxx
    99 		  The least 4 significant bits of the first octet is the most 4 significant nonzero bits
   100 		  of the UCS4 representation.
   101 		*/
   102 		noOctets = 3;
   103 		firstOctetMask = 0x0F; /* 0000(1111) - The most 4 significant bits are ignored */
   104 	} else if ((firstOctet & 0xF8) /* get the most 5 significant bits by AND'ing with 11111000 */
   105 	              == 0xF0) {  /* see if those 5 bits are 11110. If so, the char is in this range */
   106 		/*
   107 		  Characters in the range:
   108 		    00000001 00000000 00000000 to 00011111 11111111 11111111
   109 		  are stored in four octets:
   110 		    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
   111 		  The least 3 significant bits of the first octet is the most 3 significant nonzero bits
   112 		  of the UCS4 representation.
   113 		*/
   114 		noOctets = 4;
   115 		firstOctetMask = 0x07; /* 11110(111) - The most 5 significant bits are ignored */
   116 	} else if ((firstOctet & 0xFC) /* get the most 6 significant bits by AND'ing with 11111100 */
   117 	              == 0xF8) { /* see if those 6 bits are 111110. If so, the char is in this range */
   118 		/*
   119 		  Characters in the range:
   120 		    00000000 00100000 00000000 00000000 to
   121 		    00000011 11111111 11111111 11111111
   122 		  are stored in five octets:
   123 		    111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
   124 		  The least 2 significant bits of the first octet is the most 2 significant nonzero bits
   125 		  of the UCS4 representation.
   126 		*/
   127 		noOctets = 5;
   128 		firstOctetMask = 0x03; /* 111110(11) - The most 6 significant bits are ignored */
   129 	} else if ((firstOctet & 0xFE) /* get the most 7 significant bits by AND'ing with 11111110 */
   130 	              == 0xFC) { /* see if those 7 bits are 1111110. If so, the char is in this range */
   131 		/*
   132 		  Characters in the range:
   133 		    00000100 00000000 00000000 00000000 to
   134 		    01111111 11111111 11111111 11111111
   135 		  are stored in six octets:
   136 		    1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
   137 		  The least significant bit of the first octet is the most significant nonzero bit
   138 		  of the UCS4 representation.
   139 		*/
   140 		noOctets = 6;
   141 		firstOctetMask = 0x01; /* 1111110(1) - The most 7 significant bits are ignored */
   142 	} else
   143 		return 0;  /* The given chunk is not a valid UTF-8 encoded Unicode character */
   144 	
   145 	/*
   146 	  The least noOctets significant bits of the first octet is the most 2 significant nonzero bits
   147 	  of the UCS4 representation.
   148 	  The first 6 bits of the UCS4 representation is the least 8-noOctets-1 significant bits of
   149 	  firstOctet if the character is not ASCII. If so, it's the least 7 significant bits of firstOctet.
   150 	  This done by AND'ing firstOctet with its mask to trim the bits used for identifying the
   151 	  number of continuing octets (if any) and leave only the free bits (the x's)
   152 	  Sample:
   153 	  1-octet:    0xxxxxxx  &  01111111 = 0xxxxxxx
   154 	  2-octets:  110xxxxx  &  00011111 = 000xxxxx
   155 	*/
   156 	c = firstOctet & firstOctetMask;
   157 	
   158 	/* Now, start filling c.ucs4 with the bits from the continuing octets from utf8. */
   159 	for (i = 1; i < noOctets; i++) {
   160 		/* A valid continuing octet is of the form 10xxxxxx */
   161 		if ((utf8[i] & 0xC0) /* get the most 2 significant bits by AND'ing with 11000000 */
   162 		    != 0x80) /* see if those 2 bits are 10. If not, the is a malformed sequence. */
   163 			/*The given chunk is a partial sequence at the end of a string that could
   164 			   begin a valid character */
   165 			return 0;
   166 		
   167 		/* Make room for the next 6-bits */
   168 		c <<= 6;
   169 		
   170 		/*
   171 		  Take only the least 6 significance bits of the current octet (utf8[i]) and fill the created room
   172 		  of c.ucs4 with them.
   173 		  This done by AND'ing utf8[i] with 00111111 and the OR'ing the result with c.ucs4.
   174 		*/
   175 		c |= utf8[i] & 0x3F;
   176 	}
   177 	return c;
   178 }
   179 #endif
   180 
   181 /* Check to see if this is a repeated key.
   182    (idea shamelessly lifted from GII -- thanks guys! :)
   183  */
   184 static int X11_KeyRepeat(Display *display, XEvent *event)
   185 {
   186 	XEvent peekevent;
   187 	int repeated;
   188 
   189 	repeated = 0;
   190 	if ( XPending(display) ) {
   191 		XPeekEvent(display, &peekevent);
   192 		if ( (peekevent.type == KeyPress) &&
   193 		     (peekevent.xkey.keycode == event->xkey.keycode) &&
   194 		     ((peekevent.xkey.time-event->xkey.time) < 2) ) {
   195 			repeated = 1;
   196 			XNextEvent(display, &peekevent);
   197 		}
   198 	}
   199 	return(repeated);
   200 }
   201 
   202 /* Note:  The X server buffers and accumulates mouse motion events, so
   203    the motion event generated by the warp may not appear exactly as we
   204    expect it to.  We work around this (and improve performance) by only
   205    warping the pointer when it reaches the edge, and then wait for it.
   206 */
   207 #define MOUSE_FUDGE_FACTOR	8
   208 
   209 static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent)
   210 {
   211 	int w, h, i;
   212 	int deltax, deltay;
   213 	int posted;
   214 
   215 	w = SDL_VideoSurface->w;
   216 	h = SDL_VideoSurface->h;
   217 	deltax = xevent->xmotion.x - mouse_last.x;
   218 	deltay = xevent->xmotion.y - mouse_last.y;
   219 #ifdef DEBUG_MOTION
   220   printf("Warped mouse motion: %d,%d\n", deltax, deltay);
   221 #endif
   222 	mouse_last.x = xevent->xmotion.x;
   223 	mouse_last.y = xevent->xmotion.y;
   224 	posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay);
   225 
   226 	if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) ||
   227 	     (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) ||
   228 	     (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) ||
   229 	     (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) {
   230 		/* Get the events that have accumulated */
   231 		while ( XCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) {
   232 			deltax = xevent->xmotion.x - mouse_last.x;
   233 			deltay = xevent->xmotion.y - mouse_last.y;
   234 #ifdef DEBUG_MOTION
   235   printf("Extra mouse motion: %d,%d\n", deltax, deltay);
   236 #endif
   237 			mouse_last.x = xevent->xmotion.x;
   238 			mouse_last.y = xevent->xmotion.y;
   239 			posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay);
   240 		}
   241 		mouse_last.x = w/2;
   242 		mouse_last.y = h/2;
   243 		XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0,
   244 					mouse_last.x, mouse_last.y);
   245 		for ( i=0; i<10; ++i ) {
   246         		XMaskEvent(SDL_Display, PointerMotionMask, xevent);
   247 			if ( (xevent->xmotion.x >
   248 			          (mouse_last.x-MOUSE_FUDGE_FACTOR)) &&
   249 			     (xevent->xmotion.x <
   250 			          (mouse_last.x+MOUSE_FUDGE_FACTOR)) &&
   251 			     (xevent->xmotion.y >
   252 			          (mouse_last.y-MOUSE_FUDGE_FACTOR)) &&
   253 			     (xevent->xmotion.y <
   254 			          (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) {
   255 				break;
   256 			}
   257 #ifdef DEBUG_XEVENTS
   258   printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y);
   259 #endif
   260 		}
   261 #ifdef DEBUG_XEVENTS
   262 		if ( i == 10 ) {
   263 			printf("Warning: didn't detect mouse warp motion\n");
   264 		}
   265 #endif
   266 	}
   267 	return(posted);
   268 }
   269 
   270 static int X11_DispatchEvent(_THIS)
   271 {
   272 	int posted;
   273 	XEvent xevent;
   274 
   275 	SDL_memset(&xevent, '\0', sizeof (XEvent));  /* valgrind fix. --ryan. */
   276 	XNextEvent(SDL_Display, &xevent);
   277 
   278 	posted = 0;
   279 	switch (xevent.type) {
   280 
   281 	    /* Gaining mouse coverage? */
   282 	    case EnterNotify: {
   283 #ifdef DEBUG_XEVENTS
   284 printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
   285 if ( xevent.xcrossing.mode == NotifyGrab )
   286 printf("Mode: NotifyGrab\n");
   287 if ( xevent.xcrossing.mode == NotifyUngrab )
   288 printf("Mode: NotifyUngrab\n");
   289 #endif
   290 		if ( (xevent.xcrossing.mode != NotifyGrab) &&
   291 		     (xevent.xcrossing.mode != NotifyUngrab) ) {
   292 			if ( this->input_grab == SDL_GRAB_OFF ) {
   293 				posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
   294 			}
   295 			posted = SDL_PrivateMouseMotion(0, 0,
   296 					xevent.xcrossing.x,
   297 					xevent.xcrossing.y);
   298 		}
   299 	    }
   300 	    break;
   301 
   302 	    /* Losing mouse coverage? */
   303 	    case LeaveNotify: {
   304 #ifdef DEBUG_XEVENTS
   305 printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
   306 if ( xevent.xcrossing.mode == NotifyGrab )
   307 printf("Mode: NotifyGrab\n");
   308 if ( xevent.xcrossing.mode == NotifyUngrab )
   309 printf("Mode: NotifyUngrab\n");
   310 #endif
   311 		if ( (xevent.xcrossing.mode != NotifyGrab) &&
   312 		     (xevent.xcrossing.mode != NotifyUngrab) &&
   313 		     (xevent.xcrossing.detail != NotifyInferior) ) {
   314 			if ( this->input_grab == SDL_GRAB_OFF ) {
   315 				posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
   316 			} else {
   317 				posted = SDL_PrivateMouseMotion(0, 0,
   318 						xevent.xcrossing.x,
   319 						xevent.xcrossing.y);
   320 			}
   321 		}
   322 	    }
   323 	    break;
   324 
   325 	    /* Gaining input focus? */
   326 	    case FocusIn: {
   327 #ifdef DEBUG_XEVENTS
   328 printf("FocusIn!\n");
   329 #endif
   330 		posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
   331 
   332 #ifdef X_HAVE_UTF8_STRING
   333 		if ( SDL_IC != NULL ) {
   334 			XSetICFocus(SDL_IC);
   335 		}
   336 #endif
   337 		/* Queue entry into fullscreen mode */
   338 		switch_waiting = 0x01 | SDL_FULLSCREEN;
   339 		switch_time = SDL_GetTicks() + 1500;
   340 	    }
   341 	    break;
   342 
   343 	    /* Losing input focus? */
   344 	    case FocusOut: {
   345 #ifdef DEBUG_XEVENTS
   346 printf("FocusOut!\n");
   347 #endif
   348 		posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
   349 
   350 #ifdef X_HAVE_UTF8_STRING
   351 		if ( SDL_IC != NULL ) {
   352 			XUnsetICFocus(SDL_IC);
   353 		}
   354 #endif
   355 		/* Queue leaving fullscreen mode */
   356 		switch_waiting = 0x01;
   357 		switch_time = SDL_GetTicks() + 200;
   358 	    }
   359 	    break;
   360 
   361 	    /* Generated upon EnterWindow and FocusIn */
   362 	    case KeymapNotify: {
   363 #ifdef DEBUG_XEVENTS
   364 printf("KeymapNotify!\n");
   365 #endif
   366 		X11_SetKeyboardState(SDL_Display,  xevent.xkeymap.key_vector);
   367 	    }
   368 	    break;
   369 
   370 	    /* Mouse motion? */
   371 	    case MotionNotify: {
   372 		if ( SDL_VideoSurface ) {
   373 			if ( mouse_relative ) {
   374 				if ( using_dga & DGA_MOUSE ) {
   375 #ifdef DEBUG_MOTION
   376   printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
   377 #endif
   378 					posted = SDL_PrivateMouseMotion(0, 1,
   379 							xevent.xmotion.x_root,
   380 							xevent.xmotion.y_root);
   381 				} else {
   382 					posted = X11_WarpedMotion(this,&xevent);
   383 				}
   384 			} else {
   385 #ifdef DEBUG_MOTION
   386   printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
   387 #endif
   388 				posted = SDL_PrivateMouseMotion(0, 0,
   389 						xevent.xmotion.x,
   390 						xevent.xmotion.y);
   391 			}
   392 		}
   393 	    }
   394 	    break;
   395 
   396 	    /* Mouse button press? */
   397 	    case ButtonPress: {
   398 		posted = SDL_PrivateMouseButton(SDL_PRESSED, 
   399 					xevent.xbutton.button, 0, 0);
   400 	    }
   401 	    break;
   402 
   403 	    /* Mouse button release? */
   404 	    case ButtonRelease: {
   405 		posted = SDL_PrivateMouseButton(SDL_RELEASED, 
   406 					xevent.xbutton.button, 0, 0);
   407 	    }
   408 	    break;
   409 
   410 	    /* Key press? */
   411 	    case KeyPress: {
   412 		static SDL_keysym saved_keysym;
   413 		SDL_keysym keysym;
   414 		KeyCode keycode = xevent.xkey.keycode;
   415 
   416 #ifdef DEBUG_XEVENTS
   417 printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   418 #endif
   419 		/* Get the translated SDL virtual keysym */
   420 		if ( keycode ) {
   421 			keysym.scancode = keycode;
   422 			keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
   423 			keysym.mod = KMOD_NONE;
   424 			keysym.unicode = 0;
   425 		} else {
   426 			keysym = saved_keysym;
   427 		}
   428 
   429 		/* If we're not doing translation, we're done! */
   430 		if ( !SDL_TranslateUNICODE ) {
   431 			posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   432 			break;
   433 		}
   434 
   435 		if ( XFilterEvent(&xevent, None) ) {
   436 			if ( xevent.xkey.keycode ) {
   437 				posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   438 			} else {
   439 				/* Save event to be associated with IM text
   440 				   In 1.3 we'll have a text event instead.. */
   441 				saved_keysym = keysym;
   442 			}
   443 			break;
   444 		}
   445 
   446 		/* Look up the translated value for the key event */
   447 #ifdef X_HAVE_UTF8_STRING
   448 		if ( SDL_IC != NULL ) {
   449 			static Status state;
   450 			/* A UTF-8 character can be at most 6 bytes */
   451 			char keybuf[6];
   452 			if ( Xutf8LookupString(SDL_IC, &xevent.xkey,
   453 			                        keybuf, sizeof(keybuf),
   454 			                        NULL, &state) ) {
   455 				keysym.unicode = Utf8ToUcs4((Uint8*)keybuf);
   456 			}
   457 		}
   458 		else
   459 #endif
   460 		{
   461 			static XComposeStatus state;
   462 			char keybuf[32];
   463 
   464 			if ( XLookupString(&xevent.xkey,
   465 			                    keybuf, sizeof(keybuf),
   466 			                    NULL, &state) ) {
   467 				/*
   468 				* FIXME: XLookupString() may yield more than one
   469 				* character, so we need a mechanism to allow for
   470 				* this (perhaps null keypress events with a
   471 				* unicode value)
   472 				*/
   473 				keysym.unicode = (Uint8)keybuf[0];
   474 			}
   475 		}
   476 		posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   477 	    }
   478 	    break;
   479 
   480 	    /* Key release? */
   481 	    case KeyRelease: {
   482 		SDL_keysym keysym;
   483 		KeyCode keycode = xevent.xkey.keycode;
   484 
   485 #ifdef DEBUG_XEVENTS
   486 printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   487 #endif
   488 		/* Check to see if this is a repeated key */
   489 		if ( X11_KeyRepeat(SDL_Display, &xevent) ) {
   490 			break;
   491 		}
   492 
   493 		/* Get the translated SDL virtual keysym */
   494 		keysym.scancode = keycode;
   495 		keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
   496 		keysym.mod = KMOD_NONE;
   497 		keysym.unicode = 0;
   498 
   499 		posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym);
   500 	    }
   501 	    break;
   502 
   503 	    /* Have we been iconified? */
   504 	    case UnmapNotify: {
   505 #ifdef DEBUG_XEVENTS
   506 printf("UnmapNotify!\n");
   507 #endif
   508 		/* If we're active, make ourselves inactive */
   509 		if ( SDL_GetAppState() & SDL_APPACTIVE ) {
   510 			/* Swap out the gamma before we go inactive */
   511 			X11_SwapVidModeGamma(this);
   512 
   513 			/* Send an internal deactivate event */
   514 			posted = SDL_PrivateAppActive(0,
   515 					SDL_APPACTIVE|SDL_APPINPUTFOCUS);
   516 		}
   517 	    }
   518 	    break;
   519 
   520 	    /* Have we been restored? */
   521 	    case MapNotify: {
   522 #ifdef DEBUG_XEVENTS
   523 printf("MapNotify!\n");
   524 #endif
   525 		/* If we're not active, make ourselves active */
   526 		if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) {
   527 			/* Send an internal activate event */
   528 			posted = SDL_PrivateAppActive(1, SDL_APPACTIVE);
   529 
   530 			/* Now that we're active, swap the gamma back */
   531 			X11_SwapVidModeGamma(this);
   532 		}
   533 
   534 		if ( SDL_VideoSurface &&
   535 		     (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
   536 			X11_EnterFullScreen(this);
   537 		} else {
   538 			X11_GrabInputNoLock(this, this->input_grab);
   539 		}
   540 		X11_CheckMouseModeNoLock(this);
   541 
   542 		if ( SDL_VideoSurface ) {
   543 			X11_RefreshDisplay(this);
   544 		}
   545 	    }
   546 	    break;
   547 
   548 	    /* Have we been resized or moved? */
   549 	    case ConfigureNotify: {
   550 #ifdef DEBUG_XEVENTS
   551 printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);
   552 #endif
   553 		if ( SDL_VideoSurface ) {
   554 		    if ((xevent.xconfigure.width != SDL_VideoSurface->w) ||
   555 		        (xevent.xconfigure.height != SDL_VideoSurface->h)) {
   556 			/* FIXME: Find a better fix for the bug with KDE 1.2 */
   557 			if ( ! ((xevent.xconfigure.width == 32) &&
   558 			        (xevent.xconfigure.height == 32)) ) {
   559 				SDL_PrivateResize(xevent.xconfigure.width,
   560 				                  xevent.xconfigure.height);
   561 			}
   562 		    } else {
   563 			/* OpenGL windows need to know about the change */
   564 			if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
   565 				SDL_PrivateExpose();
   566 			}
   567 		    }
   568 		}
   569 	    }
   570 	    break;
   571 
   572 	    /* Have we been requested to quit (or another client message?) */
   573 	    case ClientMessage: {
   574 		if ( (xevent.xclient.format == 32) &&
   575 		     (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) )
   576 		{
   577 			posted = SDL_PrivateQuit();
   578 		} else
   579 		if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   580 			SDL_SysWMmsg wmmsg;
   581 
   582 			SDL_VERSION(&wmmsg.version);
   583 			wmmsg.subsystem = SDL_SYSWM_X11;
   584 			wmmsg.event.xevent = xevent;
   585 			posted = SDL_PrivateSysWMEvent(&wmmsg);
   586 		}
   587 	    }
   588 	    break;
   589 
   590 	    /* Do we need to refresh ourselves? */
   591 	    case Expose: {
   592 #ifdef DEBUG_XEVENTS
   593 printf("Expose (count = %d)\n", xevent.xexpose.count);
   594 #endif
   595 		if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) {
   596 			X11_RefreshDisplay(this);
   597 		}
   598 	    }
   599 	    break;
   600 
   601 	    default: {
   602 #ifdef DEBUG_XEVENTS
   603 printf("Unhandled event %d\n", xevent.type);
   604 #endif
   605 		/* Only post the event if we're watching for it */
   606 		if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   607 			SDL_SysWMmsg wmmsg;
   608 
   609 			SDL_VERSION(&wmmsg.version);
   610 			wmmsg.subsystem = SDL_SYSWM_X11;
   611 			wmmsg.event.xevent = xevent;
   612 			posted = SDL_PrivateSysWMEvent(&wmmsg);
   613 		}
   614 	    }
   615 	    break;
   616 	}
   617 	return(posted);
   618 }
   619 
   620 /* Ack!  XPending() actually performs a blocking read if no events available */
   621 int X11_Pending(Display *display)
   622 {
   623 	/* Flush the display connection and look to see if events are queued */
   624 	XFlush(display);
   625 	if ( XEventsQueued(display, QueuedAlready) ) {
   626 		return(1);
   627 	}
   628 
   629 	/* More drastic measures are required -- see if X is ready to talk */
   630 	{
   631 		static struct timeval zero_time;	/* static == 0 */
   632 		int x11_fd;
   633 		fd_set fdset;
   634 
   635 		x11_fd = ConnectionNumber(display);
   636 		FD_ZERO(&fdset);
   637 		FD_SET(x11_fd, &fdset);
   638 		if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) {
   639 			return(XPending(display));
   640 		}
   641 	}
   642 
   643 	/* Oh well, nothing is ready .. */
   644 	return(0);
   645 }
   646 
   647 void X11_PumpEvents(_THIS)
   648 {
   649 	int pending;
   650 
   651 	/* Keep processing pending events */
   652 	pending = 0;
   653 	while ( X11_Pending(SDL_Display) ) {
   654 		X11_DispatchEvent(this);
   655 		++pending;
   656 	}
   657 	if ( switch_waiting ) {
   658 		Uint32 now;
   659 
   660 		now  = SDL_GetTicks();
   661 		if ( pending || !SDL_VideoSurface ) {
   662 			/* Try again later... */
   663 			if ( switch_waiting & SDL_FULLSCREEN ) {
   664 				switch_time = now + 1500;
   665 			} else {
   666 				switch_time = now + 200;
   667 			}
   668 		} else if ( (int)(switch_time-now) <= 0 ) {
   669 			Uint32 go_fullscreen;
   670 
   671 			go_fullscreen = switch_waiting & SDL_FULLSCREEN;
   672 			switch_waiting = 0;
   673 			if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
   674 				if ( go_fullscreen ) {
   675 					X11_EnterFullScreen(this);
   676 				} else {
   677 					X11_LeaveFullScreen(this);
   678 				}
   679 			}
   680 			/* Handle focus in/out when grabbed */
   681 			if ( go_fullscreen ) {
   682 				X11_GrabInputNoLock(this, this->input_grab);
   683 			} else {
   684 				X11_GrabInputNoLock(this, SDL_GRAB_OFF);
   685 			}
   686 			X11_CheckMouseModeNoLock(this);
   687 		}
   688 	}
   689 }
   690 
   691 void X11_InitKeymap(void)
   692 {
   693 	int i;
   694 
   695 	/* Odd keys used in international keyboards */
   696 	for ( i=0; i<SDL_arraysize(ODD_keymap); ++i )
   697 		ODD_keymap[i] = SDLK_UNKNOWN;
   698 
   699  	/* Some of these might be mappable to an existing SDLK_ code */
   700  	ODD_keymap[XK_dead_grave&0xFF] = SDLK_COMPOSE;
   701  	ODD_keymap[XK_dead_acute&0xFF] = SDLK_COMPOSE;
   702  	ODD_keymap[XK_dead_tilde&0xFF] = SDLK_COMPOSE;
   703  	ODD_keymap[XK_dead_macron&0xFF] = SDLK_COMPOSE;
   704  	ODD_keymap[XK_dead_breve&0xFF] = SDLK_COMPOSE;
   705  	ODD_keymap[XK_dead_abovedot&0xFF] = SDLK_COMPOSE;
   706  	ODD_keymap[XK_dead_diaeresis&0xFF] = SDLK_COMPOSE;
   707  	ODD_keymap[XK_dead_abovering&0xFF] = SDLK_COMPOSE;
   708  	ODD_keymap[XK_dead_doubleacute&0xFF] = SDLK_COMPOSE;
   709  	ODD_keymap[XK_dead_caron&0xFF] = SDLK_COMPOSE;
   710  	ODD_keymap[XK_dead_cedilla&0xFF] = SDLK_COMPOSE;
   711  	ODD_keymap[XK_dead_ogonek&0xFF] = SDLK_COMPOSE;
   712  	ODD_keymap[XK_dead_iota&0xFF] = SDLK_COMPOSE;
   713  	ODD_keymap[XK_dead_voiced_sound&0xFF] = SDLK_COMPOSE;
   714  	ODD_keymap[XK_dead_semivoiced_sound&0xFF] = SDLK_COMPOSE;
   715  	ODD_keymap[XK_dead_belowdot&0xFF] = SDLK_COMPOSE;
   716 #ifdef XK_dead_hook
   717  	ODD_keymap[XK_dead_hook&0xFF] = SDLK_COMPOSE;
   718 #endif
   719 #ifdef XK_dead_horn
   720  	ODD_keymap[XK_dead_horn&0xFF] = SDLK_COMPOSE;
   721 #endif
   722 
   723 #ifdef XK_dead_circumflex
   724 	/* These X keysyms have 0xFE as the high byte */
   725 	ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET;
   726 #endif
   727 #ifdef XK_ISO_Level3_Shift
   728 	ODD_keymap[XK_ISO_Level3_Shift&0xFF] = SDLK_MODE; /* "Alt Gr" key */
   729 #endif
   730 
   731 	/* Map the miscellaneous keys */
   732 	for ( i=0; i<SDL_arraysize(MISC_keymap); ++i )
   733 		MISC_keymap[i] = SDLK_UNKNOWN;
   734 
   735 	/* These X keysyms have 0xFF as the high byte */
   736 	MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE;
   737 	MISC_keymap[XK_Tab&0xFF] = SDLK_TAB;
   738 	MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR;
   739 	MISC_keymap[XK_Return&0xFF] = SDLK_RETURN;
   740 	MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE;
   741 	MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE;
   742 	MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE;
   743 
   744 	MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0;		/* Keypad 0-9 */
   745 	MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1;
   746 	MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2;
   747 	MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3;
   748 	MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4;
   749 	MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5;
   750 	MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6;
   751 	MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7;
   752 	MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8;
   753 	MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9;
   754 	MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0;
   755 	MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1;	
   756 	MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2;
   757 	MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3;
   758 	MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4;
   759 	MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5;
   760 	MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6;
   761 	MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7;
   762 	MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8;
   763 	MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9;
   764 	MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD;
   765 	MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
   766 	MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
   767 	MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
   768 	MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS;
   769 	MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS;
   770 	MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER;
   771 	MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS;
   772 
   773 	MISC_keymap[XK_Up&0xFF] = SDLK_UP;
   774 	MISC_keymap[XK_Down&0xFF] = SDLK_DOWN;
   775 	MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT;
   776 	MISC_keymap[XK_Left&0xFF] = SDLK_LEFT;
   777 	MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT;
   778 	MISC_keymap[XK_Home&0xFF] = SDLK_HOME;
   779 	MISC_keymap[XK_End&0xFF] = SDLK_END;
   780 	MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP;
   781 	MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN;
   782 
   783 	MISC_keymap[XK_F1&0xFF] = SDLK_F1;
   784 	MISC_keymap[XK_F2&0xFF] = SDLK_F2;
   785 	MISC_keymap[XK_F3&0xFF] = SDLK_F3;
   786 	MISC_keymap[XK_F4&0xFF] = SDLK_F4;
   787 	MISC_keymap[XK_F5&0xFF] = SDLK_F5;
   788 	MISC_keymap[XK_F6&0xFF] = SDLK_F6;
   789 	MISC_keymap[XK_F7&0xFF] = SDLK_F7;
   790 	MISC_keymap[XK_F8&0xFF] = SDLK_F8;
   791 	MISC_keymap[XK_F9&0xFF] = SDLK_F9;
   792 	MISC_keymap[XK_F10&0xFF] = SDLK_F10;
   793 	MISC_keymap[XK_F11&0xFF] = SDLK_F11;
   794 	MISC_keymap[XK_F12&0xFF] = SDLK_F12;
   795 	MISC_keymap[XK_F13&0xFF] = SDLK_F13;
   796 	MISC_keymap[XK_F14&0xFF] = SDLK_F14;
   797 	MISC_keymap[XK_F15&0xFF] = SDLK_F15;
   798 
   799 	MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK;
   800 	MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
   801 	MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
   802 	MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT;
   803 	MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT;
   804 	MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL;
   805 	MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL;
   806 	MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT;
   807 	MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT;
   808 	MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA;
   809 	MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA;
   810 	MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
   811 	MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
   812 	MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
   813 	MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */
   814 
   815 	MISC_keymap[XK_Help&0xFF] = SDLK_HELP;
   816 	MISC_keymap[XK_Print&0xFF] = SDLK_PRINT;
   817 	MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ;
   818 	MISC_keymap[XK_Break&0xFF] = SDLK_BREAK;
   819 	MISC_keymap[XK_Menu&0xFF] = SDLK_MENU;
   820 	MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU;   /* Windows "Menu" key */
   821 }
   822 
   823 /* Get the translated SDL virtual keysym */
   824 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc)
   825 {
   826 	KeySym xsym;
   827 	SDLKey key;
   828 
   829 	xsym = XKeycodeToKeysym(display, kc, 0);
   830 #ifdef DEBUG_KEYS
   831 	fprintf(stderr, "Translating key code %d -> 0x%.4x\n", kc, xsym);
   832 #endif
   833 	key = SDLK_UNKNOWN;
   834 	if ( xsym ) {
   835 		switch (xsym>>8) {
   836 		    case 0x1005FF:
   837 #ifdef SunXK_F36
   838 			if ( xsym == SunXK_F36 )
   839 				key = SDLK_F11;
   840 #endif
   841 #ifdef SunXK_F37
   842 			if ( xsym == SunXK_F37 )
   843 				key = SDLK_F12;
   844 #endif
   845 			break;
   846 		    case 0x00:	/* Latin 1 */
   847 			key = (SDLKey)(xsym & 0xFF);
   848 			break;
   849 		    case 0x01:	/* Latin 2 */
   850 		    case 0x02:	/* Latin 3 */
   851 		    case 0x03:	/* Latin 4 */
   852 		    case 0x04:	/* Katakana */
   853 		    case 0x05:	/* Arabic */
   854 		    case 0x06:	/* Cyrillic */
   855 		    case 0x07:	/* Greek */
   856 		    case 0x08:	/* Technical */
   857 		    case 0x0A:	/* Publishing */
   858 		    case 0x0C:	/* Hebrew */
   859 		    case 0x0D:	/* Thai */
   860 			/* These are wrong, but it's better than nothing */
   861 			key = (SDLKey)(xsym & 0xFF);
   862 			break;
   863 		    case 0xFE:
   864 			key = ODD_keymap[xsym&0xFF];
   865 			break;
   866 		    case 0xFF:
   867 			key = MISC_keymap[xsym&0xFF];
   868 			break;
   869 		    default:
   870 			/*
   871 			fprintf(stderr, "X11: Unhandled xsym, sym = 0x%04x\n",
   872 					(unsigned int)xsym);
   873 			*/
   874 			break;
   875 		}
   876 	} else {
   877 		/* X11 doesn't know how to translate the key! */
   878 		switch (kc) {
   879 		    /* Caution:
   880 		       These keycodes are from the Microsoft Keyboard
   881 		     */
   882 		    case 115:
   883 			key = SDLK_LSUPER;
   884 			break;
   885 		    case 116:
   886 			key = SDLK_RSUPER;
   887 			break;
   888 		    case 117:
   889 			key = SDLK_MENU;
   890 			break;
   891 		    default:
   892 			/*
   893 			 * no point in an error message; happens for
   894 			 * several keys when we get a keymap notify
   895 			 */
   896 			break;
   897 		}
   898 	}
   899 	return key;
   900 }
   901 
   902 /* X11 modifier masks for various keys */
   903 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
   904 static unsigned num_mask, mode_switch_mask;
   905 
   906 static void get_modifier_masks(Display *display)
   907 {
   908 	static unsigned got_masks;
   909 	int i, j;
   910 	XModifierKeymap *xmods;
   911 	unsigned n;
   912 
   913 	if(got_masks)
   914 		return;
   915 
   916 	xmods = XGetModifierMapping(display);
   917 	n = xmods->max_keypermod;
   918 	for(i = 3; i < 8; i++) {
   919 		for(j = 0; j < n; j++) {
   920 			KeyCode kc = xmods->modifiermap[i * n + j];
   921 			KeySym ks = XKeycodeToKeysym(display, kc, 0);
   922 			unsigned mask = 1 << i;
   923 			switch(ks) {
   924 			case XK_Num_Lock:
   925 				num_mask = mask; break;
   926 			case XK_Alt_L:
   927 				alt_l_mask = mask; break;
   928 			case XK_Alt_R:
   929 				alt_r_mask = mask; break;
   930 			case XK_Meta_L:
   931 				meta_l_mask = mask; break;
   932 			case XK_Meta_R:
   933 				meta_r_mask = mask; break;
   934 			case XK_Mode_switch:
   935 				mode_switch_mask = mask; break;
   936 			}
   937 		}
   938 	}
   939 	XFreeModifiermap(xmods);
   940 	got_masks = 1;
   941 }
   942 
   943 
   944 /*
   945  * This function is semi-official; it is not officially exported and should
   946  * not be considered part of the SDL API, but may be used by client code
   947  * that *really* needs it (including legacy code).
   948  * It is slow, though, and should be avoided if possible.
   949  *
   950  * Note that it isn't completely accurate either; in particular, multi-key
   951  * sequences (dead accents, compose key sequences) will not work since the
   952  * state has been irrevocably lost.
   953  */
   954 Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers)
   955 {
   956 	struct SDL_VideoDevice *this = current_video;
   957 	char keybuf[32];
   958 	int i;
   959 	KeySym xsym = 0;
   960 	XKeyEvent xkey;
   961 	Uint16 unicode;
   962 
   963 	if ( !this || !SDL_Display ) {
   964 		return 0;
   965 	}
   966 
   967 	SDL_memset(&xkey, 0, sizeof(xkey));
   968 	xkey.display = SDL_Display;
   969 
   970 	xsym = keysym;		/* last resort if not found */
   971 	for (i = 0; i < 256; ++i) {
   972 		if ( MISC_keymap[i] == keysym ) {
   973 			xsym = 0xFF00 | i;
   974 			break;
   975 		} else if ( ODD_keymap[i] == keysym ) {
   976 			xsym = 0xFE00 | i;
   977 			break;
   978 		}
   979 	}
   980 
   981 	xkey.keycode = XKeysymToKeycode(xkey.display, xsym);
   982 
   983 	get_modifier_masks(SDL_Display);
   984 	if(modifiers & KMOD_SHIFT)
   985 		xkey.state |= ShiftMask;
   986 	if(modifiers & KMOD_CAPS)
   987 		xkey.state |= LockMask;
   988 	if(modifiers & KMOD_CTRL)
   989 		xkey.state |= ControlMask;
   990 	if(modifiers & KMOD_MODE)
   991 		xkey.state |= mode_switch_mask;
   992 	if(modifiers & KMOD_LALT)
   993 		xkey.state |= alt_l_mask;
   994 	if(modifiers & KMOD_RALT)
   995 		xkey.state |= alt_r_mask;
   996 	if(modifiers & KMOD_LMETA)
   997 		xkey.state |= meta_l_mask;
   998 	if(modifiers & KMOD_RMETA)
   999 		xkey.state |= meta_r_mask;
  1000 	if(modifiers & KMOD_NUM)
  1001 		xkey.state |= num_mask;
  1002 
  1003 	unicode = 0;
  1004 	if ( XLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) )
  1005 		unicode = (unsigned char)keybuf[0];
  1006 	return(unicode);
  1007 }
  1008 
  1009 
  1010 /*
  1011  * Called when focus is regained, to read the keyboard state and generate
  1012  * synthetic keypress/release events.
  1013  * key_vec is a bit vector of keycodes (256 bits)
  1014  */
  1015 void X11_SetKeyboardState(Display *display, const char *key_vec)
  1016 {
  1017 	char keys_return[32];
  1018 	int i;
  1019 	Uint8 *kstate = SDL_GetKeyState(NULL);
  1020 	SDLMod modstate;
  1021 	Window junk_window;
  1022 	int x, y;
  1023 	unsigned int mask;
  1024 
  1025 	/* The first time the window is mapped, we initialize key state */
  1026 	if ( ! key_vec ) {
  1027 		XQueryKeymap(display, keys_return);
  1028 		key_vec = keys_return;
  1029 	}
  1030 
  1031 	/* Get the keyboard modifier state */
  1032 	modstate = 0;
  1033 	get_modifier_masks(display);
  1034 	if ( XQueryPointer(display, DefaultRootWindow(display),
  1035 		&junk_window, &junk_window, &x, &y, &x, &y, &mask) ) {
  1036 		if ( mask & LockMask ) {
  1037 			modstate |= KMOD_CAPS;
  1038 		}
  1039 		if ( mask & mode_switch_mask ) {
  1040 			modstate |= KMOD_MODE;
  1041 		}
  1042 		if ( mask & num_mask ) {
  1043 			modstate |= KMOD_NUM;
  1044 		}
  1045 	}
  1046 
  1047 	/* Zero the new keyboard state and generate it */
  1048 	SDL_memset(kstate, 0, SDLK_LAST);
  1049 	/*
  1050 	 * An obvious optimisation is to check entire longwords at a time in
  1051 	 * both loops, but we can't be sure the arrays are aligned so it's not
  1052 	 * worth the extra complexity
  1053 	 */
  1054 	for ( i = 0; i < 32; i++ ) {
  1055 		int j;
  1056 		if ( !key_vec[i] )
  1057 			continue;
  1058 		for ( j = 0; j < 8; j++ ) {
  1059 			if ( key_vec[i] & (1 << j) ) {
  1060 				SDLKey key;
  1061 				KeyCode kc = (i << 3 | j);
  1062 				key = X11_TranslateKeycode(display, kc);
  1063 				if ( key == SDLK_UNKNOWN ) {
  1064 					continue;
  1065 				}
  1066 				kstate[key] = SDL_PRESSED;
  1067 				switch (key) {
  1068 				    case SDLK_LSHIFT:
  1069 					modstate |= KMOD_LSHIFT;
  1070 					break;
  1071 				    case SDLK_RSHIFT:
  1072 					modstate |= KMOD_RSHIFT;
  1073 					break;
  1074 				    case SDLK_LCTRL:
  1075 					modstate |= KMOD_LCTRL;
  1076 					break;
  1077 				    case SDLK_RCTRL:
  1078 					modstate |= KMOD_RCTRL;
  1079 					break;
  1080 				    case SDLK_LALT:
  1081 					modstate |= KMOD_LALT;
  1082 					break;
  1083 				    case SDLK_RALT:
  1084 					modstate |= KMOD_RALT;
  1085 					break;
  1086 				    case SDLK_LMETA:
  1087 					modstate |= KMOD_LMETA;
  1088 					break;
  1089 				    case SDLK_RMETA:
  1090 					modstate |= KMOD_RMETA;
  1091 					break;
  1092 				    default:
  1093 					break;
  1094 				}
  1095 			}
  1096 		}
  1097 	}
  1098 
  1099 	/* Hack - set toggle key state */
  1100 	if ( modstate & KMOD_CAPS ) {
  1101 		kstate[SDLK_CAPSLOCK] = SDL_PRESSED;
  1102 	} else {
  1103 		kstate[SDLK_CAPSLOCK] = SDL_RELEASED;
  1104 	}
  1105 	if ( modstate & KMOD_NUM ) {
  1106 		kstate[SDLK_NUMLOCK] = SDL_PRESSED;
  1107 	} else {
  1108 		kstate[SDLK_NUMLOCK] = SDL_RELEASED;
  1109 	}
  1110 
  1111 	/* Set the final modifier state */
  1112 	SDL_SetModState(modstate);
  1113 }
  1114 
  1115 void X11_InitOSKeymap(_THIS)
  1116 {
  1117 	X11_InitKeymap();
  1118 }
  1119 
  1120 void X11_SaveScreenSaver(Display *display, int *saved_timeout, BOOL *dpms)
  1121 {
  1122 	int timeout, interval, prefer_blank, allow_exp;
  1123 	XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
  1124 	*saved_timeout = timeout;
  1125 
  1126 #if SDL_VIDEO_DRIVER_X11_DPMS
  1127 	if ( SDL_X11_HAVE_DPMS ) {
  1128 		int dummy;
  1129 	  	if ( DPMSQueryExtension(display, &dummy, &dummy) ) {
  1130 			CARD16 state;
  1131 			DPMSInfo(display, &state, dpms);
  1132 		}
  1133 	}
  1134 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
  1135 }
  1136 
  1137 void X11_DisableScreenSaver(Display *display)
  1138 {
  1139 	int timeout, interval, prefer_blank, allow_exp;
  1140 	XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
  1141 	timeout = 0;
  1142 	XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
  1143 
  1144 #if SDL_VIDEO_DRIVER_X11_DPMS
  1145 	if ( SDL_X11_HAVE_DPMS ) {
  1146 		int dummy;
  1147 	  	if ( DPMSQueryExtension(display, &dummy, &dummy) ) {
  1148 			DPMSDisable(display);
  1149 		}
  1150 	}
  1151 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
  1152 }
  1153 
  1154 void X11_RestoreScreenSaver(Display *display, int saved_timeout, BOOL dpms)
  1155 {
  1156 	int timeout, interval, prefer_blank, allow_exp;
  1157 	XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
  1158 	timeout = saved_timeout;
  1159 	XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
  1160 
  1161 #if SDL_VIDEO_DRIVER_X11_DPMS
  1162 	if ( SDL_X11_HAVE_DPMS ) {
  1163 		int dummy;
  1164 	  	if ( DPMSQueryExtension(display, &dummy, &dummy) ) {
  1165 			if ( dpms ) {
  1166 				DPMSEnable(display);
  1167 			}
  1168 		}
  1169 	}
  1170 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
  1171 }