This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_x11mouse.c
284 lines (253 loc) · 7.61 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
35
36
37
38
39
40
41
42
43
#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();
44
45
XFreeCursor(SDL_Display, cursor->x_cursor);
XSync(SDL_Display, False);
46
47
SDL_Unlock_EventThread();
}
48
SDL_free(cursor);
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
}
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 */
65
cursor = (WMcursor *)SDL_malloc(sizeof(WMcursor));
66
67
68
69
70
71
72
if ( cursor == NULL ) {
SDL_OutOfMemory();
return(NULL);
}
/* Mix the mask and the data */
clen = (w/8)*h;
73
x_data = (char *)SDL_malloc(clen);
74
if ( x_data == NULL ) {
75
SDL_free(cursor);
76
77
78
SDL_OutOfMemory();
return(NULL);
}
79
x_mask = (char *)SDL_malloc(clen);
80
if ( x_mask == NULL ) {
81
82
SDL_free(cursor);
SDL_free(x_data);
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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 */
99
data_image = XCreateImage(SDL_Display,
100
101
102
103
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;
104
data_pixmap = XCreatePixmap(SDL_Display, SDL_Root, w, h, 1);
105
106
/* Create the data mask */
107
mask_image = XCreateImage(SDL_Display,
108
109
110
111
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;
112
mask_pixmap = XCreatePixmap(SDL_Display, SDL_Root, w, h, 1);
113
114
115
116
117
118
/* Create the graphics context */
GCvalues.function = GXcopy;
GCvalues.foreground = ~0;
GCvalues.background = 0;
GCvalues.plane_mask = AllPlanes;
119
GCcursor = XCreateGC(SDL_Display, data_pixmap,
120
121
122
123
(GCFunction|GCForeground|GCBackground|GCPlaneMask),
&GCvalues);
/* 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
131
XDestroyImage(data_image);
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
137
XFreePixmap(SDL_Display, data_pixmap);
XFreePixmap(SDL_Display, mask_pixmap);
138
139
/* Release the event thread */
140
XSync(SDL_Display, False);
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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 ) {
158
XDefineCursor(SDL_Display, SDL_Window,
159
160
161
SDL_BlankCursor->x_cursor);
}
} else {
162
XDefineCursor(SDL_Display, SDL_Window, cursor->x_cursor);
163
}
164
XSync(SDL_Display, False);
165
166
167
168
169
170
171
172
SDL_Unlock_EventThread();
}
return(1);
}
void X11_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
{
if ( using_dga & DGA_MOUSE ) {
173
174
175
176
177
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 */
178
179
180
SDL_PrivateMouseMotion(0, 0, x, y);
} else {
SDL_Lock_EventThread();
181
182
XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0, x, y);
XSync(SDL_Display, False);
183
184
185
186
187
188
189
190
191
192
193
194
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;
195
size_t len;
196
197
198
int accel_value[3];
char *mouse_param, *mouse_param_buf, *pin;
199
200
len = SDL_strlen(accel_param)+1;
mouse_param_buf = SDL_stack_alloc(char, len);
201
202
203
if ( ! mouse_param_buf ) {
return;
}
204
SDL_strlcpy(mouse_param_buf, accel_param, len);
205
206
207
mouse_param = mouse_param_buf;
for ( i=0; (i < 3) && mouse_param; ++i ) {
208
pin = SDL_strchr(mouse_param, '/');
209
210
211
212
213
214
215
216
217
218
219
if ( pin ) {
*pin = '\0';
}
accel_value[i] = atoi(mouse_param);
if ( pin ) {
mouse_param = pin+1;
} else {
mouse_param = NULL;
}
}
if ( mouse_param_buf ) {
220
XChangePointerControl(SDL_Display, True, True,
221
accel_value[0], accel_value[1], accel_value[2]);
222
SDL_free(mouse_param_buf);
223
224
225
226
227
228
}
}
/* Check to see if we need to enter or leave mouse relative mode */
void X11_CheckMouseModeNoLock(_THIS)
{
229
const Uint8 full_focus = (SDL_APPACTIVE|SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS);
230
231
232
233
234
235
236
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.
*/
237
env_override = SDL_getenv("SDL_MOUSE_RELATIVE");
238
239
240
241
if ( env_override ) {
enable_relative = atoi(env_override);
}
242
/* If the mouse is hidden and input is grabbed, we use relative mode */
243
244
if ( enable_relative &&
!(SDL_cursorstate & CURSOR_VISIBLE) &&
245
(this->input_grab != SDL_GRAB_OFF) &&
246
(SDL_GetAppState() & full_focus) == full_focus ) {
247
248
249
250
251
252
253
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 */
254
XGetPointerControl(SDL_Display,
255
256
257
&mouse_accel.numerator,
&mouse_accel.denominator,
&mouse_accel.threshold);
258
xmouse_accel=SDL_getenv("SDL_VIDEO_X11_MOUSEACCEL");
259
260
261
262
263
264
265
266
267
268
269
if ( xmouse_accel ) {
SetMouseAccel(this, xmouse_accel);
}
}
mouse_relative = 1;
}
} else {
if ( mouse_relative ) {
if ( using_dga & DGA_MOUSE ) {
X11_DisableDGAMouse(this);
} else {
270
XChangePointerControl(SDL_Display, True, True,
271
272
273
274
275
276
277
278
279
280
281
282
283
284
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();
}