src/video/x11/SDL_x11mouse.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 19 Feb 2006 23:46:34 +0000
changeset 1379 c0a74f199ecf
parent 1361 19418e4422cb
child 1402 d910939febfa
permissions -rw-r--r--
Use only safe string functions
     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 
    23 #include <X11/Xlib.h>
    24 #include <X11/Xutil.h>
    25 
    26 #include "SDL_mouse.h"
    27 #include "../../events/SDL_events_c.h"
    28 #include "../SDL_cursor_c.h"
    29 #include "SDL_x11dga_c.h"
    30 #include "SDL_x11mouse_c.h"
    31 
    32 
    33 /* The implementation dependent data for the window manager cursor */
    34 struct WMcursor {
    35 	Cursor x_cursor;
    36 };
    37 
    38 
    39 void X11_FreeWMCursor(_THIS, WMcursor *cursor)
    40 {
    41 	if ( SDL_Display != NULL ) {
    42 		SDL_Lock_EventThread();
    43 		pXFreeCursor(SDL_Display, cursor->x_cursor);
    44 		pXSync(SDL_Display, False);
    45 		SDL_Unlock_EventThread();
    46 	}
    47 	SDL_free(cursor);
    48 }
    49 
    50 WMcursor *X11_CreateWMCursor(_THIS,
    51 		Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y)
    52 {
    53 	WMcursor *cursor;
    54 	XGCValues GCvalues;
    55 	GC        GCcursor;
    56 	XImage *data_image, *mask_image;
    57 	Pixmap  data_pixmap, mask_pixmap;
    58 	int       clen, i;
    59 	char     *x_data, *x_mask;
    60 	static XColor black = {  0,  0,  0,  0 };
    61 	static XColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
    62 
    63 	/* Allocate the cursor memory */
    64 	cursor = (WMcursor *)SDL_malloc(sizeof(WMcursor));
    65 	if ( cursor == NULL ) {
    66 		SDL_OutOfMemory();
    67 		return(NULL);
    68 	}
    69 
    70 	/* Mix the mask and the data */
    71 	clen = (w/8)*h;
    72 	x_data = (char *)SDL_malloc(clen);
    73 	if ( x_data == NULL ) {
    74 		SDL_free(cursor);
    75 		SDL_OutOfMemory();
    76 		return(NULL);
    77 	}
    78 	x_mask = (char *)SDL_malloc(clen);
    79 	if ( x_mask == NULL ) {
    80 		SDL_free(cursor);
    81 		SDL_free(x_data);
    82 		SDL_OutOfMemory();
    83 		return(NULL);
    84 	}
    85 	for ( i=0; i<clen; ++i ) {
    86 		/* The mask is OR'd with the data to turn inverted color
    87 		   pixels black since inverted color cursors aren't supported
    88 		   under X11.
    89 		 */
    90 		x_mask[i] = data[i] | mask[i];
    91 		x_data[i] = data[i];
    92 	}
    93 
    94 	/* Prevent the event thread from running while we use the X server */
    95 	SDL_Lock_EventThread();
    96 
    97 	/* Create the data image */
    98 	data_image = pXCreateImage(SDL_Display, 
    99 			DefaultVisual(SDL_Display, SDL_Screen),
   100 					1, XYBitmap, 0, x_data, w, h, 8, w/8);
   101 	data_image->byte_order = MSBFirst;
   102 	data_image->bitmap_bit_order = MSBFirst;
   103 	data_pixmap = pXCreatePixmap(SDL_Display, SDL_Root, w, h, 1);
   104 
   105 	/* Create the data mask */
   106 	mask_image = pXCreateImage(SDL_Display, 
   107 			DefaultVisual(SDL_Display, SDL_Screen),
   108 					1, XYBitmap, 0, x_mask, w, h, 8, w/8);
   109 	mask_image->byte_order = MSBFirst;
   110 	mask_image->bitmap_bit_order = MSBFirst;
   111 	mask_pixmap = pXCreatePixmap(SDL_Display, SDL_Root, w, h, 1);
   112 
   113 	/* Create the graphics context */
   114 	GCvalues.function = GXcopy;
   115 	GCvalues.foreground = ~0;
   116 	GCvalues.background =  0;
   117 	GCvalues.plane_mask = AllPlanes;
   118 	GCcursor = pXCreateGC(SDL_Display, data_pixmap,
   119 			(GCFunction|GCForeground|GCBackground|GCPlaneMask),
   120 								&GCvalues);
   121 
   122 	/* Blit the images to the pixmaps */
   123 	pXPutImage(SDL_Display, data_pixmap, GCcursor, data_image,
   124 							0, 0, 0, 0, w, h);
   125 	pXPutImage(SDL_Display, mask_pixmap, GCcursor, mask_image,
   126 							0, 0, 0, 0, w, h);
   127 	pXFreeGC(SDL_Display, GCcursor);
   128 	/* These free the x_data and x_mask memory pointers */
   129 	pXDestroyImage(data_image);
   130 	pXDestroyImage(mask_image);
   131 
   132 	/* Create the cursor */
   133 	cursor->x_cursor = pXCreatePixmapCursor(SDL_Display, data_pixmap,
   134 				mask_pixmap, &black, &white, hot_x, hot_y);
   135 	pXFreePixmap(SDL_Display, data_pixmap);
   136 	pXFreePixmap(SDL_Display, mask_pixmap);
   137 
   138 	/* Release the event thread */
   139 	pXSync(SDL_Display, False);
   140 	SDL_Unlock_EventThread();
   141 
   142 	return(cursor);
   143 }
   144 
   145 int X11_ShowWMCursor(_THIS, WMcursor *cursor)
   146 {
   147 	/* Don't do anything if the display is gone */
   148 	if ( SDL_Display == NULL ) {
   149 		return(0);
   150 	}
   151 
   152 	/* Set the X11 cursor cursor, or blank if cursor is NULL */
   153 	if ( SDL_Window ) {
   154 		SDL_Lock_EventThread();
   155 		if ( cursor == NULL ) {
   156 			if ( SDL_BlankCursor != NULL ) {
   157 				pXDefineCursor(SDL_Display, SDL_Window,
   158 					SDL_BlankCursor->x_cursor);
   159 			}
   160 		} else {
   161 			pXDefineCursor(SDL_Display, SDL_Window, cursor->x_cursor);
   162 		}
   163 		pXSync(SDL_Display, False);
   164 		SDL_Unlock_EventThread();
   165 	}
   166 	return(1);
   167 }
   168 
   169 void X11_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
   170 {
   171 	if ( using_dga & DGA_MOUSE ) {
   172 		SDL_PrivateMouseMotion(0, 0, x, y);
   173 	} else if ( mouse_relative) {
   174 		/*	RJR: March 28, 2000
   175 			leave physical cursor at center of screen if
   176 			mouse hidden and grabbed */
   177 		SDL_PrivateMouseMotion(0, 0, x, y);
   178 	} else {
   179 		SDL_Lock_EventThread();
   180 		pXWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0, x, y);
   181 		pXSync(SDL_Display, False);
   182 		SDL_Unlock_EventThread();
   183 	}
   184 }
   185 
   186 /* Sets the mouse acceleration from a string of the form:
   187 	2/1/0
   188    The first number is the numerator, followed by the acceleration
   189    denumenator and threshold.
   190 */
   191 static void SetMouseAccel(_THIS, const char *accel_param)
   192 {
   193 	int i;
   194 	size_t len;
   195 	int accel_value[3];
   196 	char *mouse_param, *mouse_param_buf, *pin;
   197 
   198 	len = SDL_strlen(accel_param)+1;
   199 	mouse_param_buf = SDL_stack_alloc(char, len);
   200 	if ( ! mouse_param_buf ) {
   201 		return;
   202 	}
   203 	SDL_strlcpy(mouse_param_buf, accel_param, len);
   204 	mouse_param = mouse_param_buf;
   205 
   206 	for ( i=0; (i < 3) && mouse_param; ++i ) {
   207 		pin = SDL_strchr(mouse_param, '/');
   208 		if ( pin ) {
   209 			*pin = '\0';
   210 		}
   211 		accel_value[i] = atoi(mouse_param);
   212 		if ( pin ) {
   213 			mouse_param = pin+1;
   214 		} else {
   215 			mouse_param = NULL;
   216 		}
   217 	}
   218 	if ( mouse_param_buf ) {
   219 		pXChangePointerControl(SDL_Display, True, True,
   220 			accel_value[0], accel_value[1], accel_value[2]);
   221 		SDL_free(mouse_param_buf);
   222 	}
   223 }
   224 
   225 /* Check to see if we need to enter or leave mouse relative mode */
   226 void X11_CheckMouseModeNoLock(_THIS)
   227 {
   228 	char *env_override;
   229 	int enable_relative = 1;
   230 
   231 	/* Allow the user to override the relative mouse mode.
   232 	   They almost never want to do this, as it seriously affects
   233 	   applications that rely on continuous relative mouse motion.
   234 	*/
   235 	env_override = SDL_getenv("SDL_MOUSE_RELATIVE");
   236 	if ( env_override ) {
   237 		enable_relative = atoi(env_override);
   238 	}
   239 
   240 	/* If the mouse is hidden and input is grabbed, we use relative mode */
   241 	if ( enable_relative &&
   242 	     !(SDL_cursorstate & CURSOR_VISIBLE) &&
   243 	     (this->input_grab != SDL_GRAB_OFF) &&
   244              (SDL_GetAppState() & SDL_APPACTIVE) ) {
   245 		if ( ! mouse_relative ) {
   246 			X11_EnableDGAMouse(this);
   247 			if ( ! (using_dga & DGA_MOUSE) ) {
   248 				char *xmouse_accel;
   249 
   250 				SDL_GetMouseState(&mouse_last.x, &mouse_last.y);
   251 				/* Use as raw mouse mickeys as possible */
   252 				pXGetPointerControl(SDL_Display,
   253 						&mouse_accel.numerator, 
   254 						&mouse_accel.denominator,
   255 						&mouse_accel.threshold);
   256 				xmouse_accel=SDL_getenv("SDL_VIDEO_X11_MOUSEACCEL");
   257 				if ( xmouse_accel ) {
   258 					SetMouseAccel(this, xmouse_accel);
   259 				}
   260 			}
   261 			mouse_relative = 1;
   262 		}
   263 	} else {
   264 		if ( mouse_relative ) {
   265 			if ( using_dga & DGA_MOUSE ) {
   266 				X11_DisableDGAMouse(this);
   267 			} else {
   268 				pXChangePointerControl(SDL_Display, True, True,
   269 						mouse_accel.numerator, 
   270 						mouse_accel.denominator,
   271 						mouse_accel.threshold);
   272 			}
   273 			mouse_relative = 0;
   274 		}
   275 	}
   276 }
   277 void X11_CheckMouseMode(_THIS)
   278 {
   279 	SDL_Lock_EventThread();
   280 	X11_CheckMouseModeNoLock(this);
   281 	SDL_Unlock_EventThread();
   282 }