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