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