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