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