Merge lp:~brandontschaefer/libsdl/add-mir-support-v2 into lp:libsdl
- add-mir-support-v2
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~brandontschaefer/libsdl/add-mir-support-v2 |
Merge into: | lp:libsdl |
Diff against target: | 458056 lines |
To merge this branch: | bzr merge lp:~brandontschaefer/libsdl/add-mir-support-v2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
VCS imports | Pending | ||
Review via email: mp+260771@code.launchpad.net |
This proposal has been superseded by a proposal from 2015-06-01.
Commit message
Add support for Mir under libsdl1.2 for only i386/amd64 (no gles1/2 support in libsdl1.2).
Description of the change
Add support for Mir under libsdl1.2 for only i386/amd64 (no gles1/2 support in libsdl1.2).
This patch adds support for Software rendering and Opengl on the desktop for mir in sdl1.2.
*Note* This is written for the new libmir 0.13.1. This uses new event 2.0 and buffering system.
- 53. By Brandon Schaefer
-
* I should not ignore key_repeat rather, if we are not a KEY_UP action
assume its a KEY_DOWN event.
Unmerged revisions
- 53. By Brandon Schaefer
-
* I should not ignore key_repeat rather, if we are not a KEY_UP action
assume its a KEY_DOWN event. - 52. By Brandon Schaefer
-
* Make sure we depend on the version of mir this is written for
- 51. By Brandon Schaefer
-
* Add video driver backend support for Mir (i386/amd64)
- 50. By Steve Langasek
-
* Merge from Debian unstable, remaining changes:
- Drop directfb support. This is the only package which still pulls the
rather sizable directfb into a standard installation, and we never
actually used/supported it anyway.
* Dropped changes, included in Debian:
- Drop tslib support which is in universe.
- debian/patches/ sdl-check- for-SDL_ VIDEO_X11_ BACKINGSTORE. patch:
Restore old backingstore behavior to prevent tearing. - 49. By Steve Langasek
-
* Restore accidentally-
clobbered changes from 1.2.15-8ubuntu2. [ Timo Jyrinki ]
* debian/patches/ sdl-check- for-SDL_ VIDEO_X11_ BACKINGSTORE. patch:
- Restore old backingstore behavior to prevent tearing
(LP: #1280665) - 48. By Steve Langasek
-
* Merge from Debian unstable, remaining changes:
- Drop directfb support. This is the only package which still pulls the
rather sizable directfb into a standard installation, and we never
actually used/supported it anyway.
- Drop tslib support which is in universe.
* Dropped changes, included in Debian:
- fix dh_autoreconf handling. - 47. By Timo Jyrinki
-
* debian/
patches/ sdl-check- for-SDL_ VIDEO_X11_ BACKINGSTORE. patch:
- Restore old backingstore behavior to prevent tearing
(LP: #1280665) - 46. By Steve Langasek
-
* Merge from Debian unstable, remaining changes:
- Drop directfb support. This is the only package which still pulls the
rather sizable directfb into a standard installation, and we never
actually used/supported it anyway.
--enable-video-directfb from confflags.
- Drop tslib support which is in universe.
- debian/rules, debian/patches/ proper- autotools. patch: Fix wrong
handling of dh_autoreconf that fails to ever re-libtoolize the
package. Bypass calling autoheader, since configure.in isn't
compatible with current version of autoheader.
* Dropped changes, merged in Debian:
- drop the unused libsdl1.2debian- udeb package
- Use dh_autotools-dev to update config.{sub,guess} for new ports. - 45. By Steve Langasek
-
debian/rules, debian/
patches/ proper- autotools. patch: Fix wrong handling
of dh_autoreconf that fails to ever re-libtoolize the package. Bypass
calling autoheader, since configure.in isn't compatible with current
version of autoheader. - 44. By Steve Langasek
-
releasing package libsdl1.2 version 1.2.15-5ubuntu3
Preview Diff
1 | === added directory '.pc' |
2 | === added file '.pc/.quilt_patches' |
3 | --- .pc/.quilt_patches 1970-01-01 00:00:00 +0000 |
4 | +++ .pc/.quilt_patches 2015-06-01 21:40:05 +0000 |
5 | @@ -0,0 +1,1 @@ |
6 | +debian/patches |
7 | |
8 | === added file '.pc/.quilt_series' |
9 | --- .pc/.quilt_series 1970-01-01 00:00:00 +0000 |
10 | +++ .pc/.quilt_series 2015-06-01 21:40:05 +0000 |
11 | @@ -0,0 +1,1 @@ |
12 | +series |
13 | |
14 | === added file '.pc/.version' |
15 | --- .pc/.version 1970-01-01 00:00:00 +0000 |
16 | +++ .pc/.version 2015-06-01 21:40:05 +0000 |
17 | @@ -0,0 +1,1 @@ |
18 | +2 |
19 | |
20 | === added file '.pc/applied-patches' |
21 | --- .pc/applied-patches 1970-01-01 00:00:00 +0000 |
22 | +++ .pc/applied-patches 2015-06-01 21:40:05 +0000 |
23 | @@ -0,0 +1,7 @@ |
24 | +x11_keytounicode.diff |
25 | +dont_propagate_lpthread.diff |
26 | +fix_build_joystick_freebsd.diff |
27 | +fix_window_resizing.diff |
28 | +fix_joystick_misc_axes.diff |
29 | +sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch |
30 | +mir-support.diff |
31 | |
32 | === added directory '.pc/dont_propagate_lpthread.diff' |
33 | === added file '.pc/dont_propagate_lpthread.diff/sdl-config.in' |
34 | --- .pc/dont_propagate_lpthread.diff/sdl-config.in 1970-01-01 00:00:00 +0000 |
35 | +++ .pc/dont_propagate_lpthread.diff/sdl-config.in 2015-06-01 21:40:05 +0000 |
36 | @@ -0,0 +1,60 @@ |
37 | +#!/bin/sh |
38 | + |
39 | +prefix=@prefix@ |
40 | +exec_prefix=@exec_prefix@ |
41 | +exec_prefix_set=no |
42 | +libdir=@libdir@ |
43 | + |
44 | +@ENABLE_STATIC_FALSE@usage="\ |
45 | +@ENABLE_STATIC_FALSE@Usage: sdl-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--cflags] [--libs]" |
46 | +@ENABLE_STATIC_TRUE@usage="\ |
47 | +@ENABLE_STATIC_TRUE@Usage: sdl-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--cflags] [--libs] [--static-libs]" |
48 | + |
49 | +if test $# -eq 0; then |
50 | + echo "${usage}" 1>&2 |
51 | + exit 1 |
52 | +fi |
53 | + |
54 | +while test $# -gt 0; do |
55 | + case "$1" in |
56 | + -*=*) optarg=`echo "$1" | LC_ALL="C" sed 's/[-_a-zA-Z0-9]*=//'` ;; |
57 | + *) optarg= ;; |
58 | + esac |
59 | + |
60 | + case $1 in |
61 | + --prefix=*) |
62 | + prefix=$optarg |
63 | + if test $exec_prefix_set = no ; then |
64 | + exec_prefix=$optarg |
65 | + fi |
66 | + ;; |
67 | + --prefix) |
68 | + echo $prefix |
69 | + ;; |
70 | + --exec-prefix=*) |
71 | + exec_prefix=$optarg |
72 | + exec_prefix_set=yes |
73 | + ;; |
74 | + --exec-prefix) |
75 | + echo $exec_prefix |
76 | + ;; |
77 | + --version) |
78 | + echo @SDL_VERSION@ |
79 | + ;; |
80 | + --cflags) |
81 | + echo -I@includedir@/SDL @SDL_CFLAGS@ |
82 | + ;; |
83 | +@ENABLE_SHARED_TRUE@ --libs) |
84 | +@ENABLE_SHARED_TRUE@ echo -L@libdir@ @SDL_RLD_FLAGS@ @SDL_LIBS@ |
85 | +@ENABLE_SHARED_TRUE@ ;; |
86 | +@ENABLE_STATIC_TRUE@@ENABLE_SHARED_TRUE@ --static-libs) |
87 | +@ENABLE_STATIC_TRUE@@ENABLE_SHARED_FALSE@ --libs|--static-libs) |
88 | +@ENABLE_STATIC_TRUE@ echo -L@libdir@ @SDL_RLD_FLAGS@ @SDL_STATIC_LIBS@ |
89 | +@ENABLE_STATIC_TRUE@ ;; |
90 | + *) |
91 | + echo "${usage}" 1>&2 |
92 | + exit 1 |
93 | + ;; |
94 | + esac |
95 | + shift |
96 | +done |
97 | |
98 | === added file '.pc/dont_propagate_lpthread.diff/sdl.pc.in' |
99 | --- .pc/dont_propagate_lpthread.diff/sdl.pc.in 1970-01-01 00:00:00 +0000 |
100 | +++ .pc/dont_propagate_lpthread.diff/sdl.pc.in 2015-06-01 21:40:05 +0000 |
101 | @@ -0,0 +1,15 @@ |
102 | +# sdl pkg-config source file |
103 | + |
104 | +prefix=@prefix@ |
105 | +exec_prefix=@exec_prefix@ |
106 | +libdir=@libdir@ |
107 | +includedir=@includedir@ |
108 | + |
109 | +Name: sdl |
110 | +Description: Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer. |
111 | +Version: @SDL_VERSION@ |
112 | +Requires: |
113 | +Conflicts: |
114 | +Libs: -L${libdir} @SDL_RLD_FLAGS@ @SDL_LIBS@ |
115 | +Libs.private: @SDL_STATIC_LIBS@ |
116 | +Cflags: -I${includedir}/SDL @SDL_CFLAGS@ |
117 | |
118 | === added directory '.pc/fix_build_joystick_freebsd.diff' |
119 | === added directory '.pc/fix_build_joystick_freebsd.diff/src' |
120 | === added directory '.pc/fix_build_joystick_freebsd.diff/src/joystick' |
121 | === added directory '.pc/fix_build_joystick_freebsd.diff/src/joystick/bsd' |
122 | === added file '.pc/fix_build_joystick_freebsd.diff/src/joystick/bsd/SDL_sysjoystick.c' |
123 | --- .pc/fix_build_joystick_freebsd.diff/src/joystick/bsd/SDL_sysjoystick.c 1970-01-01 00:00:00 +0000 |
124 | +++ .pc/fix_build_joystick_freebsd.diff/src/joystick/bsd/SDL_sysjoystick.c 2015-06-01 21:40:05 +0000 |
125 | @@ -0,0 +1,608 @@ |
126 | +/* |
127 | + SDL - Simple DirectMedia Layer |
128 | + Copyright (C) 1997-2012 Sam Lantinga |
129 | + |
130 | + This library is free software; you can redistribute it and/or |
131 | + modify it under the terms of the GNU Lesser General Public |
132 | + License as published by the Free Software Foundation; either |
133 | + version 2.1 of the License, or (at your option) any later version. |
134 | + |
135 | + This library is distributed in the hope that it will be useful, |
136 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
137 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
138 | + Lesser General Public License for more details. |
139 | + |
140 | + You should have received a copy of the GNU Lesser General Public |
141 | + License along with this library; if not, write to the Free Software |
142 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
143 | + |
144 | + Sam Lantinga |
145 | + slouken@libsdl.org |
146 | +*/ |
147 | +#include "SDL_config.h" |
148 | + |
149 | +#ifdef SDL_JOYSTICK_USBHID |
150 | + |
151 | +/* |
152 | + * Joystick driver for the uhid(4) interface found in OpenBSD, |
153 | + * NetBSD and FreeBSD. |
154 | + * |
155 | + * Maintainer: <vedge at csoft.org> |
156 | + */ |
157 | + |
158 | +#include <sys/param.h> |
159 | + |
160 | +#include <unistd.h> |
161 | +#include <fcntl.h> |
162 | +#include <errno.h> |
163 | + |
164 | +#ifndef __FreeBSD_kernel_version |
165 | +#define __FreeBSD_kernel_version __FreeBSD_version |
166 | +#endif |
167 | + |
168 | +#if defined(HAVE_USB_H) |
169 | +#include <usb.h> |
170 | +#endif |
171 | +#ifdef __DragonFly__ |
172 | +#include <bus/usb/usb.h> |
173 | +#include <bus/usb/usbhid.h> |
174 | +#else |
175 | +#include <dev/usb/usb.h> |
176 | +#include <dev/usb/usbhid.h> |
177 | +#endif |
178 | + |
179 | +#if defined(HAVE_USBHID_H) |
180 | +#include <usbhid.h> |
181 | +#elif defined(HAVE_LIBUSB_H) |
182 | +#include <libusb.h> |
183 | +#elif defined(HAVE_LIBUSBHID_H) |
184 | +#include <libusbhid.h> |
185 | +#endif |
186 | + |
187 | +#if defined(__FREEBSD__) || defined(__FreeBSD_kernel__) |
188 | +#ifndef __DragonFly__ |
189 | +#include <osreldate.h> |
190 | +#endif |
191 | +#if __FreeBSD_kernel_version > 800063 |
192 | +#include <dev/usb/usb_ioctl.h> |
193 | +#endif |
194 | +#include <sys/joystick.h> |
195 | +#endif |
196 | + |
197 | +#if SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H |
198 | +#include <machine/joystick.h> |
199 | +#endif |
200 | + |
201 | +#include "SDL_joystick.h" |
202 | +#include "../SDL_sysjoystick.h" |
203 | +#include "../SDL_joystick_c.h" |
204 | + |
205 | +#define MAX_UHID_JOYS 4 |
206 | +#define MAX_JOY_JOYS 2 |
207 | +#define MAX_JOYS (MAX_UHID_JOYS + MAX_JOY_JOYS) |
208 | + |
209 | +struct report { |
210 | +#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) |
211 | + struct usb_gen_descriptor *buf; /* Buffer */ |
212 | +#else |
213 | + struct usb_ctl_report *buf; /* Buffer */ |
214 | +#endif |
215 | + size_t size; /* Buffer size */ |
216 | + int rid; /* Report ID */ |
217 | + enum { |
218 | + SREPORT_UNINIT, |
219 | + SREPORT_CLEAN, |
220 | + SREPORT_DIRTY |
221 | + } status; |
222 | +}; |
223 | + |
224 | +static struct { |
225 | + int uhid_report; |
226 | + hid_kind_t kind; |
227 | + const char *name; |
228 | +} const repinfo[] = { |
229 | + { UHID_INPUT_REPORT, hid_input, "input" }, |
230 | + { UHID_OUTPUT_REPORT, hid_output, "output" }, |
231 | + { UHID_FEATURE_REPORT, hid_feature, "feature" } |
232 | +}; |
233 | + |
234 | +enum { |
235 | + REPORT_INPUT = 0, |
236 | + REPORT_OUTPUT = 1, |
237 | + REPORT_FEATURE = 2 |
238 | +}; |
239 | + |
240 | +enum { |
241 | + JOYAXE_X, |
242 | + JOYAXE_Y, |
243 | + JOYAXE_Z, |
244 | + JOYAXE_SLIDER, |
245 | + JOYAXE_WHEEL, |
246 | + JOYAXE_RX, |
247 | + JOYAXE_RY, |
248 | + JOYAXE_RZ, |
249 | + JOYAXE_count |
250 | +}; |
251 | + |
252 | +struct joystick_hwdata { |
253 | + int fd; |
254 | + char *path; |
255 | + enum { |
256 | + BSDJOY_UHID, /* uhid(4) */ |
257 | + BSDJOY_JOY /* joy(4) */ |
258 | + } type; |
259 | + struct report_desc *repdesc; |
260 | + struct report inreport; |
261 | + int axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,..*/ |
262 | + int x; |
263 | + int y; |
264 | + int xmin; |
265 | + int ymin; |
266 | + int xmax; |
267 | + int ymax; |
268 | +}; |
269 | + |
270 | +static char *joynames[MAX_JOYS]; |
271 | +static char *joydevnames[MAX_JOYS]; |
272 | + |
273 | +static int report_alloc(struct report *, struct report_desc *, int); |
274 | +static void report_free(struct report *); |
275 | + |
276 | +#if defined(USBHID_UCR_DATA) || defined(__FreeBSD_kernel__) |
277 | +#define REP_BUF_DATA(rep) ((rep)->buf->ucr_data) |
278 | +#elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)) |
279 | +#define REP_BUF_DATA(rep) ((rep)->buf->ugd_data) |
280 | +#else |
281 | +#define REP_BUF_DATA(rep) ((rep)->buf->data) |
282 | +#endif |
283 | + |
284 | +int |
285 | +SDL_SYS_JoystickInit(void) |
286 | +{ |
287 | + char s[16]; |
288 | + int i, fd; |
289 | + |
290 | + SDL_numjoysticks = 0; |
291 | + |
292 | + SDL_memset(joynames, 0, sizeof(joynames)); |
293 | + SDL_memset(joydevnames, 0, sizeof(joydevnames)); |
294 | + |
295 | + for (i = 0; i < MAX_UHID_JOYS; i++) { |
296 | + SDL_Joystick nj; |
297 | + |
298 | + SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i); |
299 | + |
300 | + nj.index = SDL_numjoysticks; |
301 | + joynames[nj.index] = strdup(s); |
302 | + |
303 | + if (SDL_SYS_JoystickOpen(&nj) == 0) { |
304 | + SDL_SYS_JoystickClose(&nj); |
305 | + SDL_numjoysticks++; |
306 | + } else { |
307 | + SDL_free(joynames[nj.index]); |
308 | + joynames[nj.index] = NULL; |
309 | + } |
310 | + } |
311 | + for (i = 0; i < MAX_JOY_JOYS; i++) { |
312 | + SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i); |
313 | + fd = open(s, O_RDONLY); |
314 | + if (fd != -1) { |
315 | + joynames[SDL_numjoysticks++] = strdup(s); |
316 | + close(fd); |
317 | + } |
318 | + } |
319 | + |
320 | + /* Read the default USB HID usage table. */ |
321 | + hid_init(NULL); |
322 | + |
323 | + return (SDL_numjoysticks); |
324 | +} |
325 | + |
326 | +const char * |
327 | +SDL_SYS_JoystickName(int index) |
328 | +{ |
329 | + if (joydevnames[index] != NULL) { |
330 | + return (joydevnames[index]); |
331 | + } |
332 | + return (joynames[index]); |
333 | +} |
334 | + |
335 | +static int |
336 | +usage_to_joyaxe(unsigned usage) |
337 | +{ |
338 | + int joyaxe; |
339 | + switch (usage) { |
340 | + case HUG_X: |
341 | + joyaxe = JOYAXE_X; break; |
342 | + case HUG_Y: |
343 | + joyaxe = JOYAXE_Y; break; |
344 | + case HUG_Z: |
345 | + joyaxe = JOYAXE_Z; break; |
346 | + case HUG_SLIDER: |
347 | + joyaxe = JOYAXE_SLIDER; break; |
348 | + case HUG_WHEEL: |
349 | + joyaxe = JOYAXE_WHEEL; break; |
350 | + case HUG_RX: |
351 | + joyaxe = JOYAXE_RX; break; |
352 | + case HUG_RY: |
353 | + joyaxe = JOYAXE_RY; break; |
354 | + case HUG_RZ: |
355 | + joyaxe = JOYAXE_RZ; break; |
356 | + default: |
357 | + joyaxe = -1; |
358 | + } |
359 | + return joyaxe; |
360 | +} |
361 | + |
362 | +static unsigned |
363 | +hatval_to_sdl(Sint32 hatval) |
364 | +{ |
365 | + static const unsigned hat_dir_map[8] = { |
366 | + SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN, |
367 | + SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP |
368 | + }; |
369 | + unsigned result; |
370 | + if ((hatval & 7) == hatval) |
371 | + result = hat_dir_map[hatval]; |
372 | + else |
373 | + result = SDL_HAT_CENTERED; |
374 | + return result; |
375 | +} |
376 | + |
377 | + |
378 | +int |
379 | +SDL_SYS_JoystickOpen(SDL_Joystick *joy) |
380 | +{ |
381 | + char *path = joynames[joy->index]; |
382 | + struct joystick_hwdata *hw; |
383 | + struct hid_item hitem; |
384 | + struct hid_data *hdata; |
385 | + struct report *rep; |
386 | + int fd; |
387 | + int i; |
388 | + |
389 | + fd = open(path, O_RDONLY); |
390 | + if (fd == -1) { |
391 | + SDL_SetError("%s: %s", path, strerror(errno)); |
392 | + return (-1); |
393 | + } |
394 | + |
395 | + hw = (struct joystick_hwdata *)SDL_malloc(sizeof(struct joystick_hwdata)); |
396 | + if (hw == NULL) { |
397 | + SDL_OutOfMemory(); |
398 | + close(fd); |
399 | + return (-1); |
400 | + } |
401 | + joy->hwdata = hw; |
402 | + hw->fd = fd; |
403 | + hw->path = strdup(path); |
404 | + hw->x = 0; |
405 | + hw->y = 0; |
406 | + hw->xmin = 0xffff; |
407 | + hw->ymin = 0xffff; |
408 | + hw->xmax = 0; |
409 | + hw->ymax = 0; |
410 | + if (! SDL_strncmp(path, "/dev/joy", 8)) { |
411 | + hw->type = BSDJOY_JOY; |
412 | + joy->naxes = 2; |
413 | + joy->nbuttons = 2; |
414 | + joy->nhats = 0; |
415 | + joy->nballs = 0; |
416 | + joydevnames[joy->index] = strdup("Gameport joystick"); |
417 | + goto usbend; |
418 | + } else { |
419 | + hw->type = BSDJOY_UHID; |
420 | + } |
421 | + |
422 | + { |
423 | + int ax; |
424 | + for (ax = 0; ax < JOYAXE_count; ax++) |
425 | + hw->axis_map[ax] = -1; |
426 | + } |
427 | + hw->repdesc = hid_get_report_desc(fd); |
428 | + if (hw->repdesc == NULL) { |
429 | + SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path, |
430 | + strerror(errno)); |
431 | + goto usberr; |
432 | + } |
433 | + rep = &hw->inreport; |
434 | +#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__) |
435 | + rep->rid = hid_get_report_id(fd); |
436 | + if (rep->rid < 0) { |
437 | +#else |
438 | + if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) { |
439 | +#endif |
440 | + rep->rid = -1; /* XXX */ |
441 | + } |
442 | + if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) { |
443 | + goto usberr; |
444 | + } |
445 | + if (rep->size <= 0) { |
446 | + SDL_SetError("%s: Input report descriptor has invalid length", |
447 | + hw->path); |
448 | + goto usberr; |
449 | + } |
450 | + |
451 | +#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__) |
452 | + hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid); |
453 | +#else |
454 | + hdata = hid_start_parse(hw->repdesc, 1 << hid_input); |
455 | +#endif |
456 | + if (hdata == NULL) { |
457 | + SDL_SetError("%s: Cannot start HID parser", hw->path); |
458 | + goto usberr; |
459 | + } |
460 | + joy->naxes = 0; |
461 | + joy->nbuttons = 0; |
462 | + joy->nhats = 0; |
463 | + joy->nballs = 0; |
464 | + for (i=0; i<JOYAXE_count; i++) |
465 | + hw->axis_map[i] = -1; |
466 | + |
467 | + while (hid_get_item(hdata, &hitem) > 0) { |
468 | + char *sp; |
469 | + const char *s; |
470 | + |
471 | + switch (hitem.kind) { |
472 | + case hid_collection: |
473 | + switch (HID_PAGE(hitem.usage)) { |
474 | + case HUP_GENERIC_DESKTOP: |
475 | + switch (HID_USAGE(hitem.usage)) { |
476 | + case HUG_JOYSTICK: |
477 | + case HUG_GAME_PAD: |
478 | + s = hid_usage_in_page(hitem.usage); |
479 | + sp = SDL_malloc(SDL_strlen(s) + 5); |
480 | + SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)", s, |
481 | + joy->index); |
482 | + joydevnames[joy->index] = sp; |
483 | + } |
484 | + } |
485 | + break; |
486 | + case hid_input: |
487 | + switch (HID_PAGE(hitem.usage)) { |
488 | + case HUP_GENERIC_DESKTOP: { |
489 | + unsigned usage = HID_USAGE(hitem.usage); |
490 | + int joyaxe = usage_to_joyaxe(usage); |
491 | + if (joyaxe >= 0) { |
492 | + hw->axis_map[joyaxe] = 1; |
493 | + } else if (usage == HUG_HAT_SWITCH) { |
494 | + joy->nhats++; |
495 | + } |
496 | + break; |
497 | + } |
498 | + case HUP_BUTTON: |
499 | + joy->nbuttons++; |
500 | + break; |
501 | + default: |
502 | + break; |
503 | + } |
504 | + break; |
505 | + default: |
506 | + break; |
507 | + } |
508 | + } |
509 | + hid_end_parse(hdata); |
510 | + for (i=0; i<JOYAXE_count; i++) |
511 | + if (hw->axis_map[i] > 0) |
512 | + hw->axis_map[i] = joy->naxes++; |
513 | + |
514 | +usbend: |
515 | + /* The poll blocks the event thread. */ |
516 | + fcntl(fd, F_SETFL, O_NONBLOCK); |
517 | + |
518 | + return (0); |
519 | +usberr: |
520 | + close(hw->fd); |
521 | + SDL_free(hw->path); |
522 | + SDL_free(hw); |
523 | + return (-1); |
524 | +} |
525 | + |
526 | +void |
527 | +SDL_SYS_JoystickUpdate(SDL_Joystick *joy) |
528 | +{ |
529 | + struct hid_item hitem; |
530 | + struct hid_data *hdata; |
531 | + struct report *rep; |
532 | + int nbutton, naxe = -1; |
533 | + Sint32 v; |
534 | + |
535 | +#if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__) |
536 | + struct joystick gameport; |
537 | + |
538 | + if (joy->hwdata->type == BSDJOY_JOY) { |
539 | + if (read(joy->hwdata->fd, &gameport, sizeof gameport) != sizeof gameport) |
540 | + return; |
541 | + if (abs(joy->hwdata->x - gameport.x) > 8) { |
542 | + joy->hwdata->x = gameport.x; |
543 | + if (joy->hwdata->x < joy->hwdata->xmin) { |
544 | + joy->hwdata->xmin = joy->hwdata->x; |
545 | + } |
546 | + if (joy->hwdata->x > joy->hwdata->xmax) { |
547 | + joy->hwdata->xmax = joy->hwdata->x; |
548 | + } |
549 | + if (joy->hwdata->xmin == joy->hwdata->xmax) { |
550 | + joy->hwdata->xmin--; |
551 | + joy->hwdata->xmax++; |
552 | + } |
553 | + v = (Sint32)joy->hwdata->x; |
554 | + v -= (joy->hwdata->xmax + joy->hwdata->xmin + 1)/2; |
555 | + v *= 32768/((joy->hwdata->xmax - joy->hwdata->xmin + 1)/2); |
556 | + SDL_PrivateJoystickAxis(joy, 0, v); |
557 | + } |
558 | + if (abs(joy->hwdata->y - gameport.y) > 8) { |
559 | + joy->hwdata->y = gameport.y; |
560 | + if (joy->hwdata->y < joy->hwdata->ymin) { |
561 | + joy->hwdata->ymin = joy->hwdata->y; |
562 | + } |
563 | + if (joy->hwdata->y > joy->hwdata->ymax) { |
564 | + joy->hwdata->ymax = joy->hwdata->y; |
565 | + } |
566 | + if (joy->hwdata->ymin == joy->hwdata->ymax) { |
567 | + joy->hwdata->ymin--; |
568 | + joy->hwdata->ymax++; |
569 | + } |
570 | + v = (Sint32)joy->hwdata->y; |
571 | + v -= (joy->hwdata->ymax + joy->hwdata->ymin + 1)/2; |
572 | + v *= 32768/((joy->hwdata->ymax - joy->hwdata->ymin + 1)/2); |
573 | + SDL_PrivateJoystickAxis(joy, 1, v); |
574 | + } |
575 | + if (gameport.b1 != joy->buttons[0]) { |
576 | + SDL_PrivateJoystickButton(joy, 0, gameport.b1); |
577 | + } |
578 | + if (gameport.b2 != joy->buttons[1]) { |
579 | + SDL_PrivateJoystickButton(joy, 1, gameport.b2); |
580 | + } |
581 | + return; |
582 | + } |
583 | +#endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */ |
584 | + |
585 | + rep = &joy->hwdata->inreport; |
586 | + |
587 | + if (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) != rep->size) { |
588 | + return; |
589 | + } |
590 | +#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__) |
591 | + hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid); |
592 | +#else |
593 | + hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input); |
594 | +#endif |
595 | + if (hdata == NULL) { |
596 | + fprintf(stderr, "%s: Cannot start HID parser\n", |
597 | + joy->hwdata->path); |
598 | + return; |
599 | + } |
600 | + |
601 | + for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) { |
602 | + switch (hitem.kind) { |
603 | + case hid_input: |
604 | + switch (HID_PAGE(hitem.usage)) { |
605 | + case HUP_GENERIC_DESKTOP: { |
606 | + unsigned usage = HID_USAGE(hitem.usage); |
607 | + int joyaxe = usage_to_joyaxe(usage); |
608 | + if (joyaxe >= 0) { |
609 | + naxe = joy->hwdata->axis_map[joyaxe]; |
610 | + /* scaleaxe */ |
611 | + v = (Sint32)hid_get_data(REP_BUF_DATA(rep), |
612 | + &hitem); |
613 | + v -= (hitem.logical_maximum + hitem.logical_minimum + 1)/2; |
614 | + v *= 32768/((hitem.logical_maximum - hitem.logical_minimum + 1)/2); |
615 | + if (v != joy->axes[naxe]) { |
616 | + SDL_PrivateJoystickAxis(joy, naxe, v); |
617 | + } |
618 | + } else if (usage == HUG_HAT_SWITCH) { |
619 | + v = (Sint32)hid_get_data(REP_BUF_DATA(rep), |
620 | + &hitem); |
621 | + SDL_PrivateJoystickHat(joy, 0, |
622 | + hatval_to_sdl(v)-hitem.logical_minimum); |
623 | + } |
624 | + break; |
625 | + } |
626 | + case HUP_BUTTON: |
627 | + v = (Sint32)hid_get_data(REP_BUF_DATA(rep), |
628 | + &hitem); |
629 | + if (joy->buttons[nbutton] != v) { |
630 | + SDL_PrivateJoystickButton(joy, |
631 | + nbutton, v); |
632 | + } |
633 | + nbutton++; |
634 | + break; |
635 | + default: |
636 | + continue; |
637 | + } |
638 | + break; |
639 | + default: |
640 | + break; |
641 | + } |
642 | + } |
643 | + hid_end_parse(hdata); |
644 | + |
645 | + return; |
646 | +} |
647 | + |
648 | +/* Function to close a joystick after use */ |
649 | +void |
650 | +SDL_SYS_JoystickClose(SDL_Joystick *joy) |
651 | +{ |
652 | + if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) { |
653 | + report_free(&joy->hwdata->inreport); |
654 | + hid_dispose_report_desc(joy->hwdata->repdesc); |
655 | + } |
656 | + close(joy->hwdata->fd); |
657 | + SDL_free(joy->hwdata->path); |
658 | + SDL_free(joy->hwdata); |
659 | + |
660 | + return; |
661 | +} |
662 | + |
663 | +void |
664 | +SDL_SYS_JoystickQuit(void) |
665 | +{ |
666 | + int i; |
667 | + |
668 | + for (i = 0; i < MAX_JOYS; i++) { |
669 | + if (joynames[i] != NULL) |
670 | + SDL_free(joynames[i]); |
671 | + if (joydevnames[i] != NULL) |
672 | + SDL_free(joydevnames[i]); |
673 | + } |
674 | + |
675 | + return; |
676 | +} |
677 | + |
678 | +static int |
679 | +report_alloc(struct report *r, struct report_desc *rd, int repind) |
680 | +{ |
681 | + int len; |
682 | + |
683 | +#ifdef __DragonFly__ |
684 | + len = hid_report_size(rd, r->rid, repinfo[repind].kind); |
685 | +#elif __FREEBSD__ |
686 | +# if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__) |
687 | +# if (__FreeBSD_kernel_version <= 500111) |
688 | + len = hid_report_size(rd, r->rid, repinfo[repind].kind); |
689 | +# else |
690 | + len = hid_report_size(rd, repinfo[repind].kind, r->rid); |
691 | +# endif |
692 | +# else |
693 | + len = hid_report_size(rd, repinfo[repind].kind, &r->rid); |
694 | +# endif |
695 | +#else |
696 | +# ifdef USBHID_NEW |
697 | + len = hid_report_size(rd, repinfo[repind].kind, r->rid); |
698 | +# else |
699 | + len = hid_report_size(rd, repinfo[repind].kind, &r->rid); |
700 | +# endif |
701 | +#endif |
702 | + |
703 | + if (len < 0) { |
704 | + SDL_SetError("Negative HID report size"); |
705 | + return (-1); |
706 | + } |
707 | + r->size = len; |
708 | + |
709 | + if (r->size > 0) { |
710 | + r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) + |
711 | + r->size); |
712 | + if (r->buf == NULL) { |
713 | + SDL_OutOfMemory(); |
714 | + return (-1); |
715 | + } |
716 | + } else { |
717 | + r->buf = NULL; |
718 | + } |
719 | + |
720 | + r->status = SREPORT_CLEAN; |
721 | + return (0); |
722 | +} |
723 | + |
724 | +static void |
725 | +report_free(struct report *r) |
726 | +{ |
727 | + if (r->buf != NULL) { |
728 | + SDL_free(r->buf); |
729 | + } |
730 | + r->status = SREPORT_UNINIT; |
731 | +} |
732 | + |
733 | +#endif /* SDL_JOYSTICK_USBHID */ |
734 | |
735 | === added directory '.pc/fix_joystick_misc_axes.diff' |
736 | === added directory '.pc/fix_joystick_misc_axes.diff/src' |
737 | === added directory '.pc/fix_joystick_misc_axes.diff/src/joystick' |
738 | === added directory '.pc/fix_joystick_misc_axes.diff/src/joystick/linux' |
739 | === added file '.pc/fix_joystick_misc_axes.diff/src/joystick/linux/SDL_sysjoystick.c' |
740 | --- .pc/fix_joystick_misc_axes.diff/src/joystick/linux/SDL_sysjoystick.c 1970-01-01 00:00:00 +0000 |
741 | +++ .pc/fix_joystick_misc_axes.diff/src/joystick/linux/SDL_sysjoystick.c 2015-06-01 21:40:05 +0000 |
742 | @@ -0,0 +1,1218 @@ |
743 | +/* |
744 | + SDL - Simple DirectMedia Layer |
745 | + Copyright (C) 1997-2012 Sam Lantinga |
746 | + |
747 | + This library is free software; you can redistribute it and/or |
748 | + modify it under the terms of the GNU Lesser General Public |
749 | + License as published by the Free Software Foundation; either |
750 | + version 2.1 of the License, or (at your option) any later version. |
751 | + |
752 | + This library is distributed in the hope that it will be useful, |
753 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
754 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
755 | + Lesser General Public License for more details. |
756 | + |
757 | + You should have received a copy of the GNU Lesser General Public |
758 | + License along with this library; if not, write to the Free Software |
759 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
760 | + |
761 | + Sam Lantinga |
762 | + slouken@libsdl.org |
763 | +*/ |
764 | +#include "SDL_config.h" |
765 | + |
766 | +#ifdef SDL_JOYSTICK_LINUX |
767 | + |
768 | +/* This is the system specific header for the SDL joystick API */ |
769 | + |
770 | +#include <sys/stat.h> |
771 | +#include <unistd.h> |
772 | +#include <fcntl.h> |
773 | +#include <sys/ioctl.h> |
774 | +#include <limits.h> /* For the definition of PATH_MAX */ |
775 | +#include <linux/joystick.h> |
776 | +#if SDL_INPUT_LINUXEV |
777 | +#include <linux/input.h> |
778 | +#endif |
779 | + |
780 | +#include "SDL_joystick.h" |
781 | +#include "../SDL_sysjoystick.h" |
782 | +#include "../SDL_joystick_c.h" |
783 | + |
784 | +/* Special joystick configurations */ |
785 | +static struct { |
786 | + const char *name; |
787 | + int naxes; |
788 | + int nhats; |
789 | + int nballs; |
790 | +} special_joysticks[] = { |
791 | + { "MadCatz Panther XL", 3, 2, 1 }, /* We don't handle rudder (axis 8) */ |
792 | + { "SideWinder Precision Pro", 4, 1, 0 }, |
793 | + { "SideWinder 3D Pro", 4, 1, 0 }, |
794 | + { "Microsoft SideWinder 3D Pro", 4, 1, 0 }, |
795 | + { "Microsoft SideWinder Precision Pro", 4, 1, 0 }, |
796 | + { "Microsoft SideWinder Dual Strike USB version 1.0", 2, 1, 0 }, |
797 | + { "WingMan Interceptor", 3, 3, 0 }, |
798 | + { "WingMan Extreme Digital 3D", 4, 1, 0 }, |
799 | + { "Microsoft SideWinder Precision 2 Joystick", 4, 1, 0 }, |
800 | + { "Logitech Inc. WingMan Extreme Digital 3D", 4, 1, 0 }, |
801 | + { "Saitek Saitek X45", 6, 1, 0 } |
802 | +}; |
803 | + |
804 | +/* It looks like newer kernels have the logical mapping at the driver level */ |
805 | +#define NO_LOGICAL_JOYSTICKS |
806 | + |
807 | +#ifndef NO_LOGICAL_JOYSTICKS |
808 | + |
809 | +/* |
810 | + Some USB HIDs show up as a single joystick even though they actually |
811 | + control 2 or more joysticks. |
812 | +*/ |
813 | +/* |
814 | + This code handles the MP-8800 (Quad) and MP-8866 (Dual), which can |
815 | + be identified by their transparent blue design. It's quite trivial |
816 | + to add other joysticks with similar quirky behavior. |
817 | + -id |
818 | +*/ |
819 | + |
820 | +struct joystick_logical_mapping { |
821 | + int njoy; |
822 | + int nthing; |
823 | +}; |
824 | + |
825 | +/* |
826 | + {logical joy, logical axis}, |
827 | + {logical joy, logical hat}, |
828 | + {logical joy, logical ball}, |
829 | + {logical joy, logical button} |
830 | +*/ |
831 | + |
832 | +static struct joystick_logical_mapping mp88xx_1_logical_axismap[] = { |
833 | + {0,0},{0,1},{0,2},{0,3},{0,4},{0,5} |
834 | +}; |
835 | +static struct joystick_logical_mapping mp88xx_1_logical_buttonmap[] = { |
836 | + {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11} |
837 | +}; |
838 | + |
839 | +static struct joystick_logical_mapping mp88xx_2_logical_axismap[] = { |
840 | + {0,0},{0,1},{0,2},{1,0},{1,1},{0,3}, |
841 | + {1,2},{1,3},{0,4},{0,5},{1,4},{1,5} |
842 | +}; |
843 | +static struct joystick_logical_mapping mp88xx_2_logical_buttonmap[] = { |
844 | + {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11}, |
845 | + {1,0},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},{1,9},{1,10},{1,11} |
846 | +}; |
847 | + |
848 | +static struct joystick_logical_mapping mp88xx_3_logical_axismap[] = { |
849 | + {0,0},{0,1},{0,2},{1,0},{1,1},{0,3}, |
850 | + {1,2},{1,3},{2,0},{2,1},{2,2},{2,3}, |
851 | + {0,4},{0,5},{1,4},{1,5},{2,4},{2,5} |
852 | +}; |
853 | +static struct joystick_logical_mapping mp88xx_3_logical_buttonmap[] = { |
854 | + {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11}, |
855 | + {1,0},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},{1,9},{1,10},{1,11}, |
856 | + {2,0},{2,1},{2,2},{2,3},{2,4},{2,5},{2,6},{2,7},{2,8},{2,9},{2,10},{2,11} |
857 | +}; |
858 | + |
859 | +static struct joystick_logical_mapping mp88xx_4_logical_axismap[] = { |
860 | + {0,0},{0,1},{0,2},{1,0},{1,1},{0,3}, |
861 | + {1,2},{1,3},{2,0},{2,1},{2,2},{2,3}, |
862 | + {3,0},{3,1},{3,2},{3,3},{0,4},{0,5}, |
863 | + {1,4},{1,5},{2,4},{2,5},{3,4},{3,5} |
864 | +}; |
865 | +static struct joystick_logical_mapping mp88xx_4_logical_buttonmap[] = { |
866 | + {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11}, |
867 | + {1,0},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},{1,9},{1,10},{1,11}, |
868 | + {2,0},{2,1},{2,2},{2,3},{2,4},{2,5},{2,6},{2,7},{2,8},{2,9},{2,10},{2,11}, |
869 | + {3,0},{3,1},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{3,8},{3,9},{3,10},{3,11} |
870 | +}; |
871 | + |
872 | +struct joystick_logical_layout { |
873 | + int naxes; |
874 | + int nhats; |
875 | + int nballs; |
876 | + int nbuttons; |
877 | +}; |
878 | + |
879 | +static struct joystick_logical_layout mp88xx_1_logical_layout[] = { |
880 | + {6, 0, 0, 12} |
881 | +}; |
882 | +static struct joystick_logical_layout mp88xx_2_logical_layout[] = { |
883 | + {6, 0, 0, 12}, |
884 | + {6, 0, 0, 12} |
885 | +}; |
886 | +static struct joystick_logical_layout mp88xx_3_logical_layout[] = { |
887 | + {6, 0, 0, 12}, |
888 | + {6, 0, 0, 12}, |
889 | + {6, 0, 0, 12} |
890 | +}; |
891 | +static struct joystick_logical_layout mp88xx_4_logical_layout[] = { |
892 | + {6, 0, 0, 12}, |
893 | + {6, 0, 0, 12}, |
894 | + {6, 0, 0, 12}, |
895 | + {6, 0, 0, 12} |
896 | +}; |
897 | + |
898 | +/* |
899 | + This array sets up a means of mapping a single physical joystick to |
900 | + multiple logical joysticks. (djm) |
901 | + |
902 | + njoys |
903 | + the number of logical joysticks |
904 | + |
905 | + layouts |
906 | + an array of layout structures, one to describe each logical joystick |
907 | + |
908 | + axes, hats, balls, buttons |
909 | + arrays that map a physical thingy to a logical thingy |
910 | + */ |
911 | +struct joystick_logicalmap { |
912 | + const char *name; |
913 | + int nbuttons; |
914 | + int njoys; |
915 | + struct joystick_logical_layout *layout; |
916 | + struct joystick_logical_mapping *axismap; |
917 | + struct joystick_logical_mapping *hatmap; |
918 | + struct joystick_logical_mapping *ballmap; |
919 | + struct joystick_logical_mapping *buttonmap; |
920 | +}; |
921 | + |
922 | +static struct joystick_logicalmap joystick_logicalmap[] = { |
923 | + { |
924 | + "WiseGroup.,Ltd MP-8866 Dual USB Joypad", |
925 | + 12, |
926 | + 1, |
927 | + mp88xx_1_logical_layout, |
928 | + mp88xx_1_logical_axismap, |
929 | + NULL, |
930 | + NULL, |
931 | + mp88xx_1_logical_buttonmap |
932 | + }, |
933 | + { |
934 | + "WiseGroup.,Ltd MP-8866 Dual USB Joypad", |
935 | + 24, |
936 | + 2, |
937 | + mp88xx_2_logical_layout, |
938 | + mp88xx_2_logical_axismap, |
939 | + NULL, |
940 | + NULL, |
941 | + mp88xx_2_logical_buttonmap |
942 | + }, |
943 | + { |
944 | + "WiseGroup.,Ltd MP-8800 Quad USB Joypad", |
945 | + 12, |
946 | + 1, |
947 | + mp88xx_1_logical_layout, |
948 | + mp88xx_1_logical_axismap, |
949 | + NULL, |
950 | + NULL, |
951 | + mp88xx_1_logical_buttonmap |
952 | + }, |
953 | + { |
954 | + "WiseGroup.,Ltd MP-8800 Quad USB Joypad", |
955 | + 24, |
956 | + 2, |
957 | + mp88xx_2_logical_layout, |
958 | + mp88xx_2_logical_axismap, |
959 | + NULL, |
960 | + NULL, |
961 | + mp88xx_2_logical_buttonmap |
962 | + }, |
963 | + { |
964 | + "WiseGroup.,Ltd MP-8800 Quad USB Joypad", |
965 | + 36, |
966 | + 3, |
967 | + mp88xx_3_logical_layout, |
968 | + mp88xx_3_logical_axismap, |
969 | + NULL, |
970 | + NULL, |
971 | + mp88xx_3_logical_buttonmap |
972 | + }, |
973 | + { |
974 | + "WiseGroup.,Ltd MP-8800 Quad USB Joypad", |
975 | + 48, |
976 | + 4, |
977 | + mp88xx_4_logical_layout, |
978 | + mp88xx_4_logical_axismap, |
979 | + NULL, |
980 | + NULL, |
981 | + mp88xx_4_logical_buttonmap |
982 | + } |
983 | +}; |
984 | + |
985 | +/* find the head of a linked list, given a point in it |
986 | + */ |
987 | +#define SDL_joylist_head(i, start)\ |
988 | + for(i = start; SDL_joylist[i].fname == NULL;) i = SDL_joylist[i].prev; |
989 | + |
990 | +#define SDL_logical_joydecl(d) d |
991 | + |
992 | + |
993 | +#else |
994 | + |
995 | +#define SDL_logical_joydecl(d) |
996 | + |
997 | +#endif /* USE_LOGICAL_JOYSTICKS */ |
998 | + |
999 | +/* The maximum number of joysticks we'll detect */ |
1000 | +#define MAX_JOYSTICKS 32 |
1001 | + |
1002 | +/* A list of available joysticks */ |
1003 | +static struct |
1004 | +{ |
1005 | + char* fname; |
1006 | +#ifndef NO_LOGICAL_JOYSTICKS |
1007 | + SDL_Joystick* joy; |
1008 | + struct joystick_logicalmap* map; |
1009 | + int prev; |
1010 | + int next; |
1011 | + int logicalno; |
1012 | +#endif /* USE_LOGICAL_JOYSTICKS */ |
1013 | +} SDL_joylist[MAX_JOYSTICKS]; |
1014 | + |
1015 | + |
1016 | +/* The private structure used to keep track of a joystick */ |
1017 | +struct joystick_hwdata { |
1018 | + int fd; |
1019 | + /* The current linux joystick driver maps hats to two axes */ |
1020 | + struct hwdata_hat { |
1021 | + int axis[2]; |
1022 | + } *hats; |
1023 | + /* The current linux joystick driver maps balls to two axes */ |
1024 | + struct hwdata_ball { |
1025 | + int axis[2]; |
1026 | + } *balls; |
1027 | + |
1028 | + /* Support for the Linux 2.4 unified input interface */ |
1029 | +#if SDL_INPUT_LINUXEV |
1030 | + SDL_bool is_hid; |
1031 | + Uint8 key_map[KEY_MAX-BTN_MISC]; |
1032 | + Uint8 abs_map[ABS_MAX]; |
1033 | + struct axis_correct { |
1034 | + int used; |
1035 | + int coef[3]; |
1036 | + } abs_correct[ABS_MAX]; |
1037 | +#endif |
1038 | +}; |
1039 | + |
1040 | + |
1041 | +#ifndef NO_LOGICAL_JOYSTICKS |
1042 | + |
1043 | +static int CountLogicalJoysticks(int max) |
1044 | +{ |
1045 | + register int i, j, k, ret, prev; |
1046 | + const char* name; |
1047 | + int nbuttons, fd; |
1048 | + unsigned char n; |
1049 | + |
1050 | + ret = 0; |
1051 | + |
1052 | + for(i = 0; i < max; i++) { |
1053 | + name = SDL_SYS_JoystickName(i); |
1054 | + |
1055 | + fd = open(SDL_joylist[i].fname, O_RDONLY, 0); |
1056 | + if ( fd >= 0 ) { |
1057 | + if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) { |
1058 | + nbuttons = -1; |
1059 | + } else { |
1060 | + nbuttons = n; |
1061 | + } |
1062 | + close(fd); |
1063 | + } |
1064 | + else { |
1065 | + nbuttons=-1; |
1066 | + } |
1067 | + |
1068 | + if (name) { |
1069 | + for(j = 0; j < SDL_arraysize(joystick_logicalmap); j++) { |
1070 | + if (!SDL_strcmp(name, joystick_logicalmap[j].name) && (nbuttons==-1 || nbuttons==joystick_logicalmap[j].nbuttons)) { |
1071 | + prev = i; |
1072 | + SDL_joylist[prev].map = &(joystick_logicalmap[j]); |
1073 | + |
1074 | + for(k = 1; k < joystick_logicalmap[j].njoys; k++) { |
1075 | + SDL_joylist[prev].next = max + ret; |
1076 | + SDL_joylist[max+ret].prev = prev; |
1077 | + |
1078 | + prev = max + ret; |
1079 | + SDL_joylist[prev].logicalno = k; |
1080 | + SDL_joylist[prev].map = &(joystick_logicalmap[j]); |
1081 | + ret++; |
1082 | + } |
1083 | + |
1084 | + break; |
1085 | + } |
1086 | + } |
1087 | + } |
1088 | + } |
1089 | + |
1090 | + return ret; |
1091 | +} |
1092 | + |
1093 | +static void LogicalSuffix(int logicalno, char* namebuf, int len) |
1094 | +{ |
1095 | + register int slen; |
1096 | + const static char suffixs[] = |
1097 | + "01020304050607080910111213141516171819" |
1098 | + "20212223242526272829303132"; |
1099 | + const char* suffix; |
1100 | + slen = SDL_strlen(namebuf); |
1101 | + suffix = NULL; |
1102 | + |
1103 | + if (logicalno*2<sizeof(suffixs)) |
1104 | + suffix = suffixs + (logicalno*2); |
1105 | + |
1106 | + if (slen + 4 < len && suffix) { |
1107 | + namebuf[slen++] = ' '; |
1108 | + namebuf[slen++] = '#'; |
1109 | + namebuf[slen++] = suffix[0]; |
1110 | + namebuf[slen++] = suffix[1]; |
1111 | + namebuf[slen++] = 0; |
1112 | + } |
1113 | +} |
1114 | + |
1115 | +#endif /* USE_LOGICAL_JOYSTICKS */ |
1116 | + |
1117 | +#if SDL_INPUT_LINUXEV |
1118 | +#define test_bit(nr, addr) \ |
1119 | + (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0) |
1120 | +#define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1) |
1121 | + |
1122 | +static int EV_IsJoystick(int fd) |
1123 | +{ |
1124 | + unsigned long evbit[NBITS(EV_MAX)] = { 0 }; |
1125 | + unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; |
1126 | + unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; |
1127 | + |
1128 | + if ( (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) || |
1129 | + (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || |
1130 | + (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) ) { |
1131 | + return(0); |
1132 | + } |
1133 | + if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && |
1134 | + test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) && |
1135 | + (test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_A, keybit) || test_bit(BTN_1, keybit)))) return 0; |
1136 | + return(1); |
1137 | +} |
1138 | + |
1139 | +#endif /* SDL_INPUT_LINUXEV */ |
1140 | + |
1141 | +/* Function to scan the system for joysticks */ |
1142 | +int SDL_SYS_JoystickInit(void) |
1143 | +{ |
1144 | + /* The base path of the joystick devices */ |
1145 | + const char *joydev_pattern[] = { |
1146 | +#if SDL_INPUT_LINUXEV |
1147 | + "/dev/input/event%d", |
1148 | +#endif |
1149 | + "/dev/input/js%d", |
1150 | + "/dev/js%d" |
1151 | + }; |
1152 | + int numjoysticks; |
1153 | + int i, j; |
1154 | + int fd; |
1155 | + char path[PATH_MAX]; |
1156 | + dev_t dev_nums[MAX_JOYSTICKS]; /* major/minor device numbers */ |
1157 | + struct stat sb; |
1158 | + int n, duplicate; |
1159 | + |
1160 | + numjoysticks = 0; |
1161 | + |
1162 | + /* First see if the user specified one or more joysticks to use */ |
1163 | + if ( SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL ) { |
1164 | + char *envcopy, *envpath, *delim; |
1165 | + envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE")); |
1166 | + envpath = envcopy; |
1167 | + while ( envpath != NULL ) { |
1168 | + delim = SDL_strchr(envpath, ':'); |
1169 | + if ( delim != NULL ) { |
1170 | + *delim++ = '\0'; |
1171 | + } |
1172 | + if ( stat(envpath, &sb) == 0 ) { |
1173 | + fd = open(envpath, O_RDONLY, 0); |
1174 | + if ( fd >= 0 ) { |
1175 | + /* Assume the user knows what they're doing. */ |
1176 | + SDL_joylist[numjoysticks].fname = SDL_strdup(envpath); |
1177 | + if ( SDL_joylist[numjoysticks].fname ) { |
1178 | + dev_nums[numjoysticks] = sb.st_rdev; |
1179 | + ++numjoysticks; |
1180 | + } |
1181 | + close(fd); |
1182 | + } |
1183 | + } |
1184 | + envpath = delim; |
1185 | + } |
1186 | + SDL_free(envcopy); |
1187 | + } |
1188 | + |
1189 | + for ( i=0; i<SDL_arraysize(joydev_pattern); ++i ) { |
1190 | + for ( j=0; j < MAX_JOYSTICKS; ++j ) { |
1191 | + SDL_snprintf(path, SDL_arraysize(path), joydev_pattern[i], j); |
1192 | + |
1193 | + /* rcg06302000 replaced access(F_OK) call with stat(). |
1194 | + * stat() will fail if the file doesn't exist, so it's |
1195 | + * equivalent behaviour. |
1196 | + */ |
1197 | + if ( stat(path, &sb) == 0 ) { |
1198 | + /* Check to make sure it's not already in list. |
1199 | + * This happens when we see a stick via symlink. |
1200 | + */ |
1201 | + duplicate = 0; |
1202 | + for (n=0; (n<numjoysticks) && !duplicate; ++n) { |
1203 | + if ( sb.st_rdev == dev_nums[n] ) { |
1204 | + duplicate = 1; |
1205 | + } |
1206 | + } |
1207 | + if (duplicate) { |
1208 | + continue; |
1209 | + } |
1210 | + |
1211 | + fd = open(path, O_RDONLY, 0); |
1212 | + if ( fd < 0 ) { |
1213 | + continue; |
1214 | + } |
1215 | +#if SDL_INPUT_LINUXEV |
1216 | +#ifdef DEBUG_INPUT_EVENTS |
1217 | + printf("Checking %s\n", path); |
1218 | +#endif |
1219 | + if ( (i == 0) && ! EV_IsJoystick(fd) ) { |
1220 | + close(fd); |
1221 | + continue; |
1222 | + } |
1223 | +#endif |
1224 | + close(fd); |
1225 | + |
1226 | + /* We're fine, add this joystick */ |
1227 | + SDL_joylist[numjoysticks].fname = SDL_strdup(path); |
1228 | + if ( SDL_joylist[numjoysticks].fname ) { |
1229 | + dev_nums[numjoysticks] = sb.st_rdev; |
1230 | + ++numjoysticks; |
1231 | + } |
1232 | + } |
1233 | + } |
1234 | + |
1235 | +#if SDL_INPUT_LINUXEV |
1236 | + /* This is a special case... |
1237 | + If the event devices are valid then the joystick devices |
1238 | + will be duplicates but without extra information about their |
1239 | + hats or balls. Unfortunately, the event devices can't |
1240 | + currently be calibrated, so it's a win-lose situation. |
1241 | + So : /dev/input/eventX = /dev/input/jsY = /dev/jsY |
1242 | + */ |
1243 | + if ( (i == 0) && (numjoysticks > 0) ) |
1244 | + break; |
1245 | +#endif |
1246 | + } |
1247 | +#ifndef NO_LOGICAL_JOYSTICKS |
1248 | + numjoysticks += CountLogicalJoysticks(numjoysticks); |
1249 | +#endif |
1250 | + |
1251 | + return(numjoysticks); |
1252 | +} |
1253 | + |
1254 | +/* Function to get the device-dependent name of a joystick */ |
1255 | +const char *SDL_SYS_JoystickName(int index) |
1256 | +{ |
1257 | + int fd; |
1258 | + static char namebuf[128]; |
1259 | + char *name; |
1260 | + SDL_logical_joydecl(int oindex = index); |
1261 | + |
1262 | +#ifndef NO_LOGICAL_JOYSTICKS |
1263 | + SDL_joylist_head(index, index); |
1264 | +#endif |
1265 | + name = NULL; |
1266 | + fd = open(SDL_joylist[index].fname, O_RDONLY, 0); |
1267 | + if ( fd >= 0 ) { |
1268 | + if ( |
1269 | +#if SDL_INPUT_LINUXEV |
1270 | + (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) && |
1271 | +#endif |
1272 | + (ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf) <= 0) ) { |
1273 | + name = SDL_joylist[index].fname; |
1274 | + } else { |
1275 | + name = namebuf; |
1276 | + } |
1277 | + close(fd); |
1278 | + |
1279 | + |
1280 | +#ifndef NO_LOGICAL_JOYSTICKS |
1281 | + if (SDL_joylist[oindex].prev || SDL_joylist[oindex].next || index!=oindex) |
1282 | + { |
1283 | + LogicalSuffix(SDL_joylist[oindex].logicalno, namebuf, 128); |
1284 | + } |
1285 | +#endif |
1286 | + } |
1287 | + return name; |
1288 | +} |
1289 | + |
1290 | +static int allocate_hatdata(SDL_Joystick *joystick) |
1291 | +{ |
1292 | + int i; |
1293 | + |
1294 | + joystick->hwdata->hats = (struct hwdata_hat *)SDL_malloc( |
1295 | + joystick->nhats * sizeof(struct hwdata_hat)); |
1296 | + if ( joystick->hwdata->hats == NULL ) { |
1297 | + return(-1); |
1298 | + } |
1299 | + for ( i=0; i<joystick->nhats; ++i ) { |
1300 | + joystick->hwdata->hats[i].axis[0] = 1; |
1301 | + joystick->hwdata->hats[i].axis[1] = 1; |
1302 | + } |
1303 | + return(0); |
1304 | +} |
1305 | + |
1306 | +static int allocate_balldata(SDL_Joystick *joystick) |
1307 | +{ |
1308 | + int i; |
1309 | + |
1310 | + joystick->hwdata->balls = (struct hwdata_ball *)SDL_malloc( |
1311 | + joystick->nballs * sizeof(struct hwdata_ball)); |
1312 | + if ( joystick->hwdata->balls == NULL ) { |
1313 | + return(-1); |
1314 | + } |
1315 | + for ( i=0; i<joystick->nballs; ++i ) { |
1316 | + joystick->hwdata->balls[i].axis[0] = 0; |
1317 | + joystick->hwdata->balls[i].axis[1] = 0; |
1318 | + } |
1319 | + return(0); |
1320 | +} |
1321 | + |
1322 | +static SDL_bool JS_ConfigJoystick(SDL_Joystick *joystick, int fd) |
1323 | +{ |
1324 | + SDL_bool handled; |
1325 | + unsigned char n; |
1326 | + int tmp_naxes, tmp_nhats, tmp_nballs; |
1327 | + const char *name; |
1328 | + char *env, env_name[128]; |
1329 | + int i; |
1330 | + |
1331 | + handled = SDL_FALSE; |
1332 | + |
1333 | + /* Default joystick device settings */ |
1334 | + if ( ioctl(fd, JSIOCGAXES, &n) < 0 ) { |
1335 | + joystick->naxes = 2; |
1336 | + } else { |
1337 | + joystick->naxes = n; |
1338 | + } |
1339 | + if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) { |
1340 | + joystick->nbuttons = 2; |
1341 | + } else { |
1342 | + joystick->nbuttons = n; |
1343 | + } |
1344 | + |
1345 | + name = SDL_SYS_JoystickName(joystick->index); |
1346 | + |
1347 | + /* Generic analog joystick support */ |
1348 | + if ( SDL_strstr(name, "Analog") == name && SDL_strstr(name, "-hat") ) { |
1349 | + if ( SDL_sscanf(name,"Analog %d-axis %*d-button %d-hat", |
1350 | + &tmp_naxes, &tmp_nhats) == 2 ) { |
1351 | + |
1352 | + joystick->naxes = tmp_naxes; |
1353 | + joystick->nhats = tmp_nhats; |
1354 | + |
1355 | + handled = SDL_TRUE; |
1356 | + } |
1357 | + } |
1358 | + |
1359 | + /* Special joystick support */ |
1360 | + for ( i=0; i < SDL_arraysize(special_joysticks); ++i ) { |
1361 | + if ( SDL_strcmp(name, special_joysticks[i].name) == 0 ) { |
1362 | + |
1363 | + joystick->naxes = special_joysticks[i].naxes; |
1364 | + joystick->nhats = special_joysticks[i].nhats; |
1365 | + joystick->nballs = special_joysticks[i].nballs; |
1366 | + |
1367 | + handled = SDL_TRUE; |
1368 | + break; |
1369 | + } |
1370 | + } |
1371 | + |
1372 | + /* User environment joystick support */ |
1373 | + if ( (env = SDL_getenv("SDL_LINUX_JOYSTICK")) ) { |
1374 | + *env_name = '\0'; |
1375 | + if ( *env == '\'' && SDL_sscanf(env, "'%[^']s'", env_name) == 1 ) |
1376 | + env += SDL_strlen(env_name)+2; |
1377 | + else if ( SDL_sscanf(env, "%s", env_name) == 1 ) |
1378 | + env += SDL_strlen(env_name); |
1379 | + |
1380 | + if ( SDL_strcmp(name, env_name) == 0 ) { |
1381 | + |
1382 | + if ( SDL_sscanf(env, "%d %d %d", &tmp_naxes, &tmp_nhats, |
1383 | + &tmp_nballs) == 3 ) { |
1384 | + |
1385 | + joystick->naxes = tmp_naxes; |
1386 | + joystick->nhats = tmp_nhats; |
1387 | + joystick->nballs = tmp_nballs; |
1388 | + |
1389 | + handled = SDL_TRUE; |
1390 | + } |
1391 | + } |
1392 | + } |
1393 | + |
1394 | + /* Remap hats and balls */ |
1395 | + if (handled) { |
1396 | + if ( joystick->nhats > 0 ) { |
1397 | + if ( allocate_hatdata(joystick) < 0 ) { |
1398 | + joystick->nhats = 0; |
1399 | + } |
1400 | + } |
1401 | + if ( joystick->nballs > 0 ) { |
1402 | + if ( allocate_balldata(joystick) < 0 ) { |
1403 | + joystick->nballs = 0; |
1404 | + } |
1405 | + } |
1406 | + } |
1407 | + |
1408 | + return(handled); |
1409 | +} |
1410 | + |
1411 | +#if SDL_INPUT_LINUXEV |
1412 | + |
1413 | +static SDL_bool EV_ConfigJoystick(SDL_Joystick *joystick, int fd) |
1414 | +{ |
1415 | + int i, t; |
1416 | + unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; |
1417 | + unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; |
1418 | + unsigned long relbit[NBITS(REL_MAX)] = { 0 }; |
1419 | + |
1420 | + /* See if this device uses the new unified event API */ |
1421 | + if ( (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) && |
1422 | + (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) && |
1423 | + (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) ) { |
1424 | + joystick->hwdata->is_hid = SDL_TRUE; |
1425 | + |
1426 | + /* Get the number of buttons, axes, and other thingamajigs */ |
1427 | + for ( i=BTN_JOYSTICK; i < KEY_MAX; ++i ) { |
1428 | + if ( test_bit(i, keybit) ) { |
1429 | +#ifdef DEBUG_INPUT_EVENTS |
1430 | + printf("Joystick has button: 0x%x\n", i); |
1431 | +#endif |
1432 | + joystick->hwdata->key_map[i-BTN_MISC] = |
1433 | + joystick->nbuttons; |
1434 | + ++joystick->nbuttons; |
1435 | + } |
1436 | + } |
1437 | + for ( i=BTN_MISC; i < BTN_JOYSTICK; ++i ) { |
1438 | + if ( test_bit(i, keybit) ) { |
1439 | +#ifdef DEBUG_INPUT_EVENTS |
1440 | + printf("Joystick has button: 0x%x\n", i); |
1441 | +#endif |
1442 | + joystick->hwdata->key_map[i-BTN_MISC] = |
1443 | + joystick->nbuttons; |
1444 | + ++joystick->nbuttons; |
1445 | + } |
1446 | + } |
1447 | + for ( i=0; i<ABS_MISC; ++i ) { |
1448 | + /* Skip hats */ |
1449 | + if ( i == ABS_HAT0X ) { |
1450 | + i = ABS_HAT3Y; |
1451 | + continue; |
1452 | + } |
1453 | + if ( test_bit(i, absbit) ) { |
1454 | + struct input_absinfo absinfo; |
1455 | + |
1456 | + if ( ioctl(fd, EVIOCGABS(i), &absinfo) < 0 ) |
1457 | + continue; |
1458 | +#ifdef DEBUG_INPUT_EVENTS |
1459 | + printf("Joystick has absolute axis: %x\n", i); |
1460 | + printf("Values = { %d, %d, %d, %d, %d }\n", |
1461 | + absinfo.value, absinfo.minimum, |
1462 | + absinfo.maximum, absinfo.fuzz, absinfo.flat); |
1463 | +#endif /* DEBUG_INPUT_EVENTS */ |
1464 | + joystick->hwdata->abs_map[i] = joystick->naxes; |
1465 | + if ( absinfo.minimum == absinfo.maximum ) { |
1466 | + joystick->hwdata->abs_correct[i].used = 0; |
1467 | + } else { |
1468 | + joystick->hwdata->abs_correct[i].used = 1; |
1469 | + joystick->hwdata->abs_correct[i].coef[0] = |
1470 | + (absinfo.maximum + absinfo.minimum) / 2 - absinfo.flat; |
1471 | + joystick->hwdata->abs_correct[i].coef[1] = |
1472 | + (absinfo.maximum + absinfo.minimum) / 2 + absinfo.flat; |
1473 | + t = ((absinfo.maximum - absinfo.minimum) / 2 - 2 * absinfo.flat); |
1474 | + if ( t != 0 ) { |
1475 | + joystick->hwdata->abs_correct[i].coef[2] = (1 << 29) / t; |
1476 | + } else { |
1477 | + joystick->hwdata->abs_correct[i].coef[2] = 0; |
1478 | + } |
1479 | + } |
1480 | + ++joystick->naxes; |
1481 | + } |
1482 | + } |
1483 | + for ( i=ABS_HAT0X; i <= ABS_HAT3Y; i += 2 ) { |
1484 | + if ( test_bit(i, absbit) || test_bit(i+1, absbit) ) { |
1485 | +#ifdef DEBUG_INPUT_EVENTS |
1486 | + printf("Joystick has hat %d\n",(i-ABS_HAT0X)/2); |
1487 | +#endif |
1488 | + ++joystick->nhats; |
1489 | + } |
1490 | + } |
1491 | + if ( test_bit(REL_X, relbit) || test_bit(REL_Y, relbit) ) { |
1492 | + ++joystick->nballs; |
1493 | + } |
1494 | + |
1495 | + /* Allocate data to keep track of these thingamajigs */ |
1496 | + if ( joystick->nhats > 0 ) { |
1497 | + if ( allocate_hatdata(joystick) < 0 ) { |
1498 | + joystick->nhats = 0; |
1499 | + } |
1500 | + } |
1501 | + if ( joystick->nballs > 0 ) { |
1502 | + if ( allocate_balldata(joystick) < 0 ) { |
1503 | + joystick->nballs = 0; |
1504 | + } |
1505 | + } |
1506 | + } |
1507 | + return(joystick->hwdata->is_hid); |
1508 | +} |
1509 | + |
1510 | +#endif /* SDL_INPUT_LINUXEV */ |
1511 | + |
1512 | +#ifndef NO_LOGICAL_JOYSTICKS |
1513 | +static void ConfigLogicalJoystick(SDL_Joystick *joystick) |
1514 | +{ |
1515 | + struct joystick_logical_layout* layout; |
1516 | + |
1517 | + layout = SDL_joylist[joystick->index].map->layout + |
1518 | + SDL_joylist[joystick->index].logicalno; |
1519 | + |
1520 | + joystick->nbuttons = layout->nbuttons; |
1521 | + joystick->nhats = layout->nhats; |
1522 | + joystick->naxes = layout->naxes; |
1523 | + joystick->nballs = layout->nballs; |
1524 | +} |
1525 | +#endif |
1526 | + |
1527 | + |
1528 | +/* Function to open a joystick for use. |
1529 | + The joystick to open is specified by the index field of the joystick. |
1530 | + This should fill the nbuttons and naxes fields of the joystick structure. |
1531 | + It returns 0, or -1 if there is an error. |
1532 | + */ |
1533 | +int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) |
1534 | +{ |
1535 | + int fd; |
1536 | + SDL_logical_joydecl(int realindex); |
1537 | + SDL_logical_joydecl(SDL_Joystick *realjoy = NULL); |
1538 | + |
1539 | + /* Open the joystick and set the joystick file descriptor */ |
1540 | +#ifndef NO_LOGICAL_JOYSTICKS |
1541 | + if (SDL_joylist[joystick->index].fname == NULL) { |
1542 | + SDL_joylist_head(realindex, joystick->index); |
1543 | + realjoy = SDL_JoystickOpen(realindex); |
1544 | + |
1545 | + if (realjoy == NULL) |
1546 | + return(-1); |
1547 | + |
1548 | + fd = realjoy->hwdata->fd; |
1549 | + |
1550 | + } else { |
1551 | + fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0); |
1552 | + } |
1553 | + SDL_joylist[joystick->index].joy = joystick; |
1554 | +#else |
1555 | + fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0); |
1556 | +#endif |
1557 | + |
1558 | + if ( fd < 0 ) { |
1559 | + SDL_SetError("Unable to open %s\n", |
1560 | + SDL_joylist[joystick->index]); |
1561 | + return(-1); |
1562 | + } |
1563 | + joystick->hwdata = (struct joystick_hwdata *) |
1564 | + SDL_malloc(sizeof(*joystick->hwdata)); |
1565 | + if ( joystick->hwdata == NULL ) { |
1566 | + SDL_OutOfMemory(); |
1567 | + close(fd); |
1568 | + return(-1); |
1569 | + } |
1570 | + SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata)); |
1571 | + joystick->hwdata->fd = fd; |
1572 | + |
1573 | + /* Set the joystick to non-blocking read mode */ |
1574 | + fcntl(fd, F_SETFL, O_NONBLOCK); |
1575 | + |
1576 | + /* Get the number of buttons and axes on the joystick */ |
1577 | +#ifndef NO_LOGICAL_JOYSTICKS |
1578 | + if (realjoy) |
1579 | + ConfigLogicalJoystick(joystick); |
1580 | + else |
1581 | +#endif |
1582 | +#if SDL_INPUT_LINUXEV |
1583 | + if ( ! EV_ConfigJoystick(joystick, fd) ) |
1584 | +#endif |
1585 | + JS_ConfigJoystick(joystick, fd); |
1586 | + |
1587 | + return(0); |
1588 | +} |
1589 | + |
1590 | +#ifndef NO_LOGICAL_JOYSTICKS |
1591 | + |
1592 | +static SDL_Joystick* FindLogicalJoystick( |
1593 | + SDL_Joystick *joystick, struct joystick_logical_mapping* v) |
1594 | +{ |
1595 | + SDL_Joystick *logicaljoy; |
1596 | + register int i; |
1597 | + |
1598 | + i = joystick->index; |
1599 | + logicaljoy = NULL; |
1600 | + |
1601 | + /* get the fake joystick that will receive the event |
1602 | + */ |
1603 | + for(;;) { |
1604 | + |
1605 | + if (SDL_joylist[i].logicalno == v->njoy) { |
1606 | + logicaljoy = SDL_joylist[i].joy; |
1607 | + break; |
1608 | + } |
1609 | + |
1610 | + if (SDL_joylist[i].next == 0) |
1611 | + break; |
1612 | + |
1613 | + i = SDL_joylist[i].next; |
1614 | + |
1615 | + } |
1616 | + |
1617 | + return logicaljoy; |
1618 | +} |
1619 | + |
1620 | +static int LogicalJoystickButton( |
1621 | + SDL_Joystick *joystick, Uint8 button, Uint8 state){ |
1622 | + struct joystick_logical_mapping* buttons; |
1623 | + SDL_Joystick *logicaljoy = NULL; |
1624 | + |
1625 | + /* if there's no map then this is just a regular joystick |
1626 | + */ |
1627 | + if (SDL_joylist[joystick->index].map == NULL) |
1628 | + return 0; |
1629 | + |
1630 | + /* get the logical joystick that will receive the event |
1631 | + */ |
1632 | + buttons = SDL_joylist[joystick->index].map->buttonmap+button; |
1633 | + logicaljoy = FindLogicalJoystick(joystick, buttons); |
1634 | + |
1635 | + if (logicaljoy == NULL) |
1636 | + return 1; |
1637 | + |
1638 | + SDL_PrivateJoystickButton(logicaljoy, buttons->nthing, state); |
1639 | + |
1640 | + return 1; |
1641 | +} |
1642 | + |
1643 | +static int LogicalJoystickAxis( |
1644 | + SDL_Joystick *joystick, Uint8 axis, Sint16 value) |
1645 | +{ |
1646 | + struct joystick_logical_mapping* axes; |
1647 | + SDL_Joystick *logicaljoy = NULL; |
1648 | + |
1649 | + /* if there's no map then this is just a regular joystick |
1650 | + */ |
1651 | + if (SDL_joylist[joystick->index].map == NULL) |
1652 | + return 0; |
1653 | + |
1654 | + /* get the logical joystick that will receive the event |
1655 | + */ |
1656 | + axes = SDL_joylist[joystick->index].map->axismap+axis; |
1657 | + logicaljoy = FindLogicalJoystick(joystick, axes); |
1658 | + |
1659 | + if (logicaljoy == NULL) |
1660 | + return 1; |
1661 | + |
1662 | + SDL_PrivateJoystickAxis(logicaljoy, axes->nthing, value); |
1663 | + |
1664 | + return 1; |
1665 | +} |
1666 | +#endif /* USE_LOGICAL_JOYSTICKS */ |
1667 | + |
1668 | +static __inline__ |
1669 | +void HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value) |
1670 | +{ |
1671 | + struct hwdata_hat *the_hat; |
1672 | + const Uint8 position_map[3][3] = { |
1673 | + { SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP }, |
1674 | + { SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT }, |
1675 | + { SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN } |
1676 | + }; |
1677 | + SDL_logical_joydecl(SDL_Joystick *logicaljoy = NULL); |
1678 | + SDL_logical_joydecl(struct joystick_logical_mapping* hats = NULL); |
1679 | + |
1680 | + if (stick->nhats <= hat) { |
1681 | + return; /* whoops, that shouldn't happen! */ |
1682 | + } |
1683 | + |
1684 | + the_hat = &stick->hwdata->hats[hat]; |
1685 | + if ( value < 0 ) { |
1686 | + value = 0; |
1687 | + } else |
1688 | + if ( value == 0 ) { |
1689 | + value = 1; |
1690 | + } else |
1691 | + if ( value > 0 ) { |
1692 | + value = 2; |
1693 | + } |
1694 | + if ( value != the_hat->axis[axis] ) { |
1695 | + the_hat->axis[axis] = value; |
1696 | + |
1697 | +#ifndef NO_LOGICAL_JOYSTICKS |
1698 | + /* if there's no map then this is just a regular joystick |
1699 | + */ |
1700 | + if (SDL_joylist[stick->index].map != NULL) { |
1701 | + |
1702 | + /* get the fake joystick that will receive the event |
1703 | + */ |
1704 | + hats = SDL_joylist[stick->index].map->hatmap+hat; |
1705 | + logicaljoy = FindLogicalJoystick(stick, hats); |
1706 | + } |
1707 | + |
1708 | + if (logicaljoy) { |
1709 | + stick = logicaljoy; |
1710 | + hat = hats->nthing; |
1711 | + } |
1712 | +#endif /* USE_LOGICAL_JOYSTICKS */ |
1713 | + |
1714 | + SDL_PrivateJoystickHat(stick, hat, |
1715 | + position_map[the_hat->axis[1]][the_hat->axis[0]]); |
1716 | + } |
1717 | +} |
1718 | + |
1719 | +static __inline__ |
1720 | +void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value) |
1721 | +{ |
1722 | + if ((stick->nballs <= ball) || (axis >= 2)) { |
1723 | + return; /* whoops, that shouldn't happen! */ |
1724 | + } |
1725 | + stick->hwdata->balls[ball].axis[axis] += value; |
1726 | +} |
1727 | + |
1728 | +/* Function to update the state of a joystick - called as a device poll. |
1729 | + * This function shouldn't update the joystick structure directly, |
1730 | + * but instead should call SDL_PrivateJoystick*() to deliver events |
1731 | + * and update joystick device state. |
1732 | + */ |
1733 | +static __inline__ void JS_HandleEvents(SDL_Joystick *joystick) |
1734 | +{ |
1735 | + struct js_event events[32]; |
1736 | + int i, len; |
1737 | + Uint8 other_axis; |
1738 | + |
1739 | +#ifndef NO_LOGICAL_JOYSTICKS |
1740 | + if (SDL_joylist[joystick->index].fname == NULL) { |
1741 | + SDL_joylist_head(i, joystick->index); |
1742 | + JS_HandleEvents(SDL_joylist[i].joy); |
1743 | + return; |
1744 | + } |
1745 | +#endif |
1746 | + |
1747 | + while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) { |
1748 | + len /= sizeof(events[0]); |
1749 | + for ( i=0; i<len; ++i ) { |
1750 | + switch (events[i].type & ~JS_EVENT_INIT) { |
1751 | + case JS_EVENT_AXIS: |
1752 | + if ( events[i].number < joystick->naxes ) { |
1753 | +#ifndef NO_LOGICAL_JOYSTICKS |
1754 | + if (!LogicalJoystickAxis(joystick, |
1755 | + events[i].number, events[i].value)) |
1756 | +#endif |
1757 | + SDL_PrivateJoystickAxis(joystick, |
1758 | + events[i].number, events[i].value); |
1759 | + break; |
1760 | + } |
1761 | + events[i].number -= joystick->naxes; |
1762 | + other_axis = (events[i].number / 2); |
1763 | + if ( other_axis < joystick->nhats ) { |
1764 | + HandleHat(joystick, other_axis, |
1765 | + events[i].number%2, |
1766 | + events[i].value); |
1767 | + break; |
1768 | + } |
1769 | + events[i].number -= joystick->nhats*2; |
1770 | + other_axis = (events[i].number / 2); |
1771 | + if ( other_axis < joystick->nballs ) { |
1772 | + HandleBall(joystick, other_axis, |
1773 | + events[i].number%2, |
1774 | + events[i].value); |
1775 | + break; |
1776 | + } |
1777 | + break; |
1778 | + case JS_EVENT_BUTTON: |
1779 | +#ifndef NO_LOGICAL_JOYSTICKS |
1780 | + if (!LogicalJoystickButton(joystick, |
1781 | + events[i].number, events[i].value)) |
1782 | +#endif |
1783 | + SDL_PrivateJoystickButton(joystick, |
1784 | + events[i].number, events[i].value); |
1785 | + break; |
1786 | + default: |
1787 | + /* ?? */ |
1788 | + break; |
1789 | + } |
1790 | + } |
1791 | + } |
1792 | +} |
1793 | +#if SDL_INPUT_LINUXEV |
1794 | +static __inline__ int EV_AxisCorrect(SDL_Joystick *joystick, int which, int value) |
1795 | +{ |
1796 | + struct axis_correct *correct; |
1797 | + |
1798 | + correct = &joystick->hwdata->abs_correct[which]; |
1799 | + if ( correct->used ) { |
1800 | + if ( value > correct->coef[0] ) { |
1801 | + if ( value < correct->coef[1] ) { |
1802 | + return 0; |
1803 | + } |
1804 | + value -= correct->coef[1]; |
1805 | + } else { |
1806 | + value -= correct->coef[0]; |
1807 | + } |
1808 | + value *= correct->coef[2]; |
1809 | + value >>= 14; |
1810 | + } |
1811 | + |
1812 | + /* Clamp and return */ |
1813 | + if ( value < -32768 ) return -32768; |
1814 | + if ( value > 32767 ) return 32767; |
1815 | + |
1816 | + return value; |
1817 | +} |
1818 | + |
1819 | +static __inline__ void EV_HandleEvents(SDL_Joystick *joystick) |
1820 | +{ |
1821 | + struct input_event events[32]; |
1822 | + int i, len; |
1823 | + int code; |
1824 | + |
1825 | +#ifndef NO_LOGICAL_JOYSTICKS |
1826 | + if (SDL_joylist[joystick->index].fname == NULL) { |
1827 | + SDL_joylist_head(i, joystick->index); |
1828 | + return EV_HandleEvents(SDL_joylist[i].joy); |
1829 | + } |
1830 | +#endif |
1831 | + |
1832 | + while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) { |
1833 | + len /= sizeof(events[0]); |
1834 | + for ( i=0; i<len; ++i ) { |
1835 | + code = events[i].code; |
1836 | + switch (events[i].type) { |
1837 | + case EV_KEY: |
1838 | + if ( code >= BTN_MISC ) { |
1839 | + code -= BTN_MISC; |
1840 | +#ifndef NO_LOGICAL_JOYSTICKS |
1841 | + if (!LogicalJoystickButton(joystick, |
1842 | + joystick->hwdata->key_map[code], |
1843 | + events[i].value)) |
1844 | +#endif |
1845 | + SDL_PrivateJoystickButton(joystick, |
1846 | + joystick->hwdata->key_map[code], |
1847 | + events[i].value); |
1848 | + } |
1849 | + break; |
1850 | + case EV_ABS: |
1851 | + switch (code) { |
1852 | + case ABS_HAT0X: |
1853 | + case ABS_HAT0Y: |
1854 | + case ABS_HAT1X: |
1855 | + case ABS_HAT1Y: |
1856 | + case ABS_HAT2X: |
1857 | + case ABS_HAT2Y: |
1858 | + case ABS_HAT3X: |
1859 | + case ABS_HAT3Y: |
1860 | + code -= ABS_HAT0X; |
1861 | + HandleHat(joystick, code/2, code%2, |
1862 | + events[i].value); |
1863 | + break; |
1864 | + default: |
1865 | + events[i].value = EV_AxisCorrect(joystick, code, events[i].value); |
1866 | +#ifndef NO_LOGICAL_JOYSTICKS |
1867 | + if (!LogicalJoystickAxis(joystick, |
1868 | + joystick->hwdata->abs_map[code], |
1869 | + events[i].value)) |
1870 | +#endif |
1871 | + SDL_PrivateJoystickAxis(joystick, |
1872 | + joystick->hwdata->abs_map[code], |
1873 | + events[i].value); |
1874 | + break; |
1875 | + } |
1876 | + break; |
1877 | + case EV_REL: |
1878 | + switch (code) { |
1879 | + case REL_X: |
1880 | + case REL_Y: |
1881 | + code -= REL_X; |
1882 | + HandleBall(joystick, code/2, code%2, |
1883 | + events[i].value); |
1884 | + break; |
1885 | + default: |
1886 | + break; |
1887 | + } |
1888 | + break; |
1889 | + default: |
1890 | + break; |
1891 | + } |
1892 | + } |
1893 | + } |
1894 | +} |
1895 | +#endif /* SDL_INPUT_LINUXEV */ |
1896 | + |
1897 | +void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) |
1898 | +{ |
1899 | + int i; |
1900 | + |
1901 | +#if SDL_INPUT_LINUXEV |
1902 | + if ( joystick->hwdata->is_hid ) |
1903 | + EV_HandleEvents(joystick); |
1904 | + else |
1905 | +#endif |
1906 | + JS_HandleEvents(joystick); |
1907 | + |
1908 | + /* Deliver ball motion updates */ |
1909 | + for ( i=0; i<joystick->nballs; ++i ) { |
1910 | + int xrel, yrel; |
1911 | + |
1912 | + xrel = joystick->hwdata->balls[i].axis[0]; |
1913 | + yrel = joystick->hwdata->balls[i].axis[1]; |
1914 | + if ( xrel || yrel ) { |
1915 | + joystick->hwdata->balls[i].axis[0] = 0; |
1916 | + joystick->hwdata->balls[i].axis[1] = 0; |
1917 | + SDL_PrivateJoystickBall(joystick, (Uint8)i, xrel, yrel); |
1918 | + } |
1919 | + } |
1920 | +} |
1921 | + |
1922 | +/* Function to close a joystick after use */ |
1923 | +void SDL_SYS_JoystickClose(SDL_Joystick *joystick) |
1924 | +{ |
1925 | +#ifndef NO_LOGICAL_JOYSTICKS |
1926 | + register int i; |
1927 | + if (SDL_joylist[joystick->index].fname == NULL) { |
1928 | + SDL_joylist_head(i, joystick->index); |
1929 | + SDL_JoystickClose(SDL_joylist[i].joy); |
1930 | + } |
1931 | +#endif |
1932 | + |
1933 | + if ( joystick->hwdata ) { |
1934 | +#ifndef NO_LOGICAL_JOYSTICKS |
1935 | + if (SDL_joylist[joystick->index].fname != NULL) |
1936 | +#endif |
1937 | + close(joystick->hwdata->fd); |
1938 | + if ( joystick->hwdata->hats ) { |
1939 | + SDL_free(joystick->hwdata->hats); |
1940 | + } |
1941 | + if ( joystick->hwdata->balls ) { |
1942 | + SDL_free(joystick->hwdata->balls); |
1943 | + } |
1944 | + SDL_free(joystick->hwdata); |
1945 | + joystick->hwdata = NULL; |
1946 | + } |
1947 | +} |
1948 | + |
1949 | +/* Function to perform any system-specific joystick related cleanup */ |
1950 | +void SDL_SYS_JoystickQuit(void) |
1951 | +{ |
1952 | + int i; |
1953 | + |
1954 | + for ( i=0; SDL_joylist[i].fname; ++i ) { |
1955 | + SDL_free(SDL_joylist[i].fname); |
1956 | + SDL_joylist[i].fname = NULL; |
1957 | + } |
1958 | +} |
1959 | + |
1960 | +#endif /* SDL_JOYSTICK_LINUX */ |
1961 | |
1962 | === added directory '.pc/fix_window_resizing.diff' |
1963 | === added directory '.pc/fix_window_resizing.diff/src' |
1964 | === added directory '.pc/fix_window_resizing.diff/src/video' |
1965 | === added directory '.pc/fix_window_resizing.diff/src/video/x11' |
1966 | === added file '.pc/fix_window_resizing.diff/src/video/x11/SDL_x11events.c' |
1967 | --- .pc/fix_window_resizing.diff/src/video/x11/SDL_x11events.c 1970-01-01 00:00:00 +0000 |
1968 | +++ .pc/fix_window_resizing.diff/src/video/x11/SDL_x11events.c 2015-06-01 21:40:05 +0000 |
1969 | @@ -0,0 +1,1423 @@ |
1970 | +/* |
1971 | + SDL - Simple DirectMedia Layer |
1972 | + Copyright (C) 1997-2012 Sam Lantinga |
1973 | + |
1974 | + This library is free software; you can redistribute it and/or |
1975 | + modify it under the terms of the GNU Lesser General Public |
1976 | + License as published by the Free Software Foundation; either |
1977 | + version 2.1 of the License, or (at your option) any later version. |
1978 | + |
1979 | + This library is distributed in the hope that it will be useful, |
1980 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
1981 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1982 | + Lesser General Public License for more details. |
1983 | + |
1984 | + You should have received a copy of the GNU Lesser General Public |
1985 | + License along with this library; if not, write to the Free Software |
1986 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
1987 | + |
1988 | + Sam Lantinga |
1989 | + slouken@libsdl.org |
1990 | +*/ |
1991 | +#include "SDL_config.h" |
1992 | + |
1993 | +/* Handle the event stream, converting X11 events into SDL events */ |
1994 | + |
1995 | +#include <setjmp.h> |
1996 | +#include <X11/Xlib.h> |
1997 | +#include <X11/Xutil.h> |
1998 | +#include <X11/keysym.h> |
1999 | +#ifdef __SVR4 |
2000 | +#include <X11/Sunkeysym.h> |
2001 | +#endif |
2002 | +#include <sys/types.h> |
2003 | +#include <sys/time.h> |
2004 | +#include <unistd.h> |
2005 | + |
2006 | +#include "SDL_timer.h" |
2007 | +#include "SDL_syswm.h" |
2008 | +#include "../SDL_sysvideo.h" |
2009 | +#include "../../events/SDL_sysevents.h" |
2010 | +#include "../../events/SDL_events_c.h" |
2011 | +#include "SDL_x11video.h" |
2012 | +#include "SDL_x11dga_c.h" |
2013 | +#include "SDL_x11modes_c.h" |
2014 | +#include "SDL_x11image_c.h" |
2015 | +#include "SDL_x11gamma_c.h" |
2016 | +#include "SDL_x11wm_c.h" |
2017 | +#include "SDL_x11mouse_c.h" |
2018 | +#include "SDL_x11events_c.h" |
2019 | + |
2020 | + |
2021 | +/* Define this if you want to debug X11 events */ |
2022 | +/*#define DEBUG_XEVENTS*/ |
2023 | + |
2024 | +/* The translation tables from an X11 keysym to a SDL keysym */ |
2025 | +static SDLKey ODD_keymap[256]; |
2026 | +static SDLKey MISC_keymap[256]; |
2027 | +SDLKey X11_TranslateKeycode(Display *display, KeyCode kc); |
2028 | + |
2029 | +/* |
2030 | + Pending resize target for ConfigureNotify (so outdated events don't |
2031 | + cause inappropriate resize events) |
2032 | +*/ |
2033 | +int X11_PendingConfigureNotifyWidth = -1; |
2034 | +int X11_PendingConfigureNotifyHeight = -1; |
2035 | + |
2036 | +#ifdef X_HAVE_UTF8_STRING |
2037 | +Uint32 Utf8ToUcs4(const Uint8 *utf8) |
2038 | +{ |
2039 | + Uint32 c; |
2040 | + int i = 1; |
2041 | + int noOctets = 0; |
2042 | + int firstOctetMask = 0; |
2043 | + unsigned char firstOctet = utf8[0]; |
2044 | + if (firstOctet < 0x80) { |
2045 | + /* |
2046 | + Characters in the range: |
2047 | + 00000000 to 01111111 (ASCII Range) |
2048 | + are stored in one octet: |
2049 | + 0xxxxxxx (The same as its ASCII representation) |
2050 | + The least 6 significant bits of the first octet is the most 6 significant nonzero bits |
2051 | + of the UCS4 representation. |
2052 | + */ |
2053 | + noOctets = 1; |
2054 | + firstOctetMask = 0x7F; /* 0(1111111) - The most significant bit is ignored */ |
2055 | + } else if ((firstOctet & 0xE0) /* get the most 3 significant bits by AND'ing with 11100000 */ |
2056 | + == 0xC0 ) { /* see if those 3 bits are 110. If so, the char is in this range */ |
2057 | + /* |
2058 | + Characters in the range: |
2059 | + 00000000 10000000 to 00000111 11111111 |
2060 | + are stored in two octets: |
2061 | + 110xxxxx 10xxxxxx |
2062 | + The least 5 significant bits of the first octet is the most 5 significant nonzero bits |
2063 | + of the UCS4 representation. |
2064 | + */ |
2065 | + noOctets = 2; |
2066 | + firstOctetMask = 0x1F; /* 000(11111) - The most 3 significant bits are ignored */ |
2067 | + } else if ((firstOctet & 0xF0) /* get the most 4 significant bits by AND'ing with 11110000 */ |
2068 | + == 0xE0) { /* see if those 4 bits are 1110. If so, the char is in this range */ |
2069 | + /* |
2070 | + Characters in the range: |
2071 | + 00001000 00000000 to 11111111 11111111 |
2072 | + are stored in three octets: |
2073 | + 1110xxxx 10xxxxxx 10xxxxxx |
2074 | + The least 4 significant bits of the first octet is the most 4 significant nonzero bits |
2075 | + of the UCS4 representation. |
2076 | + */ |
2077 | + noOctets = 3; |
2078 | + firstOctetMask = 0x0F; /* 0000(1111) - The most 4 significant bits are ignored */ |
2079 | + } else if ((firstOctet & 0xF8) /* get the most 5 significant bits by AND'ing with 11111000 */ |
2080 | + == 0xF0) { /* see if those 5 bits are 11110. If so, the char is in this range */ |
2081 | + /* |
2082 | + Characters in the range: |
2083 | + 00000001 00000000 00000000 to 00011111 11111111 11111111 |
2084 | + are stored in four octets: |
2085 | + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
2086 | + The least 3 significant bits of the first octet is the most 3 significant nonzero bits |
2087 | + of the UCS4 representation. |
2088 | + */ |
2089 | + noOctets = 4; |
2090 | + firstOctetMask = 0x07; /* 11110(111) - The most 5 significant bits are ignored */ |
2091 | + } else if ((firstOctet & 0xFC) /* get the most 6 significant bits by AND'ing with 11111100 */ |
2092 | + == 0xF8) { /* see if those 6 bits are 111110. If so, the char is in this range */ |
2093 | + /* |
2094 | + Characters in the range: |
2095 | + 00000000 00100000 00000000 00000000 to |
2096 | + 00000011 11111111 11111111 11111111 |
2097 | + are stored in five octets: |
2098 | + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
2099 | + The least 2 significant bits of the first octet is the most 2 significant nonzero bits |
2100 | + of the UCS4 representation. |
2101 | + */ |
2102 | + noOctets = 5; |
2103 | + firstOctetMask = 0x03; /* 111110(11) - The most 6 significant bits are ignored */ |
2104 | + } else if ((firstOctet & 0xFE) /* get the most 7 significant bits by AND'ing with 11111110 */ |
2105 | + == 0xFC) { /* see if those 7 bits are 1111110. If so, the char is in this range */ |
2106 | + /* |
2107 | + Characters in the range: |
2108 | + 00000100 00000000 00000000 00000000 to |
2109 | + 01111111 11111111 11111111 11111111 |
2110 | + are stored in six octets: |
2111 | + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
2112 | + The least significant bit of the first octet is the most significant nonzero bit |
2113 | + of the UCS4 representation. |
2114 | + */ |
2115 | + noOctets = 6; |
2116 | + firstOctetMask = 0x01; /* 1111110(1) - The most 7 significant bits are ignored */ |
2117 | + } else |
2118 | + return 0; /* The given chunk is not a valid UTF-8 encoded Unicode character */ |
2119 | + |
2120 | + /* |
2121 | + The least noOctets significant bits of the first octet is the most 2 significant nonzero bits |
2122 | + of the UCS4 representation. |
2123 | + The first 6 bits of the UCS4 representation is the least 8-noOctets-1 significant bits of |
2124 | + firstOctet if the character is not ASCII. If so, it's the least 7 significant bits of firstOctet. |
2125 | + This done by AND'ing firstOctet with its mask to trim the bits used for identifying the |
2126 | + number of continuing octets (if any) and leave only the free bits (the x's) |
2127 | + Sample: |
2128 | + 1-octet: 0xxxxxxx & 01111111 = 0xxxxxxx |
2129 | + 2-octets: 110xxxxx & 00011111 = 000xxxxx |
2130 | + */ |
2131 | + c = firstOctet & firstOctetMask; |
2132 | + |
2133 | + /* Now, start filling c.ucs4 with the bits from the continuing octets from utf8. */ |
2134 | + for (i = 1; i < noOctets; i++) { |
2135 | + /* A valid continuing octet is of the form 10xxxxxx */ |
2136 | + if ((utf8[i] & 0xC0) /* get the most 2 significant bits by AND'ing with 11000000 */ |
2137 | + != 0x80) /* see if those 2 bits are 10. If not, the is a malformed sequence. */ |
2138 | + /*The given chunk is a partial sequence at the end of a string that could |
2139 | + begin a valid character */ |
2140 | + return 0; |
2141 | + |
2142 | + /* Make room for the next 6-bits */ |
2143 | + c <<= 6; |
2144 | + |
2145 | + /* |
2146 | + Take only the least 6 significance bits of the current octet (utf8[i]) and fill the created room |
2147 | + of c.ucs4 with them. |
2148 | + This done by AND'ing utf8[i] with 00111111 and the OR'ing the result with c.ucs4. |
2149 | + */ |
2150 | + c |= utf8[i] & 0x3F; |
2151 | + } |
2152 | + return c; |
2153 | +} |
2154 | + |
2155 | +/* Given a UTF-8 encoded string pointed to by utf8 of length length in |
2156 | + bytes, returns the corresponding UTF-16 encoded string in the |
2157 | + buffer pointed to by utf16. The maximum number of UTF-16 encoding |
2158 | + units (i.e., Unit16s) allowed in the buffer is specified in |
2159 | + utf16_max_length. The return value is the number of UTF-16 |
2160 | + encoding units placed in the output buffer pointed to by utf16. |
2161 | + |
2162 | + In case of an error, -1 is returned, leaving some unusable partial |
2163 | + results in the output buffer. |
2164 | + |
2165 | + The caller must estimate the size of utf16 buffer by itself before |
2166 | + calling this function. Insufficient output buffer is considered as |
2167 | + an error, and once an error occured, this function doesn't give any |
2168 | + clue how large the result will be. |
2169 | + |
2170 | + The error cases include following: |
2171 | + |
2172 | + - Invalid byte sequences were in the input UTF-8 bytes. The caller |
2173 | + has no way to know what point in the input buffer was the |
2174 | + errornous byte. |
2175 | + |
2176 | + - The input contained a character (a valid UTF-8 byte sequence) |
2177 | + whose scalar value exceeded the range that UTF-16 can represent |
2178 | + (i.e., characters whose Unicode scalar value above 0x110000). |
2179 | + |
2180 | + - The output buffer has no enough space to hold entire utf16 data. |
2181 | + |
2182 | + Please note: |
2183 | + |
2184 | + - '\0'-termination is not assumed both on the input UTF-8 string |
2185 | + and on the output UTF-16 string; any legal zero byte in the input |
2186 | + UTF-8 string will be converted to a 16-bit zero in output. As a |
2187 | + side effect, the last UTF-16 encoding unit stored in the output |
2188 | + buffer will have a non-zero value if the input UTF-8 was not |
2189 | + '\0'-terminated. |
2190 | + |
2191 | + - UTF-8 aliases are *not* considered as an error. They are |
2192 | + converted to UTF-16. For example, 0xC0 0xA0, 0xE0 0x80 0xA0, |
2193 | + and 0xF0 0x80 0x80 0xA0 are all mapped to a single UTF-16 |
2194 | + encoding unit 0x0020. |
2195 | + |
2196 | + - Three byte UTF-8 sequences whose value corresponds to a surrogate |
2197 | + code or other reserved scalar value are not considered as an |
2198 | + error either. They may cause an invalid UTF-16 data (e.g., those |
2199 | + containing unpaired surrogates). |
2200 | + |
2201 | +*/ |
2202 | + |
2203 | +static int Utf8ToUtf16(const Uint8 *utf8, const int utf8_length, Uint16 *utf16, const int utf16_max_length) { |
2204 | + |
2205 | + /* p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. */ |
2206 | + Uint16 *p = utf16; |
2207 | + Uint16 const *const max_ptr = utf16 + utf16_max_length; |
2208 | + |
2209 | + /* end_of_input points to the last byte of input as opposed to the next to the last byte. */ |
2210 | + Uint8 const *const end_of_input = utf8 + utf8_length - 1; |
2211 | + |
2212 | + while (utf8 <= end_of_input) { |
2213 | + Uint8 const c = *utf8; |
2214 | + if (p >= max_ptr) { |
2215 | + /* No more output space. */ |
2216 | + return -1; |
2217 | + } |
2218 | + if (c < 0x80) { |
2219 | + /* One byte ASCII. */ |
2220 | + *p++ = c; |
2221 | + utf8 += 1; |
2222 | + } else if (c < 0xC0) { |
2223 | + /* Follower byte without preceeding leader bytes. */ |
2224 | + return -1; |
2225 | + } else if (c < 0xE0) { |
2226 | + /* Two byte sequence. We need one follower byte. */ |
2227 | + if (end_of_input - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) { |
2228 | + return -1; |
2229 | + } |
2230 | + *p++ = (Uint16)(0xCF80 + (c << 6) + utf8[1]); |
2231 | + utf8 += 2; |
2232 | + } else if (c < 0xF0) { |
2233 | + /* Three byte sequence. We need two follower byte. */ |
2234 | + if (end_of_input - utf8 < 2 || (((utf8[1] ^ 0x80) | (utf8[2] ^ 0x80)) & 0xC0)) { |
2235 | + return -1; |
2236 | + } |
2237 | + *p++ = (Uint16)(0xDF80 + (c << 12) + (utf8[1] << 6) + utf8[2]); |
2238 | + utf8 += 3; |
2239 | + } else if (c < 0xF8) { |
2240 | + int plane; |
2241 | + /* Four byte sequence. We need three follower bytes. */ |
2242 | + if (end_of_input - utf8 < 3 || (((utf8[1] ^ 0x80) | (utf8[2] ^0x80) | (utf8[3] ^ 0x80)) & 0xC0)) { |
2243 | + return -1; |
2244 | + } |
2245 | + plane = (-0xC8 + (c << 2) + (utf8[1] >> 4)); |
2246 | + if (plane == 0) { |
2247 | + /* This four byte sequence is an alias that |
2248 | + corresponds to a Unicode scalar value in BMP. |
2249 | + It fits in an UTF-16 encoding unit. */ |
2250 | + *p++ = (Uint16)(0xDF80 + (utf8[1] << 12) + (utf8[2] << 6) + utf8[3]); |
2251 | + } else if (plane <= 16) { |
2252 | + /* This is a legal four byte sequence that corresponds to a surrogate pair. */ |
2253 | + if (p + 1 >= max_ptr) { |
2254 | + /* No enough space on the output buffer for the pair. */ |
2255 | + return -1; |
2256 | + } |
2257 | + *p++ = (Uint16)(0xE5B8 + (c << 8) + (utf8[1] << 2) + (utf8[2] >> 4)); |
2258 | + *p++ = (Uint16)(0xDB80 + ((utf8[2] & 0x0F) << 6) + utf8[3]); |
2259 | + } else { |
2260 | + /* This four byte sequence is out of UTF-16 code space. */ |
2261 | + return -1; |
2262 | + } |
2263 | + utf8 += 4; |
2264 | + } else { |
2265 | + /* Longer sequence or unused byte. */ |
2266 | + return -1; |
2267 | + } |
2268 | + } |
2269 | + return p - utf16; |
2270 | +} |
2271 | + |
2272 | +#endif |
2273 | + |
2274 | +/* Check to see if this is a repeated key. |
2275 | + (idea shamelessly lifted from GII -- thanks guys! :) |
2276 | + */ |
2277 | +static int X11_KeyRepeat(Display *display, XEvent *event) |
2278 | +{ |
2279 | + XEvent peekevent; |
2280 | + int repeated; |
2281 | + |
2282 | + repeated = 0; |
2283 | + if ( XPending(display) ) { |
2284 | + XPeekEvent(display, &peekevent); |
2285 | + if ( (peekevent.type == KeyPress) && |
2286 | + (peekevent.xkey.keycode == event->xkey.keycode) && |
2287 | + ((peekevent.xkey.time-event->xkey.time) < 2) ) { |
2288 | + repeated = 1; |
2289 | + XNextEvent(display, &peekevent); |
2290 | + } |
2291 | + } |
2292 | + return(repeated); |
2293 | +} |
2294 | + |
2295 | +/* Note: The X server buffers and accumulates mouse motion events, so |
2296 | + the motion event generated by the warp may not appear exactly as we |
2297 | + expect it to. We work around this (and improve performance) by only |
2298 | + warping the pointer when it reaches the edge, and then wait for it. |
2299 | +*/ |
2300 | +#define MOUSE_FUDGE_FACTOR 8 |
2301 | + |
2302 | +static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent) |
2303 | +{ |
2304 | + int w, h, i; |
2305 | + int deltax, deltay; |
2306 | + int posted; |
2307 | + |
2308 | + w = SDL_VideoSurface->w; |
2309 | + h = SDL_VideoSurface->h; |
2310 | + deltax = xevent->xmotion.x - mouse_last.x; |
2311 | + deltay = xevent->xmotion.y - mouse_last.y; |
2312 | +#ifdef DEBUG_MOTION |
2313 | + printf("Warped mouse motion: %d,%d\n", deltax, deltay); |
2314 | +#endif |
2315 | + mouse_last.x = xevent->xmotion.x; |
2316 | + mouse_last.y = xevent->xmotion.y; |
2317 | + posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay); |
2318 | + |
2319 | + if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) || |
2320 | + (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) || |
2321 | + (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) || |
2322 | + (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) { |
2323 | + /* Get the events that have accumulated */ |
2324 | + while ( XCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) { |
2325 | + deltax = xevent->xmotion.x - mouse_last.x; |
2326 | + deltay = xevent->xmotion.y - mouse_last.y; |
2327 | +#ifdef DEBUG_MOTION |
2328 | + printf("Extra mouse motion: %d,%d\n", deltax, deltay); |
2329 | +#endif |
2330 | + mouse_last.x = xevent->xmotion.x; |
2331 | + mouse_last.y = xevent->xmotion.y; |
2332 | + posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay); |
2333 | + } |
2334 | + mouse_last.x = w/2; |
2335 | + mouse_last.y = h/2; |
2336 | + XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0, |
2337 | + mouse_last.x, mouse_last.y); |
2338 | + for ( i=0; i<10; ++i ) { |
2339 | + XMaskEvent(SDL_Display, PointerMotionMask, xevent); |
2340 | + if ( (xevent->xmotion.x > |
2341 | + (mouse_last.x-MOUSE_FUDGE_FACTOR)) && |
2342 | + (xevent->xmotion.x < |
2343 | + (mouse_last.x+MOUSE_FUDGE_FACTOR)) && |
2344 | + (xevent->xmotion.y > |
2345 | + (mouse_last.y-MOUSE_FUDGE_FACTOR)) && |
2346 | + (xevent->xmotion.y < |
2347 | + (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) { |
2348 | + break; |
2349 | + } |
2350 | +#ifdef DEBUG_XEVENTS |
2351 | + printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y); |
2352 | +#endif |
2353 | + } |
2354 | +#ifdef DEBUG_XEVENTS |
2355 | + if ( i == 10 ) { |
2356 | + printf("Warning: didn't detect mouse warp motion\n"); |
2357 | + } |
2358 | +#endif |
2359 | + } |
2360 | + return(posted); |
2361 | +} |
2362 | + |
2363 | +static int X11_DispatchEvent(_THIS) |
2364 | +{ |
2365 | + int posted; |
2366 | + XEvent xevent; |
2367 | + |
2368 | + SDL_memset(&xevent, '\0', sizeof (XEvent)); /* valgrind fix. --ryan. */ |
2369 | + XNextEvent(SDL_Display, &xevent); |
2370 | + |
2371 | + /* Discard KeyRelease and KeyPress events generated by auto-repeat. |
2372 | + We need to do it before passing event to XFilterEvent. Otherwise, |
2373 | + KeyRelease aware IMs are confused... */ |
2374 | + if ( xevent.type == KeyRelease |
2375 | + && X11_KeyRepeat(SDL_Display, &xevent) ) { |
2376 | + return 0; |
2377 | + } |
2378 | + |
2379 | +#ifdef X_HAVE_UTF8_STRING |
2380 | + /* If we are translating with IM, we need to pass all events |
2381 | + to XFilterEvent, and discard those filtered events immediately. */ |
2382 | + if ( SDL_TranslateUNICODE |
2383 | + && SDL_IM != NULL |
2384 | + && XFilterEvent(&xevent, None) ) { |
2385 | + return 0; |
2386 | + } |
2387 | +#endif |
2388 | + |
2389 | + posted = 0; |
2390 | + switch (xevent.type) { |
2391 | + |
2392 | + /* Gaining mouse coverage? */ |
2393 | + case EnterNotify: { |
2394 | +#ifdef DEBUG_XEVENTS |
2395 | +printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y); |
2396 | +if ( xevent.xcrossing.mode == NotifyGrab ) |
2397 | +printf("Mode: NotifyGrab\n"); |
2398 | +if ( xevent.xcrossing.mode == NotifyUngrab ) |
2399 | +printf("Mode: NotifyUngrab\n"); |
2400 | +#endif |
2401 | + if ( this->input_grab == SDL_GRAB_OFF ) { |
2402 | + posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); |
2403 | + } |
2404 | + posted = SDL_PrivateMouseMotion(0, 0, |
2405 | + xevent.xcrossing.x, |
2406 | + xevent.xcrossing.y); |
2407 | + } |
2408 | + break; |
2409 | + |
2410 | + /* Losing mouse coverage? */ |
2411 | + case LeaveNotify: { |
2412 | +#ifdef DEBUG_XEVENTS |
2413 | +printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y); |
2414 | +if ( xevent.xcrossing.mode == NotifyGrab ) |
2415 | +printf("Mode: NotifyGrab\n"); |
2416 | +if ( xevent.xcrossing.mode == NotifyUngrab ) |
2417 | +printf("Mode: NotifyUngrab\n"); |
2418 | +#endif |
2419 | + if ( (xevent.xcrossing.mode != NotifyGrab) && |
2420 | + (xevent.xcrossing.mode != NotifyUngrab) && |
2421 | + (xevent.xcrossing.detail != NotifyInferior) ) { |
2422 | + if ( this->input_grab == SDL_GRAB_OFF ) { |
2423 | + posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); |
2424 | + } else { |
2425 | + posted = SDL_PrivateMouseMotion(0, 0, |
2426 | + xevent.xcrossing.x, |
2427 | + xevent.xcrossing.y); |
2428 | + } |
2429 | + } |
2430 | + } |
2431 | + break; |
2432 | + |
2433 | + /* Gaining input focus? */ |
2434 | + case FocusIn: { |
2435 | +#ifdef DEBUG_XEVENTS |
2436 | +printf("FocusIn!\n"); |
2437 | +#endif |
2438 | + posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS); |
2439 | + |
2440 | +#ifdef X_HAVE_UTF8_STRING |
2441 | + if ( SDL_IC != NULL ) { |
2442 | + XSetICFocus(SDL_IC); |
2443 | + } |
2444 | +#endif |
2445 | + /* Queue entry into fullscreen mode */ |
2446 | + switch_waiting = 0x01 | SDL_FULLSCREEN; |
2447 | + switch_time = SDL_GetTicks() + 1500; |
2448 | + } |
2449 | + break; |
2450 | + |
2451 | + /* Losing input focus? */ |
2452 | + case FocusOut: { |
2453 | +#ifdef DEBUG_XEVENTS |
2454 | +printf("FocusOut!\n"); |
2455 | +#endif |
2456 | + posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS); |
2457 | + |
2458 | +#ifdef X_HAVE_UTF8_STRING |
2459 | + if ( SDL_IC != NULL ) { |
2460 | + XUnsetICFocus(SDL_IC); |
2461 | + } |
2462 | +#endif |
2463 | + /* Queue leaving fullscreen mode */ |
2464 | + switch_waiting = 0x01; |
2465 | + switch_time = SDL_GetTicks() + 200; |
2466 | + } |
2467 | + break; |
2468 | + |
2469 | +#ifdef X_HAVE_UTF8_STRING |
2470 | + /* Some IM requires MappingNotify to be passed to |
2471 | + XRefreshKeyboardMapping by the app. */ |
2472 | + case MappingNotify: { |
2473 | + XRefreshKeyboardMapping(&xevent.xmapping); |
2474 | + } |
2475 | + break; |
2476 | +#endif /* X_HAVE_UTF8_STRING */ |
2477 | + |
2478 | + /* Generated upon EnterWindow and FocusIn */ |
2479 | + case KeymapNotify: { |
2480 | +#ifdef DEBUG_XEVENTS |
2481 | +printf("KeymapNotify!\n"); |
2482 | +#endif |
2483 | + X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector); |
2484 | + } |
2485 | + break; |
2486 | + |
2487 | + /* Mouse motion? */ |
2488 | + case MotionNotify: { |
2489 | + if ( SDL_VideoSurface ) { |
2490 | + if ( mouse_relative ) { |
2491 | + if ( using_dga & DGA_MOUSE ) { |
2492 | +#ifdef DEBUG_MOTION |
2493 | + printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root); |
2494 | +#endif |
2495 | + posted = SDL_PrivateMouseMotion(0, 1, |
2496 | + xevent.xmotion.x_root, |
2497 | + xevent.xmotion.y_root); |
2498 | + } else { |
2499 | + posted = X11_WarpedMotion(this,&xevent); |
2500 | + } |
2501 | + } else { |
2502 | +#ifdef DEBUG_MOTION |
2503 | + printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y); |
2504 | +#endif |
2505 | + posted = SDL_PrivateMouseMotion(0, 0, |
2506 | + xevent.xmotion.x, |
2507 | + xevent.xmotion.y); |
2508 | + } |
2509 | + } |
2510 | + } |
2511 | + break; |
2512 | + |
2513 | + /* Mouse button press? */ |
2514 | + case ButtonPress: { |
2515 | + posted = SDL_PrivateMouseButton(SDL_PRESSED, |
2516 | + xevent.xbutton.button, 0, 0); |
2517 | + } |
2518 | + break; |
2519 | + |
2520 | + /* Mouse button release? */ |
2521 | + case ButtonRelease: { |
2522 | + posted = SDL_PrivateMouseButton(SDL_RELEASED, |
2523 | + xevent.xbutton.button, 0, 0); |
2524 | + } |
2525 | + break; |
2526 | + |
2527 | + /* Key press? */ |
2528 | + case KeyPress: { |
2529 | + SDL_keysym keysym; |
2530 | + KeyCode keycode = xevent.xkey.keycode; |
2531 | + |
2532 | +#ifdef DEBUG_XEVENTS |
2533 | +printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode); |
2534 | +#endif |
2535 | + /* If we're not doing translation, we're done! */ |
2536 | + if ( !SDL_TranslateUNICODE ) { |
2537 | + /* Get the translated SDL virtual keysym and put it on the queue.*/ |
2538 | + keysym.scancode = keycode; |
2539 | + keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); |
2540 | + keysym.mod = KMOD_NONE; |
2541 | + keysym.unicode = 0; |
2542 | + posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); |
2543 | + break; |
2544 | + } |
2545 | + |
2546 | + /* Look up the translated value for the key event */ |
2547 | +#ifdef X_HAVE_UTF8_STRING |
2548 | + if ( SDL_IC != NULL ) { |
2549 | + Status status; |
2550 | + KeySym xkeysym; |
2551 | + int i; |
2552 | + /* A UTF-8 character can be at most 6 bytes */ |
2553 | + /* ... It's true, but Xutf8LookupString can |
2554 | + return more than one characters. Moreover, |
2555 | + the spec. put no upper bound, so we should |
2556 | + be ready for longer strings. */ |
2557 | + char keybuf[32]; |
2558 | + char *keydata = keybuf; |
2559 | + int count; |
2560 | + Uint16 utf16buf[32]; |
2561 | + Uint16 *utf16data = utf16buf; |
2562 | + int utf16size; |
2563 | + int utf16length; |
2564 | + |
2565 | + count = Xutf8LookupString(SDL_IC, &xevent.xkey, keydata, sizeof(keybuf), &xkeysym, &status); |
2566 | + if (XBufferOverflow == status) { |
2567 | + /* The IM has just generated somewhat long |
2568 | + string. We need a longer buffer in this |
2569 | + case. */ |
2570 | + keydata = SDL_malloc(count); |
2571 | + if ( keydata == NULL ) { |
2572 | + SDL_OutOfMemory(); |
2573 | + break; |
2574 | + } |
2575 | + count = Xutf8LookupString(SDL_IC, &xevent.xkey, keydata, count, &xkeysym, &status); |
2576 | + } |
2577 | + |
2578 | + switch (status) { |
2579 | + |
2580 | + case XBufferOverflow: { |
2581 | + /* Oops! We have allocated the bytes as |
2582 | + requested by Xutf8LookupString, so the |
2583 | + length of the buffer must be |
2584 | + sufficient. This case should never |
2585 | + happen! */ |
2586 | + SDL_SetError("Xutf8LookupString indicated a double buffer overflow!"); |
2587 | + break; |
2588 | + } |
2589 | + |
2590 | + case XLookupChars: |
2591 | + case XLookupBoth: { |
2592 | + if (0 == count) { |
2593 | + break; |
2594 | + } |
2595 | + |
2596 | + /* We got a converted string from IM. Make |
2597 | + sure to deliver all characters to the |
2598 | + application as SDL events. Note that |
2599 | + an SDL event can only carry one UTF-16 |
2600 | + encoding unit, and a surrogate pair is |
2601 | + delivered as two SDL events. I guess |
2602 | + this behaviour is probably _imported_ |
2603 | + from Windows or MacOS. To do so, we need |
2604 | + to convert the UTF-8 data into UTF-16 |
2605 | + data (not UCS4/UTF-32!). We need an |
2606 | + estimate of the number of UTF-16 encoding |
2607 | + units here. The worst case is pure ASCII |
2608 | + string. Assume so. */ |
2609 | + /* In 1.3 SDL may have a text event instead, that |
2610 | + carries the whole UTF-8 string with it. */ |
2611 | + utf16size = count * sizeof(Uint16); |
2612 | + if (utf16size > sizeof(utf16buf)) { |
2613 | + utf16data = (Uint16 *) SDL_malloc(utf16size); |
2614 | + if (utf16data == NULL) { |
2615 | + SDL_OutOfMemory(); |
2616 | + break; |
2617 | + } |
2618 | + } |
2619 | + utf16length = Utf8ToUtf16((Uint8 *)keydata, count, utf16data, utf16size); |
2620 | + if (utf16length < 0) { |
2621 | + /* The keydata contained an invalid byte |
2622 | + sequence. It should be a bug of the IM |
2623 | + or Xlib... */ |
2624 | + SDL_SetError("Oops! Xutf8LookupString returned an invalid UTF-8 sequence!"); |
2625 | + break; |
2626 | + } |
2627 | + |
2628 | + /* Deliver all UTF-16 encoding units. At |
2629 | + this moment, SDL event queue has a |
2630 | + fixed size (128 events), and an SDL |
2631 | + event can hold just one UTF-16 encoding |
2632 | + unit. So, if we receive more than 128 |
2633 | + UTF-16 encoding units from a commit, |
2634 | + exceeded characters will be lost. */ |
2635 | + for (i = 0; i < utf16length - 1; i++) { |
2636 | + keysym.scancode = 0; |
2637 | + keysym.sym = SDLK_UNKNOWN; |
2638 | + keysym.mod = KMOD_NONE; |
2639 | + keysym.unicode = utf16data[i]; |
2640 | + posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); |
2641 | + } |
2642 | + /* The keysym for the last character carries the |
2643 | + scancode and symbol that corresponds to the X11 |
2644 | + keycode. */ |
2645 | + if (utf16length > 0) { |
2646 | + keysym.scancode = keycode; |
2647 | + keysym.sym = (keycode ? X11_TranslateKeycode(SDL_Display, keycode) : 0); |
2648 | + keysym.mod = KMOD_NONE; |
2649 | + keysym.unicode = utf16data[utf16length - 1]; |
2650 | + posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); |
2651 | + } |
2652 | + break; |
2653 | + } |
2654 | + |
2655 | + case XLookupKeySym: { |
2656 | + /* I'm not sure whether it is possible that |
2657 | + a zero keycode makes XLookupKeySym |
2658 | + status. What I'm sure is that a |
2659 | + combination of a zero scan code and a non |
2660 | + zero sym makes SDL_PrivateKeyboard |
2661 | + strange state... So, just discard it. |
2662 | + If this doesn't work, I'm receiving bug |
2663 | + reports, and I can know under what |
2664 | + condition this case happens. */ |
2665 | + if (keycode) { |
2666 | + keysym.scancode = keycode; |
2667 | + keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); |
2668 | + keysym.mod = KMOD_NONE; |
2669 | + keysym.unicode = 0; |
2670 | + posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); |
2671 | + } |
2672 | + break; |
2673 | + } |
2674 | + |
2675 | + case XLookupNone: { |
2676 | + /* IM has eaten the event. */ |
2677 | + break; |
2678 | + } |
2679 | + |
2680 | + default: |
2681 | + /* An unknown status from Xutf8LookupString. */ |
2682 | + SDL_SetError("Oops! Xutf8LookupStringreturned an unknown status"); |
2683 | + } |
2684 | + |
2685 | + /* Release dynamic buffers if allocated. */ |
2686 | + if (keydata != NULL && keybuf != keydata) { |
2687 | + SDL_free(keydata); |
2688 | + } |
2689 | + if (utf16data != NULL && utf16buf != utf16data) { |
2690 | + SDL_free(utf16data); |
2691 | + } |
2692 | + } |
2693 | + else |
2694 | +#endif |
2695 | + { |
2696 | + static XComposeStatus state; |
2697 | + char keybuf[32]; |
2698 | + |
2699 | + keysym.scancode = keycode; |
2700 | + keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); |
2701 | + keysym.mod = KMOD_NONE; |
2702 | + keysym.unicode = 0; |
2703 | + if ( XLookupString(&xevent.xkey, |
2704 | + keybuf, sizeof(keybuf), |
2705 | + NULL, &state) ) { |
2706 | + /* |
2707 | + * FIXME: XLookupString() may yield more than one |
2708 | + * character, so we need a mechanism to allow for |
2709 | + * this (perhaps null keypress events with a |
2710 | + * unicode value) |
2711 | + */ |
2712 | + keysym.unicode = (Uint8)keybuf[0]; |
2713 | + } |
2714 | + |
2715 | + posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); |
2716 | + } |
2717 | + } |
2718 | + break; |
2719 | + |
2720 | + /* Key release? */ |
2721 | + case KeyRelease: { |
2722 | + SDL_keysym keysym; |
2723 | + KeyCode keycode = xevent.xkey.keycode; |
2724 | + |
2725 | + if (keycode == 0) { |
2726 | + /* There should be no KeyRelease for keycode == 0, |
2727 | + since it is a notification from IM but a real |
2728 | + keystroke. */ |
2729 | + /* We need to emit some diagnostic message here. */ |
2730 | + break; |
2731 | + } |
2732 | + |
2733 | +#ifdef DEBUG_XEVENTS |
2734 | +printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode); |
2735 | +#endif |
2736 | + |
2737 | + /* Get the translated SDL virtual keysym */ |
2738 | + keysym.scancode = keycode; |
2739 | + keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); |
2740 | + keysym.mod = KMOD_NONE; |
2741 | + keysym.unicode = 0; |
2742 | + |
2743 | + posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym); |
2744 | + } |
2745 | + break; |
2746 | + |
2747 | + /* Have we been iconified? */ |
2748 | + case UnmapNotify: { |
2749 | +#ifdef DEBUG_XEVENTS |
2750 | +printf("UnmapNotify!\n"); |
2751 | +#endif |
2752 | + /* If we're active, make ourselves inactive */ |
2753 | + if ( SDL_GetAppState() & SDL_APPACTIVE ) { |
2754 | + /* Swap out the gamma before we go inactive */ |
2755 | + X11_SwapVidModeGamma(this); |
2756 | + |
2757 | + /* Send an internal deactivate event */ |
2758 | + posted = SDL_PrivateAppActive(0, |
2759 | + SDL_APPACTIVE|SDL_APPINPUTFOCUS); |
2760 | + } |
2761 | + } |
2762 | + break; |
2763 | + |
2764 | + /* Have we been restored? */ |
2765 | + case MapNotify: { |
2766 | +#ifdef DEBUG_XEVENTS |
2767 | +printf("MapNotify!\n"); |
2768 | +#endif |
2769 | + /* If we're not active, make ourselves active */ |
2770 | + if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) { |
2771 | + /* Send an internal activate event */ |
2772 | + posted = SDL_PrivateAppActive(1, SDL_APPACTIVE); |
2773 | + |
2774 | + /* Now that we're active, swap the gamma back */ |
2775 | + X11_SwapVidModeGamma(this); |
2776 | + } |
2777 | + |
2778 | + if ( SDL_VideoSurface && |
2779 | + (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) { |
2780 | + X11_EnterFullScreen(this); |
2781 | + } else { |
2782 | + X11_GrabInputNoLock(this, this->input_grab); |
2783 | + } |
2784 | + X11_CheckMouseModeNoLock(this); |
2785 | + |
2786 | + if ( SDL_VideoSurface ) { |
2787 | + X11_RefreshDisplay(this); |
2788 | + } |
2789 | + } |
2790 | + break; |
2791 | + |
2792 | + /* Have we been resized or moved? */ |
2793 | + case ConfigureNotify: { |
2794 | +#ifdef DEBUG_XEVENTS |
2795 | +printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height); |
2796 | +#endif |
2797 | + if ((X11_PendingConfigureNotifyWidth != -1) && |
2798 | + (X11_PendingConfigureNotifyHeight != -1)) { |
2799 | + if ((xevent.xconfigure.width != X11_PendingConfigureNotifyWidth) && |
2800 | + (xevent.xconfigure.height != X11_PendingConfigureNotifyHeight)) { |
2801 | + /* Event is from before the resize, so ignore. */ |
2802 | + break; |
2803 | + } |
2804 | + X11_PendingConfigureNotifyWidth = -1; |
2805 | + X11_PendingConfigureNotifyHeight = -1; |
2806 | + } |
2807 | + if ( SDL_VideoSurface ) { |
2808 | + if ((xevent.xconfigure.width != SDL_VideoSurface->w) || |
2809 | + (xevent.xconfigure.height != SDL_VideoSurface->h)) { |
2810 | + /* FIXME: Find a better fix for the bug with KDE 1.2 */ |
2811 | + if ( ! ((xevent.xconfigure.width == 32) && |
2812 | + (xevent.xconfigure.height == 32)) ) { |
2813 | + SDL_PrivateResize(xevent.xconfigure.width, |
2814 | + xevent.xconfigure.height); |
2815 | + } |
2816 | + } else { |
2817 | + /* OpenGL windows need to know about the change */ |
2818 | + if ( SDL_VideoSurface->flags & SDL_OPENGL ) { |
2819 | + SDL_PrivateExpose(); |
2820 | + } |
2821 | + } |
2822 | + } |
2823 | + } |
2824 | + break; |
2825 | + |
2826 | + /* Have we been requested to quit (or another client message?) */ |
2827 | + case ClientMessage: { |
2828 | + if ( (xevent.xclient.format == 32) && |
2829 | + (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) ) |
2830 | + { |
2831 | + posted = SDL_PrivateQuit(); |
2832 | + } else |
2833 | + if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) { |
2834 | + SDL_SysWMmsg wmmsg; |
2835 | + |
2836 | + SDL_VERSION(&wmmsg.version); |
2837 | + wmmsg.subsystem = SDL_SYSWM_X11; |
2838 | + wmmsg.event.xevent = xevent; |
2839 | + posted = SDL_PrivateSysWMEvent(&wmmsg); |
2840 | + } |
2841 | + } |
2842 | + break; |
2843 | + |
2844 | + /* Do we need to refresh ourselves? */ |
2845 | + case Expose: { |
2846 | +#ifdef DEBUG_XEVENTS |
2847 | +printf("Expose (count = %d)\n", xevent.xexpose.count); |
2848 | +#endif |
2849 | + if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) { |
2850 | + X11_RefreshDisplay(this); |
2851 | + } |
2852 | + } |
2853 | + break; |
2854 | + |
2855 | + default: { |
2856 | +#ifdef DEBUG_XEVENTS |
2857 | +printf("Unhandled event %d\n", xevent.type); |
2858 | +#endif |
2859 | + /* Only post the event if we're watching for it */ |
2860 | + if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) { |
2861 | + SDL_SysWMmsg wmmsg; |
2862 | + |
2863 | + SDL_VERSION(&wmmsg.version); |
2864 | + wmmsg.subsystem = SDL_SYSWM_X11; |
2865 | + wmmsg.event.xevent = xevent; |
2866 | + posted = SDL_PrivateSysWMEvent(&wmmsg); |
2867 | + } |
2868 | + } |
2869 | + break; |
2870 | + } |
2871 | + return(posted); |
2872 | +} |
2873 | + |
2874 | +/* Ack! XPending() actually performs a blocking read if no events available */ |
2875 | +int X11_Pending(Display *display) |
2876 | +{ |
2877 | + /* Flush the display connection and look to see if events are queued */ |
2878 | + XFlush(display); |
2879 | + if ( XEventsQueued(display, QueuedAlready) ) { |
2880 | + return(1); |
2881 | + } |
2882 | + |
2883 | + /* More drastic measures are required -- see if X is ready to talk */ |
2884 | + { |
2885 | + static struct timeval zero_time; /* static == 0 */ |
2886 | + int x11_fd; |
2887 | + fd_set fdset; |
2888 | + |
2889 | + x11_fd = ConnectionNumber(display); |
2890 | + FD_ZERO(&fdset); |
2891 | + FD_SET(x11_fd, &fdset); |
2892 | + if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) { |
2893 | + return(XPending(display)); |
2894 | + } |
2895 | + } |
2896 | + |
2897 | + /* Oh well, nothing is ready .. */ |
2898 | + return(0); |
2899 | +} |
2900 | + |
2901 | +void X11_PumpEvents(_THIS) |
2902 | +{ |
2903 | + int pending; |
2904 | + |
2905 | + /* Update activity every five seconds to prevent screensaver. --ryan. */ |
2906 | + if (!allow_screensaver) { |
2907 | + static Uint32 screensaverTicks; |
2908 | + Uint32 nowTicks = SDL_GetTicks(); |
2909 | + if ((nowTicks - screensaverTicks) > 5000) { |
2910 | + XResetScreenSaver(SDL_Display); |
2911 | + screensaverTicks = nowTicks; |
2912 | + } |
2913 | + } |
2914 | + |
2915 | + /* Keep processing pending events */ |
2916 | + pending = 0; |
2917 | + while ( X11_Pending(SDL_Display) ) { |
2918 | + X11_DispatchEvent(this); |
2919 | + ++pending; |
2920 | + } |
2921 | + if ( switch_waiting ) { |
2922 | + Uint32 now; |
2923 | + |
2924 | + now = SDL_GetTicks(); |
2925 | + if ( pending || !SDL_VideoSurface ) { |
2926 | + /* Try again later... */ |
2927 | + if ( switch_waiting & SDL_FULLSCREEN ) { |
2928 | + switch_time = now + 1500; |
2929 | + } else { |
2930 | + switch_time = now + 200; |
2931 | + } |
2932 | + } else if ( (int)(switch_time-now) <= 0 ) { |
2933 | + Uint32 go_fullscreen; |
2934 | + |
2935 | + go_fullscreen = switch_waiting & SDL_FULLSCREEN; |
2936 | + switch_waiting = 0; |
2937 | + if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) { |
2938 | + if ( go_fullscreen ) { |
2939 | + X11_EnterFullScreen(this); |
2940 | + } else { |
2941 | + X11_LeaveFullScreen(this); |
2942 | + } |
2943 | + } |
2944 | + /* Handle focus in/out when grabbed */ |
2945 | + if ( go_fullscreen ) { |
2946 | + X11_GrabInputNoLock(this, this->input_grab); |
2947 | + } else { |
2948 | + X11_GrabInputNoLock(this, SDL_GRAB_OFF); |
2949 | + } |
2950 | + X11_CheckMouseModeNoLock(this); |
2951 | + } |
2952 | + } |
2953 | +} |
2954 | + |
2955 | +void X11_InitKeymap(void) |
2956 | +{ |
2957 | + int i; |
2958 | + |
2959 | + /* Odd keys used in international keyboards */ |
2960 | + for ( i=0; i<SDL_arraysize(ODD_keymap); ++i ) |
2961 | + ODD_keymap[i] = SDLK_UNKNOWN; |
2962 | + |
2963 | + /* Some of these might be mappable to an existing SDLK_ code */ |
2964 | + ODD_keymap[XK_dead_grave&0xFF] = SDLK_COMPOSE; |
2965 | + ODD_keymap[XK_dead_acute&0xFF] = SDLK_COMPOSE; |
2966 | + ODD_keymap[XK_dead_tilde&0xFF] = SDLK_COMPOSE; |
2967 | + ODD_keymap[XK_dead_macron&0xFF] = SDLK_COMPOSE; |
2968 | + ODD_keymap[XK_dead_breve&0xFF] = SDLK_COMPOSE; |
2969 | + ODD_keymap[XK_dead_abovedot&0xFF] = SDLK_COMPOSE; |
2970 | + ODD_keymap[XK_dead_diaeresis&0xFF] = SDLK_COMPOSE; |
2971 | + ODD_keymap[XK_dead_abovering&0xFF] = SDLK_COMPOSE; |
2972 | + ODD_keymap[XK_dead_doubleacute&0xFF] = SDLK_COMPOSE; |
2973 | + ODD_keymap[XK_dead_caron&0xFF] = SDLK_COMPOSE; |
2974 | + ODD_keymap[XK_dead_cedilla&0xFF] = SDLK_COMPOSE; |
2975 | + ODD_keymap[XK_dead_ogonek&0xFF] = SDLK_COMPOSE; |
2976 | + ODD_keymap[XK_dead_iota&0xFF] = SDLK_COMPOSE; |
2977 | + ODD_keymap[XK_dead_voiced_sound&0xFF] = SDLK_COMPOSE; |
2978 | + ODD_keymap[XK_dead_semivoiced_sound&0xFF] = SDLK_COMPOSE; |
2979 | + ODD_keymap[XK_dead_belowdot&0xFF] = SDLK_COMPOSE; |
2980 | +#ifdef XK_dead_hook |
2981 | + ODD_keymap[XK_dead_hook&0xFF] = SDLK_COMPOSE; |
2982 | +#endif |
2983 | +#ifdef XK_dead_horn |
2984 | + ODD_keymap[XK_dead_horn&0xFF] = SDLK_COMPOSE; |
2985 | +#endif |
2986 | + |
2987 | +#ifdef XK_dead_circumflex |
2988 | + /* These X keysyms have 0xFE as the high byte */ |
2989 | + ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET; |
2990 | +#endif |
2991 | +#ifdef XK_ISO_Level3_Shift |
2992 | + ODD_keymap[XK_ISO_Level3_Shift&0xFF] = SDLK_MODE; /* "Alt Gr" key */ |
2993 | +#endif |
2994 | + |
2995 | + /* Map the miscellaneous keys */ |
2996 | + for ( i=0; i<SDL_arraysize(MISC_keymap); ++i ) |
2997 | + MISC_keymap[i] = SDLK_UNKNOWN; |
2998 | + |
2999 | + /* These X keysyms have 0xFF as the high byte */ |
3000 | + MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE; |
3001 | + MISC_keymap[XK_Tab&0xFF] = SDLK_TAB; |
3002 | + MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR; |
3003 | + MISC_keymap[XK_Return&0xFF] = SDLK_RETURN; |
3004 | + MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE; |
3005 | + MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE; |
3006 | + MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE; |
3007 | + |
3008 | + MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0; /* Keypad 0-9 */ |
3009 | + MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1; |
3010 | + MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2; |
3011 | + MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3; |
3012 | + MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4; |
3013 | + MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5; |
3014 | + MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6; |
3015 | + MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7; |
3016 | + MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8; |
3017 | + MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9; |
3018 | + MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0; |
3019 | + MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1; |
3020 | + MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2; |
3021 | + MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3; |
3022 | + MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4; |
3023 | + MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5; |
3024 | + MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6; |
3025 | + MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7; |
3026 | + MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8; |
3027 | + MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9; |
3028 | + MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD; |
3029 | + MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD; |
3030 | + MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE; |
3031 | + MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY; |
3032 | + MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS; |
3033 | + MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS; |
3034 | + MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER; |
3035 | + MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS; |
3036 | + |
3037 | + MISC_keymap[XK_Up&0xFF] = SDLK_UP; |
3038 | + MISC_keymap[XK_Down&0xFF] = SDLK_DOWN; |
3039 | + MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT; |
3040 | + MISC_keymap[XK_Left&0xFF] = SDLK_LEFT; |
3041 | + MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT; |
3042 | + MISC_keymap[XK_Home&0xFF] = SDLK_HOME; |
3043 | + MISC_keymap[XK_End&0xFF] = SDLK_END; |
3044 | + MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP; |
3045 | + MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN; |
3046 | + |
3047 | + MISC_keymap[XK_F1&0xFF] = SDLK_F1; |
3048 | + MISC_keymap[XK_F2&0xFF] = SDLK_F2; |
3049 | + MISC_keymap[XK_F3&0xFF] = SDLK_F3; |
3050 | + MISC_keymap[XK_F4&0xFF] = SDLK_F4; |
3051 | + MISC_keymap[XK_F5&0xFF] = SDLK_F5; |
3052 | + MISC_keymap[XK_F6&0xFF] = SDLK_F6; |
3053 | + MISC_keymap[XK_F7&0xFF] = SDLK_F7; |
3054 | + MISC_keymap[XK_F8&0xFF] = SDLK_F8; |
3055 | + MISC_keymap[XK_F9&0xFF] = SDLK_F9; |
3056 | + MISC_keymap[XK_F10&0xFF] = SDLK_F10; |
3057 | + MISC_keymap[XK_F11&0xFF] = SDLK_F11; |
3058 | + MISC_keymap[XK_F12&0xFF] = SDLK_F12; |
3059 | + MISC_keymap[XK_F13&0xFF] = SDLK_F13; |
3060 | + MISC_keymap[XK_F14&0xFF] = SDLK_F14; |
3061 | + MISC_keymap[XK_F15&0xFF] = SDLK_F15; |
3062 | + |
3063 | + MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK; |
3064 | + MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK; |
3065 | + MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK; |
3066 | + MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT; |
3067 | + MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT; |
3068 | + MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL; |
3069 | + MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL; |
3070 | + MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT; |
3071 | + MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT; |
3072 | + MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA; |
3073 | + MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA; |
3074 | + MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */ |
3075 | + MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */ |
3076 | + MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */ |
3077 | + MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */ |
3078 | + |
3079 | + MISC_keymap[XK_Help&0xFF] = SDLK_HELP; |
3080 | + MISC_keymap[XK_Print&0xFF] = SDLK_PRINT; |
3081 | + MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ; |
3082 | + MISC_keymap[XK_Break&0xFF] = SDLK_BREAK; |
3083 | + MISC_keymap[XK_Menu&0xFF] = SDLK_MENU; |
3084 | + MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU; /* Windows "Menu" key */ |
3085 | +} |
3086 | + |
3087 | +/* Get the translated SDL virtual keysym */ |
3088 | +SDLKey X11_TranslateKeycode(Display *display, KeyCode kc) |
3089 | +{ |
3090 | + KeySym xsym; |
3091 | + SDLKey key; |
3092 | + |
3093 | + xsym = XKeycodeToKeysym(display, kc, 0); |
3094 | +#ifdef DEBUG_KEYS |
3095 | + fprintf(stderr, "Translating key code %d -> 0x%.4x\n", kc, xsym); |
3096 | +#endif |
3097 | + key = SDLK_UNKNOWN; |
3098 | + if ( xsym ) { |
3099 | + switch (xsym>>8) { |
3100 | + case 0x1005FF: |
3101 | +#ifdef SunXK_F36 |
3102 | + if ( xsym == SunXK_F36 ) |
3103 | + key = SDLK_F11; |
3104 | +#endif |
3105 | +#ifdef SunXK_F37 |
3106 | + if ( xsym == SunXK_F37 ) |
3107 | + key = SDLK_F12; |
3108 | +#endif |
3109 | + break; |
3110 | + case 0x00: /* Latin 1 */ |
3111 | + key = (SDLKey)(xsym & 0xFF); |
3112 | + break; |
3113 | + case 0x01: /* Latin 2 */ |
3114 | + case 0x02: /* Latin 3 */ |
3115 | + case 0x03: /* Latin 4 */ |
3116 | + case 0x04: /* Katakana */ |
3117 | + case 0x05: /* Arabic */ |
3118 | + case 0x06: /* Cyrillic */ |
3119 | + case 0x07: /* Greek */ |
3120 | + case 0x08: /* Technical */ |
3121 | + case 0x0A: /* Publishing */ |
3122 | + case 0x0C: /* Hebrew */ |
3123 | + case 0x0D: /* Thai */ |
3124 | + /* These are wrong, but it's better than nothing */ |
3125 | + key = (SDLKey)(xsym & 0xFF); |
3126 | + break; |
3127 | + case 0xFE: |
3128 | + key = ODD_keymap[xsym&0xFF]; |
3129 | + break; |
3130 | + case 0xFF: |
3131 | + key = MISC_keymap[xsym&0xFF]; |
3132 | + break; |
3133 | + default: |
3134 | + /* |
3135 | + fprintf(stderr, "X11: Unhandled xsym, sym = 0x%04x\n", |
3136 | + (unsigned int)xsym); |
3137 | + */ |
3138 | + break; |
3139 | + } |
3140 | + } else { |
3141 | + /* X11 doesn't know how to translate the key! */ |
3142 | + switch (kc) { |
3143 | + /* Caution: |
3144 | + These keycodes are from the Microsoft Keyboard |
3145 | + */ |
3146 | + case 115: |
3147 | + key = SDLK_LSUPER; |
3148 | + break; |
3149 | + case 116: |
3150 | + key = SDLK_RSUPER; |
3151 | + break; |
3152 | + case 117: |
3153 | + key = SDLK_MENU; |
3154 | + break; |
3155 | + default: |
3156 | + /* |
3157 | + * no point in an error message; happens for |
3158 | + * several keys when we get a keymap notify |
3159 | + */ |
3160 | + break; |
3161 | + } |
3162 | + } |
3163 | + return key; |
3164 | +} |
3165 | + |
3166 | +/* X11 modifier masks for various keys */ |
3167 | +static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask; |
3168 | +static unsigned num_mask, mode_switch_mask; |
3169 | + |
3170 | +static void get_modifier_masks(Display *display) |
3171 | +{ |
3172 | + static unsigned got_masks; |
3173 | + int i, j; |
3174 | + XModifierKeymap *xmods; |
3175 | + unsigned n; |
3176 | + |
3177 | + if(got_masks) |
3178 | + return; |
3179 | + |
3180 | + xmods = XGetModifierMapping(display); |
3181 | + n = xmods->max_keypermod; |
3182 | + for(i = 3; i < 8; i++) { |
3183 | + for(j = 0; j < n; j++) { |
3184 | + KeyCode kc = xmods->modifiermap[i * n + j]; |
3185 | + KeySym ks = XKeycodeToKeysym(display, kc, 0); |
3186 | + unsigned mask = 1 << i; |
3187 | + switch(ks) { |
3188 | + case XK_Num_Lock: |
3189 | + num_mask = mask; break; |
3190 | + case XK_Alt_L: |
3191 | + alt_l_mask = mask; break; |
3192 | + case XK_Alt_R: |
3193 | + alt_r_mask = mask; break; |
3194 | + case XK_Meta_L: |
3195 | + meta_l_mask = mask; break; |
3196 | + case XK_Meta_R: |
3197 | + meta_r_mask = mask; break; |
3198 | + case XK_Mode_switch: |
3199 | + mode_switch_mask = mask; break; |
3200 | + } |
3201 | + } |
3202 | + } |
3203 | + XFreeModifiermap(xmods); |
3204 | + got_masks = 1; |
3205 | +} |
3206 | + |
3207 | + |
3208 | +/* |
3209 | + * This function is semi-official; it is not officially exported and should |
3210 | + * not be considered part of the SDL API, but may be used by client code |
3211 | + * that *really* needs it (including legacy code). |
3212 | + * It is slow, though, and should be avoided if possible. |
3213 | + * |
3214 | + * Note that it isn't completely accurate either; in particular, multi-key |
3215 | + * sequences (dead accents, compose key sequences) will not work since the |
3216 | + * state has been irrevocably lost. |
3217 | + */ |
3218 | +extern DECLSPEC Uint16 SDLCALL X11_KeyToUnicode(SDLKey, SDLMod); |
3219 | + |
3220 | +Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers) |
3221 | +{ |
3222 | + static int warning = 1; |
3223 | + struct SDL_VideoDevice *this = current_video; |
3224 | + char keybuf[32]; |
3225 | + int i; |
3226 | + KeySym xsym = 0; |
3227 | + XKeyEvent xkey; |
3228 | + Uint16 unicode; |
3229 | + |
3230 | + if ( warning ) { |
3231 | + warning = 0; |
3232 | + fprintf(stderr, "WARNING: Application is using X11_KeyToUnicode().\n"); |
3233 | + fprintf(stderr, "This is not an official SDL function, please report this as a bug.\n"); |
3234 | + } |
3235 | + |
3236 | + if ( !this || !SDL_Display ) { |
3237 | + return 0; |
3238 | + } |
3239 | + |
3240 | + SDL_memset(&xkey, 0, sizeof(xkey)); |
3241 | + xkey.display = SDL_Display; |
3242 | + |
3243 | + xsym = keysym; /* last resort if not found */ |
3244 | + for (i = 0; i < 256; ++i) { |
3245 | + if ( MISC_keymap[i] == keysym ) { |
3246 | + xsym = 0xFF00 | i; |
3247 | + break; |
3248 | + } else if ( ODD_keymap[i] == keysym ) { |
3249 | + xsym = 0xFE00 | i; |
3250 | + break; |
3251 | + } |
3252 | + } |
3253 | + |
3254 | + xkey.keycode = XKeysymToKeycode(xkey.display, xsym); |
3255 | + |
3256 | + get_modifier_masks(SDL_Display); |
3257 | + if(modifiers & KMOD_SHIFT) |
3258 | + xkey.state |= ShiftMask; |
3259 | + if(modifiers & KMOD_CAPS) |
3260 | + xkey.state |= LockMask; |
3261 | + if(modifiers & KMOD_CTRL) |
3262 | + xkey.state |= ControlMask; |
3263 | + if(modifiers & KMOD_MODE) |
3264 | + xkey.state |= mode_switch_mask; |
3265 | + if(modifiers & KMOD_LALT) |
3266 | + xkey.state |= alt_l_mask; |
3267 | + if(modifiers & KMOD_RALT) |
3268 | + xkey.state |= alt_r_mask; |
3269 | + if(modifiers & KMOD_LMETA) |
3270 | + xkey.state |= meta_l_mask; |
3271 | + if(modifiers & KMOD_RMETA) |
3272 | + xkey.state |= meta_r_mask; |
3273 | + if(modifiers & KMOD_NUM) |
3274 | + xkey.state |= num_mask; |
3275 | + |
3276 | + unicode = 0; |
3277 | + if ( XLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) ) |
3278 | + unicode = (unsigned char)keybuf[0]; |
3279 | + return(unicode); |
3280 | +} |
3281 | + |
3282 | + |
3283 | +/* |
3284 | + * Called when focus is regained, to read the keyboard state and generate |
3285 | + * synthetic keypress/release events. |
3286 | + * key_vec is a bit vector of keycodes (256 bits) |
3287 | + */ |
3288 | +void X11_SetKeyboardState(Display *display, const char *key_vec) |
3289 | +{ |
3290 | + char keys_return[32]; |
3291 | + int i; |
3292 | + Uint8 *kstate = SDL_GetKeyState(NULL); |
3293 | + SDLMod modstate; |
3294 | + Window junk_window; |
3295 | + int x, y; |
3296 | + unsigned int mask; |
3297 | + |
3298 | + /* The first time the window is mapped, we initialize key state */ |
3299 | + if ( ! key_vec ) { |
3300 | + XQueryKeymap(display, keys_return); |
3301 | + key_vec = keys_return; |
3302 | + } |
3303 | + |
3304 | + /* Get the keyboard modifier state */ |
3305 | + modstate = 0; |
3306 | + get_modifier_masks(display); |
3307 | + if ( XQueryPointer(display, DefaultRootWindow(display), |
3308 | + &junk_window, &junk_window, &x, &y, &x, &y, &mask) ) { |
3309 | + if ( mask & LockMask ) { |
3310 | + modstate |= KMOD_CAPS; |
3311 | + } |
3312 | + if ( mask & mode_switch_mask ) { |
3313 | + modstate |= KMOD_MODE; |
3314 | + } |
3315 | + if ( mask & num_mask ) { |
3316 | + modstate |= KMOD_NUM; |
3317 | + } |
3318 | + } |
3319 | + |
3320 | + /* Zero the new keyboard state and generate it */ |
3321 | + SDL_memset(kstate, 0, SDLK_LAST); |
3322 | + /* |
3323 | + * An obvious optimisation is to check entire longwords at a time in |
3324 | + * both loops, but we can't be sure the arrays are aligned so it's not |
3325 | + * worth the extra complexity |
3326 | + */ |
3327 | + for ( i = 0; i < 32; i++ ) { |
3328 | + int j; |
3329 | + if ( !key_vec[i] ) |
3330 | + continue; |
3331 | + for ( j = 0; j < 8; j++ ) { |
3332 | + if ( key_vec[i] & (1 << j) ) { |
3333 | + SDLKey key; |
3334 | + KeyCode kc = (i << 3 | j); |
3335 | + key = X11_TranslateKeycode(display, kc); |
3336 | + if ( key == SDLK_UNKNOWN ) { |
3337 | + continue; |
3338 | + } |
3339 | + kstate[key] = SDL_PRESSED; |
3340 | + switch (key) { |
3341 | + case SDLK_LSHIFT: |
3342 | + modstate |= KMOD_LSHIFT; |
3343 | + break; |
3344 | + case SDLK_RSHIFT: |
3345 | + modstate |= KMOD_RSHIFT; |
3346 | + break; |
3347 | + case SDLK_LCTRL: |
3348 | + modstate |= KMOD_LCTRL; |
3349 | + break; |
3350 | + case SDLK_RCTRL: |
3351 | + modstate |= KMOD_RCTRL; |
3352 | + break; |
3353 | + case SDLK_LALT: |
3354 | + modstate |= KMOD_LALT; |
3355 | + break; |
3356 | + case SDLK_RALT: |
3357 | + modstate |= KMOD_RALT; |
3358 | + break; |
3359 | + case SDLK_LMETA: |
3360 | + modstate |= KMOD_LMETA; |
3361 | + break; |
3362 | + case SDLK_RMETA: |
3363 | + modstate |= KMOD_RMETA; |
3364 | + break; |
3365 | + default: |
3366 | + break; |
3367 | + } |
3368 | + } |
3369 | + } |
3370 | + } |
3371 | + |
3372 | + /* Hack - set toggle key state */ |
3373 | + if ( modstate & KMOD_CAPS ) { |
3374 | + kstate[SDLK_CAPSLOCK] = SDL_PRESSED; |
3375 | + } else { |
3376 | + kstate[SDLK_CAPSLOCK] = SDL_RELEASED; |
3377 | + } |
3378 | + if ( modstate & KMOD_NUM ) { |
3379 | + kstate[SDLK_NUMLOCK] = SDL_PRESSED; |
3380 | + } else { |
3381 | + kstate[SDLK_NUMLOCK] = SDL_RELEASED; |
3382 | + } |
3383 | + |
3384 | + /* Set the final modifier state */ |
3385 | + SDL_SetModState(modstate); |
3386 | +} |
3387 | + |
3388 | +void X11_InitOSKeymap(_THIS) |
3389 | +{ |
3390 | + X11_InitKeymap(); |
3391 | +} |
3392 | + |
3393 | |
3394 | === added file '.pc/fix_window_resizing.diff/src/video/x11/SDL_x11events_c.h' |
3395 | --- .pc/fix_window_resizing.diff/src/video/x11/SDL_x11events_c.h 1970-01-01 00:00:00 +0000 |
3396 | +++ .pc/fix_window_resizing.diff/src/video/x11/SDL_x11events_c.h 2015-06-01 21:40:05 +0000 |
3397 | @@ -0,0 +1,34 @@ |
3398 | +/* |
3399 | + SDL - Simple DirectMedia Layer |
3400 | + Copyright (C) 1997-2012 Sam Lantinga |
3401 | + |
3402 | + This library is free software; you can redistribute it and/or |
3403 | + modify it under the terms of the GNU Lesser General Public |
3404 | + License as published by the Free Software Foundation; either |
3405 | + version 2.1 of the License, or (at your option) any later version. |
3406 | + |
3407 | + This library is distributed in the hope that it will be useful, |
3408 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3409 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3410 | + Lesser General Public License for more details. |
3411 | + |
3412 | + You should have received a copy of the GNU Lesser General Public |
3413 | + License along with this library; if not, write to the Free Software |
3414 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
3415 | + |
3416 | + Sam Lantinga |
3417 | + slouken@libsdl.org |
3418 | +*/ |
3419 | +#include "SDL_config.h" |
3420 | + |
3421 | +#include "SDL_x11video.h" |
3422 | + |
3423 | +/* Functions to be exported */ |
3424 | +extern void X11_InitOSKeymap(_THIS); |
3425 | +extern void X11_PumpEvents(_THIS); |
3426 | +extern void X11_SetKeyboardState(Display *display, const char *key_vec); |
3427 | + |
3428 | +/* Variables to be exported */ |
3429 | +extern int X11_PendingConfigureNotifyWidth; |
3430 | +extern int X11_PendingConfigureNotifyHeight; |
3431 | + |
3432 | |
3433 | === added file '.pc/fix_window_resizing.diff/src/video/x11/SDL_x11video.c' |
3434 | --- .pc/fix_window_resizing.diff/src/video/x11/SDL_x11video.c 1970-01-01 00:00:00 +0000 |
3435 | +++ .pc/fix_window_resizing.diff/src/video/x11/SDL_x11video.c 2015-06-01 21:40:05 +0000 |
3436 | @@ -0,0 +1,1571 @@ |
3437 | +/* |
3438 | + SDL - Simple DirectMedia Layer |
3439 | + Copyright (C) 1997-2012 Sam Lantinga |
3440 | + |
3441 | + This library is free software; you can redistribute it and/or |
3442 | + modify it under the terms of the GNU Lesser General Public |
3443 | + License as published by the Free Software Foundation; either |
3444 | + version 2.1 of the License, or (at your option) any later version. |
3445 | + |
3446 | + This library is distributed in the hope that it will be useful, |
3447 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3448 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3449 | + Lesser General Public License for more details. |
3450 | + |
3451 | + You should have received a copy of the GNU Lesser General Public |
3452 | + License along with this library; if not, write to the Free Software |
3453 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
3454 | + |
3455 | + Sam Lantinga |
3456 | + slouken@libsdl.org |
3457 | +*/ |
3458 | +#include "SDL_config.h" |
3459 | + |
3460 | +/* X11 based SDL video driver implementation. |
3461 | + Note: This implementation does not currently need X11 thread locking, |
3462 | + since the event thread uses a separate X connection and any |
3463 | + additional locking necessary is handled internally. However, |
3464 | + if full locking is neccessary, take a look at XInitThreads(). |
3465 | +*/ |
3466 | + |
3467 | +#include <unistd.h> |
3468 | +#include <sys/ioctl.h> |
3469 | +#ifdef MTRR_SUPPORT |
3470 | +#include <asm/mtrr.h> |
3471 | +#include <sys/fcntl.h> |
3472 | +#endif |
3473 | + |
3474 | +#include "SDL_endian.h" |
3475 | +#include "SDL_timer.h" |
3476 | +#include "SDL_thread.h" |
3477 | +#include "SDL_video.h" |
3478 | +#include "SDL_mouse.h" |
3479 | +#include "../SDL_sysvideo.h" |
3480 | +#include "../SDL_pixels_c.h" |
3481 | +#include "../../events/SDL_events_c.h" |
3482 | +#include "SDL_x11video.h" |
3483 | +#include "SDL_x11wm_c.h" |
3484 | +#include "SDL_x11mouse_c.h" |
3485 | +#include "SDL_x11events_c.h" |
3486 | +#include "SDL_x11modes_c.h" |
3487 | +#include "SDL_x11image_c.h" |
3488 | +#include "SDL_x11yuv_c.h" |
3489 | +#include "SDL_x11gl_c.h" |
3490 | +#include "SDL_x11gamma_c.h" |
3491 | +#include "../blank_cursor.h" |
3492 | + |
3493 | +#ifdef X_HAVE_UTF8_STRING |
3494 | +#include <locale.h> |
3495 | +#endif |
3496 | + |
3497 | +/* Initialization/Query functions */ |
3498 | +static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat); |
3499 | +static SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); |
3500 | +static int X11_ToggleFullScreen(_THIS, int on); |
3501 | +static void X11_UpdateMouse(_THIS); |
3502 | +static int X11_SetColors(_THIS, int firstcolor, int ncolors, |
3503 | + SDL_Color *colors); |
3504 | +static int X11_SetGammaRamp(_THIS, Uint16 *ramp); |
3505 | +static void X11_VideoQuit(_THIS); |
3506 | + |
3507 | + |
3508 | +/* X11 driver bootstrap functions */ |
3509 | + |
3510 | +static int X11_Available(void) |
3511 | +{ |
3512 | + Display *display = NULL; |
3513 | + if ( SDL_X11_LoadSymbols() ) { |
3514 | + display = XOpenDisplay(NULL); |
3515 | + if ( display != NULL ) { |
3516 | + XCloseDisplay(display); |
3517 | + } |
3518 | + SDL_X11_UnloadSymbols(); |
3519 | + } |
3520 | + return(display != NULL); |
3521 | +} |
3522 | + |
3523 | +static void X11_DeleteDevice(SDL_VideoDevice *device) |
3524 | +{ |
3525 | + if ( device ) { |
3526 | + if ( device->hidden ) { |
3527 | + SDL_free(device->hidden); |
3528 | + } |
3529 | + if ( device->gl_data ) { |
3530 | + SDL_free(device->gl_data); |
3531 | + } |
3532 | + SDL_free(device); |
3533 | + SDL_X11_UnloadSymbols(); |
3534 | + } |
3535 | +} |
3536 | + |
3537 | +static SDL_VideoDevice *X11_CreateDevice(int devindex) |
3538 | +{ |
3539 | + SDL_VideoDevice *device = NULL; |
3540 | + |
3541 | + if ( SDL_X11_LoadSymbols() ) { |
3542 | + /* Initialize all variables that we clean on shutdown */ |
3543 | + device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice)); |
3544 | + if ( device ) { |
3545 | + SDL_memset(device, 0, (sizeof *device)); |
3546 | + device->hidden = (struct SDL_PrivateVideoData *) |
3547 | + SDL_malloc((sizeof *device->hidden)); |
3548 | + device->gl_data = (struct SDL_PrivateGLData *) |
3549 | + SDL_malloc((sizeof *device->gl_data)); |
3550 | + } |
3551 | + if ( (device == NULL) || (device->hidden == NULL) || |
3552 | + (device->gl_data == NULL) ) { |
3553 | + SDL_OutOfMemory(); |
3554 | + X11_DeleteDevice(device); /* calls SDL_X11_UnloadSymbols(). */ |
3555 | + return(0); |
3556 | + } |
3557 | + SDL_memset(device->hidden, 0, (sizeof *device->hidden)); |
3558 | + SDL_memset(device->gl_data, 0, (sizeof *device->gl_data)); |
3559 | + |
3560 | +#if SDL_VIDEO_OPENGL_GLX |
3561 | + device->gl_data->swap_interval = -1; |
3562 | +#endif |
3563 | + |
3564 | + /* Set the driver flags */ |
3565 | + device->handles_any_size = 1; |
3566 | + |
3567 | + /* Set the function pointers */ |
3568 | + device->VideoInit = X11_VideoInit; |
3569 | + device->ListModes = X11_ListModes; |
3570 | + device->SetVideoMode = X11_SetVideoMode; |
3571 | + device->ToggleFullScreen = X11_ToggleFullScreen; |
3572 | + device->UpdateMouse = X11_UpdateMouse; |
3573 | +#if SDL_VIDEO_DRIVER_X11_XV |
3574 | + device->CreateYUVOverlay = X11_CreateYUVOverlay; |
3575 | +#endif |
3576 | + device->SetColors = X11_SetColors; |
3577 | + device->UpdateRects = NULL; |
3578 | + device->VideoQuit = X11_VideoQuit; |
3579 | + device->AllocHWSurface = X11_AllocHWSurface; |
3580 | + device->CheckHWBlit = NULL; |
3581 | + device->FillHWRect = NULL; |
3582 | + device->SetHWColorKey = NULL; |
3583 | + device->SetHWAlpha = NULL; |
3584 | + device->LockHWSurface = X11_LockHWSurface; |
3585 | + device->UnlockHWSurface = X11_UnlockHWSurface; |
3586 | + device->FlipHWSurface = X11_FlipHWSurface; |
3587 | + device->FreeHWSurface = X11_FreeHWSurface; |
3588 | + device->SetGamma = X11_SetVidModeGamma; |
3589 | + device->GetGamma = X11_GetVidModeGamma; |
3590 | + device->SetGammaRamp = X11_SetGammaRamp; |
3591 | + device->GetGammaRamp = NULL; |
3592 | +#if SDL_VIDEO_OPENGL_GLX |
3593 | + device->GL_LoadLibrary = X11_GL_LoadLibrary; |
3594 | + device->GL_GetProcAddress = X11_GL_GetProcAddress; |
3595 | + device->GL_GetAttribute = X11_GL_GetAttribute; |
3596 | + device->GL_MakeCurrent = X11_GL_MakeCurrent; |
3597 | + device->GL_SwapBuffers = X11_GL_SwapBuffers; |
3598 | +#endif |
3599 | + device->SetCaption = X11_SetCaption; |
3600 | + device->SetIcon = X11_SetIcon; |
3601 | + device->IconifyWindow = X11_IconifyWindow; |
3602 | + device->GrabInput = X11_GrabInput; |
3603 | + device->GetWMInfo = X11_GetWMInfo; |
3604 | + device->FreeWMCursor = X11_FreeWMCursor; |
3605 | + device->CreateWMCursor = X11_CreateWMCursor; |
3606 | + device->ShowWMCursor = X11_ShowWMCursor; |
3607 | + device->WarpWMCursor = X11_WarpWMCursor; |
3608 | + device->CheckMouseMode = X11_CheckMouseMode; |
3609 | + device->InitOSKeymap = X11_InitOSKeymap; |
3610 | + device->PumpEvents = X11_PumpEvents; |
3611 | + |
3612 | + device->free = X11_DeleteDevice; |
3613 | + } |
3614 | + |
3615 | + return device; |
3616 | +} |
3617 | + |
3618 | +VideoBootStrap X11_bootstrap = { |
3619 | + "x11", "X Window System", |
3620 | + X11_Available, X11_CreateDevice |
3621 | +}; |
3622 | + |
3623 | +/* Normal X11 error handler routine */ |
3624 | +static int (*X_handler)(Display *, XErrorEvent *) = NULL; |
3625 | +static int x_errhandler(Display *d, XErrorEvent *e) |
3626 | +{ |
3627 | +#if SDL_VIDEO_DRIVER_X11_VIDMODE |
3628 | + extern int vm_error; |
3629 | +#endif |
3630 | +#if SDL_VIDEO_DRIVER_X11_DGAMOUSE |
3631 | + extern int dga_error; |
3632 | +#endif |
3633 | + |
3634 | +#if SDL_VIDEO_DRIVER_X11_VIDMODE |
3635 | + /* VidMode errors are non-fatal. :) */ |
3636 | + /* Are the errors offset by one from the error base? |
3637 | + e.g. the error base is 143, the code is 148, and the |
3638 | + actual error is XF86VidModeExtensionDisabled (4) ? |
3639 | + */ |
3640 | + if ( (vm_error >= 0) && |
3641 | + (((e->error_code == BadRequest)&&(e->request_code == vm_error)) || |
3642 | + ((e->error_code > vm_error) && |
3643 | + (e->error_code <= (vm_error+XF86VidModeNumberErrors)))) ) { |
3644 | +#ifdef X11_DEBUG |
3645 | +{ char errmsg[1024]; |
3646 | + XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg)); |
3647 | +printf("VidMode error: %s\n", errmsg); |
3648 | +} |
3649 | +#endif |
3650 | + return(0); |
3651 | + } |
3652 | +#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ |
3653 | + |
3654 | +#if SDL_VIDEO_DRIVER_X11_DGAMOUSE |
3655 | + /* DGA errors can be non-fatal. :) */ |
3656 | + if ( (dga_error >= 0) && |
3657 | + ((e->error_code > dga_error) && |
3658 | + (e->error_code <= (dga_error+XF86DGANumberErrors))) ) { |
3659 | +#ifdef X11_DEBUG |
3660 | +{ char errmsg[1024]; |
3661 | + XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg)); |
3662 | +printf("DGA error: %s\n", errmsg); |
3663 | +} |
3664 | +#endif |
3665 | + return(0); |
3666 | + } |
3667 | +#endif /* SDL_VIDEO_DRIVER_X11_DGAMOUSE */ |
3668 | + |
3669 | + return(X_handler(d,e)); |
3670 | +} |
3671 | + |
3672 | +/* X11 I/O error handler routine */ |
3673 | +static int (*XIO_handler)(Display *) = NULL; |
3674 | +static int xio_errhandler(Display *d) |
3675 | +{ |
3676 | + /* Ack! Lost X11 connection! */ |
3677 | + |
3678 | + /* We will crash if we try to clean up our display */ |
3679 | + if ( SDL_VideoSurface && current_video->hidden->Ximage ) { |
3680 | + SDL_VideoSurface->pixels = NULL; |
3681 | + } |
3682 | + current_video->hidden->X11_Display = NULL; |
3683 | + |
3684 | + /* Continue with the standard X11 error handler */ |
3685 | + return(XIO_handler(d)); |
3686 | +} |
3687 | + |
3688 | +static int (*Xext_handler)(Display *, _Xconst char *, _Xconst char *) = NULL; |
3689 | +static int xext_errhandler(Display *d, _Xconst char *ext, _Xconst char *reason) |
3690 | +{ |
3691 | +#ifdef X11_DEBUG |
3692 | + printf("Xext error inside SDL (may be harmless):\n"); |
3693 | + printf(" Extension \"%s\" %s on display \"%s\".\n", |
3694 | + ext, reason, XDisplayString(d)); |
3695 | +#endif |
3696 | + |
3697 | + if (SDL_strcmp(reason, "missing") == 0) { |
3698 | + /* |
3699 | + * Since the query itself, elsewhere, can handle a missing extension |
3700 | + * and the default behaviour in Xlib is to write to stderr, which |
3701 | + * generates unnecessary bug reports, we just ignore these. |
3702 | + */ |
3703 | + return 0; |
3704 | + } |
3705 | + |
3706 | + /* Everything else goes to the default handler... */ |
3707 | + return Xext_handler(d, ext, reason); |
3708 | +} |
3709 | + |
3710 | +/* Find out what class name we should use */ |
3711 | +static char *get_classname(char *classname, int maxlen) |
3712 | +{ |
3713 | + char *spot; |
3714 | +#if defined(__LINUX__) || defined(__FREEBSD__) |
3715 | + char procfile[1024]; |
3716 | + char linkfile[1024]; |
3717 | + int linksize; |
3718 | +#endif |
3719 | + |
3720 | + /* First allow environment variable override */ |
3721 | + spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS"); |
3722 | + if ( spot ) { |
3723 | + SDL_strlcpy(classname, spot, maxlen); |
3724 | + return classname; |
3725 | + } |
3726 | + |
3727 | + /* Next look at the application's executable name */ |
3728 | +#if defined(__LINUX__) || defined(__FREEBSD__) |
3729 | +#if defined(__LINUX__) |
3730 | + SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid()); |
3731 | +#elif defined(__FREEBSD__) |
3732 | + SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file", getpid()); |
3733 | +#else |
3734 | +#error Where can we find the executable name? |
3735 | +#endif |
3736 | + linksize = readlink(procfile, linkfile, sizeof(linkfile)-1); |
3737 | + if ( linksize > 0 ) { |
3738 | + linkfile[linksize] = '\0'; |
3739 | + spot = SDL_strrchr(linkfile, '/'); |
3740 | + if ( spot ) { |
3741 | + SDL_strlcpy(classname, spot+1, maxlen); |
3742 | + } else { |
3743 | + SDL_strlcpy(classname, linkfile, maxlen); |
3744 | + } |
3745 | + return classname; |
3746 | + } |
3747 | +#endif /* __LINUX__ */ |
3748 | + |
3749 | + /* Finally use the default we've used forever */ |
3750 | + SDL_strlcpy(classname, "SDL_App", maxlen); |
3751 | + return classname; |
3752 | +} |
3753 | + |
3754 | +/* Create auxiliary (toplevel) windows with the current visual */ |
3755 | +static void create_aux_windows(_THIS) |
3756 | +{ |
3757 | + int x = 0, y = 0; |
3758 | + char classname[1024]; |
3759 | + XSetWindowAttributes xattr; |
3760 | + XWMHints *hints; |
3761 | + unsigned long app_event_mask; |
3762 | + int def_vis = (SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen)); |
3763 | + |
3764 | + /* Look up some useful Atoms */ |
3765 | + WM_DELETE_WINDOW = XInternAtom(SDL_Display, "WM_DELETE_WINDOW", False); |
3766 | + |
3767 | + /* Don't create any extra windows if we are being managed */ |
3768 | + if ( SDL_windowid ) { |
3769 | + FSwindow = 0; |
3770 | + WMwindow = SDL_strtol(SDL_windowid, NULL, 0); |
3771 | + return; |
3772 | + } |
3773 | + |
3774 | + if(FSwindow) |
3775 | + XDestroyWindow(SDL_Display, FSwindow); |
3776 | + |
3777 | +#if SDL_VIDEO_DRIVER_X11_XINERAMA |
3778 | + if ( use_xinerama ) { |
3779 | + x = xinerama_info.x_org; |
3780 | + y = xinerama_info.y_org; |
3781 | + } |
3782 | +#endif |
3783 | + xattr.override_redirect = True; |
3784 | + xattr.background_pixel = def_vis ? BlackPixel(SDL_Display, SDL_Screen) : 0; |
3785 | + xattr.border_pixel = 0; |
3786 | + xattr.colormap = SDL_XColorMap; |
3787 | + |
3788 | + FSwindow = XCreateWindow(SDL_Display, SDL_Root, |
3789 | + x, y, 32, 32, 0, |
3790 | + this->hidden->depth, InputOutput, SDL_Visual, |
3791 | + CWOverrideRedirect | CWBackPixel | CWBorderPixel |
3792 | + | CWColormap, |
3793 | + &xattr); |
3794 | + |
3795 | + XSelectInput(SDL_Display, FSwindow, StructureNotifyMask); |
3796 | + |
3797 | + /* Tell KDE to keep the fullscreen window on top */ |
3798 | + { |
3799 | + XEvent ev; |
3800 | + long mask; |
3801 | + |
3802 | + SDL_memset(&ev, 0, sizeof(ev)); |
3803 | + ev.xclient.type = ClientMessage; |
3804 | + ev.xclient.window = SDL_Root; |
3805 | + ev.xclient.message_type = XInternAtom(SDL_Display, |
3806 | + "KWM_KEEP_ON_TOP", False); |
3807 | + ev.xclient.format = 32; |
3808 | + ev.xclient.data.l[0] = FSwindow; |
3809 | + ev.xclient.data.l[1] = CurrentTime; |
3810 | + mask = SubstructureRedirectMask; |
3811 | + XSendEvent(SDL_Display, SDL_Root, False, mask, &ev); |
3812 | + } |
3813 | + |
3814 | + hints = NULL; |
3815 | + if(WMwindow) { |
3816 | + /* All window attributes must survive the recreation */ |
3817 | + hints = XGetWMHints(SDL_Display, WMwindow); |
3818 | + XDestroyWindow(SDL_Display, WMwindow); |
3819 | + } |
3820 | + |
3821 | + /* Create the window for windowed management */ |
3822 | + /* (reusing the xattr structure above) */ |
3823 | + WMwindow = XCreateWindow(SDL_Display, SDL_Root, |
3824 | + x, y, 32, 32, 0, |
3825 | + this->hidden->depth, InputOutput, SDL_Visual, |
3826 | + CWBackPixel | CWBorderPixel | CWColormap, |
3827 | + &xattr); |
3828 | + |
3829 | + /* Set the input hints so we get keyboard input */ |
3830 | + if(!hints) { |
3831 | + hints = XAllocWMHints(); |
3832 | + hints->input = True; |
3833 | + hints->flags = InputHint; |
3834 | + } |
3835 | + XSetWMHints(SDL_Display, WMwindow, hints); |
3836 | + XFree(hints); |
3837 | + X11_SetCaptionNoLock(this, this->wm_title, this->wm_icon); |
3838 | + |
3839 | + app_event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask |
3840 | + | PropertyChangeMask | StructureNotifyMask | KeymapStateMask; |
3841 | + XSelectInput(SDL_Display, WMwindow, app_event_mask); |
3842 | + |
3843 | + /* Set the class hints so we can get an icon (AfterStep) */ |
3844 | + get_classname(classname, sizeof(classname)); |
3845 | + { |
3846 | + XClassHint *classhints; |
3847 | + classhints = XAllocClassHint(); |
3848 | + if(classhints != NULL) { |
3849 | + classhints->res_name = classname; |
3850 | + classhints->res_class = classname; |
3851 | + XSetClassHint(SDL_Display, WMwindow, classhints); |
3852 | + XFree(classhints); |
3853 | + } |
3854 | + } |
3855 | + |
3856 | + { |
3857 | + pid_t pid = getpid(); |
3858 | + char hostname[256]; |
3859 | + |
3860 | + if (pid > 0 && gethostname(hostname, sizeof(hostname)) > -1) { |
3861 | + Atom _NET_WM_PID = XInternAtom(SDL_Display, "_NET_WM_PID", False); |
3862 | + Atom WM_CLIENT_MACHINE = XInternAtom(SDL_Display, "WM_CLIENT_MACHINE", False); |
3863 | + |
3864 | + hostname[sizeof(hostname)-1] = '\0'; |
3865 | + XChangeProperty(SDL_Display, WMwindow, _NET_WM_PID, XA_CARDINAL, 32, |
3866 | + PropModeReplace, (unsigned char *)&pid, 1); |
3867 | + XChangeProperty(SDL_Display, WMwindow, WM_CLIENT_MACHINE, XA_STRING, 8, |
3868 | + PropModeReplace, (unsigned char *)hostname, SDL_strlen(hostname)); |
3869 | + } |
3870 | + } |
3871 | + |
3872 | + /* Setup the communication with the IM server */ |
3873 | + /* create_aux_windows may be called several times against the same |
3874 | + Display. We should reuse the SDL_IM if one has been opened for |
3875 | + the Display, so we should not simply reset SDL_IM here. */ |
3876 | + |
3877 | + #ifdef X_HAVE_UTF8_STRING |
3878 | + if (SDL_X11_HAVE_UTF8) { |
3879 | + /* Discard obsolete resources if any. */ |
3880 | + if (SDL_IM != NULL && SDL_Display != XDisplayOfIM(SDL_IM)) { |
3881 | + /* Just a double check. I don't think this |
3882 | + code is ever executed. */ |
3883 | + SDL_SetError("display has changed while an IM is kept"); |
3884 | + if (SDL_IC) { |
3885 | + XUnsetICFocus(SDL_IC); |
3886 | + XDestroyIC(SDL_IC); |
3887 | + SDL_IC = NULL; |
3888 | + } |
3889 | + XCloseIM(SDL_IM); |
3890 | + SDL_IM = NULL; |
3891 | + } |
3892 | + |
3893 | + /* Open an input method. */ |
3894 | + if (SDL_IM == NULL) { |
3895 | + char *old_locale = NULL, *old_modifiers = NULL; |
3896 | + const char *p; |
3897 | + size_t n; |
3898 | + /* I'm not comfortable to do locale setup |
3899 | + here. However, we need C library locale |
3900 | + (and xlib modifiers) to be set based on the |
3901 | + user's preference to use XIM, and many |
3902 | + existing game programs doesn't take care of |
3903 | + users' locale preferences, so someone other |
3904 | + than the game program should do it. |
3905 | + Moreover, ones say that some game programs |
3906 | + heavily rely on the C locale behaviour, |
3907 | + e.g., strcol()'s, and we can't change the C |
3908 | + library locale. Given the situation, I |
3909 | + couldn't find better place to do the |
3910 | + job... */ |
3911 | + |
3912 | + /* Save the current (application program's) |
3913 | + locale settings. */ |
3914 | + p = setlocale(LC_ALL, NULL); |
3915 | + if ( p ) { |
3916 | + n = SDL_strlen(p)+1; |
3917 | + old_locale = SDL_stack_alloc(char, n); |
3918 | + if ( old_locale ) { |
3919 | + SDL_strlcpy(old_locale, p, n); |
3920 | + } |
3921 | + } |
3922 | + p = XSetLocaleModifiers(NULL); |
3923 | + if ( p ) { |
3924 | + n = SDL_strlen(p)+1; |
3925 | + old_modifiers = SDL_stack_alloc(char, n); |
3926 | + if ( old_modifiers ) { |
3927 | + SDL_strlcpy(old_modifiers, p, n); |
3928 | + } |
3929 | + } |
3930 | + |
3931 | + /* Fetch the user's preferences and open the |
3932 | + input method with them. */ |
3933 | + setlocale(LC_ALL, ""); |
3934 | + XSetLocaleModifiers(""); |
3935 | + SDL_IM = XOpenIM(SDL_Display, NULL, classname, classname); |
3936 | + |
3937 | + /* Restore the application's locale settings |
3938 | + so that we don't break the application's |
3939 | + expected behaviour. */ |
3940 | + if ( old_locale ) { |
3941 | + /* We need to restore the C library |
3942 | + locale first, since the |
3943 | + interpretation of the X modifier |
3944 | + may depend on it. */ |
3945 | + setlocale(LC_ALL, old_locale); |
3946 | + SDL_stack_free(old_locale); |
3947 | + } |
3948 | + if ( old_modifiers ) { |
3949 | + XSetLocaleModifiers(old_modifiers); |
3950 | + SDL_stack_free(old_modifiers); |
3951 | + } |
3952 | + } |
3953 | + |
3954 | + /* Create a new input context for the new window just created. */ |
3955 | + if (SDL_IM == NULL) { |
3956 | + SDL_SetError("no input method could be opened"); |
3957 | + } else { |
3958 | + if (SDL_IC != NULL) { |
3959 | + /* Discard the old IC before creating new one. */ |
3960 | + XUnsetICFocus(SDL_IC); |
3961 | + XDestroyIC(SDL_IC); |
3962 | + } |
3963 | + /* Theoretically we should check the current IM supports |
3964 | + PreeditNothing+StatusNothing style (i.e., root window method) |
3965 | + before creating the IC. However, it is the bottom line method, |
3966 | + and we supports any other options. If the IM didn't support |
3967 | + root window method, the following call fails, and SDL falls |
3968 | + back to pre-XIM keyboard handling. */ |
3969 | + SDL_IC = pXCreateIC(SDL_IM, |
3970 | + XNClientWindow, WMwindow, |
3971 | + XNFocusWindow, WMwindow, |
3972 | + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, |
3973 | + XNResourceName, classname, |
3974 | + XNResourceClass, classname, |
3975 | + NULL); |
3976 | + |
3977 | + if (SDL_IC == NULL) { |
3978 | + SDL_SetError("no input context could be created"); |
3979 | + XCloseIM(SDL_IM); |
3980 | + SDL_IM = NULL; |
3981 | + } else { |
3982 | + /* We need to receive X events that an IM wants and to pass |
3983 | + them to the IM through XFilterEvent. The set of events may |
3984 | + vary depending on the IM implementation and the options |
3985 | + specified through various routes. Although unlikely, the |
3986 | + xlib specification allows IM to change the event requirement |
3987 | + with its own circumstances, it is safe to call SelectInput |
3988 | + whenever we re-create an IC. */ |
3989 | + unsigned long mask = 0; |
3990 | + char *ret = pXGetICValues(SDL_IC, XNFilterEvents, &mask, NULL); |
3991 | + if (ret != NULL) { |
3992 | + XUnsetICFocus(SDL_IC); |
3993 | + XDestroyIC(SDL_IC); |
3994 | + SDL_IC = NULL; |
3995 | + SDL_SetError("no input context could be created"); |
3996 | + XCloseIM(SDL_IM); |
3997 | + SDL_IM = NULL; |
3998 | + } else { |
3999 | + XSelectInput(SDL_Display, WMwindow, app_event_mask | mask); |
4000 | + XSetICFocus(SDL_IC); |
4001 | + } |
4002 | + } |
4003 | + } |
4004 | + } |
4005 | + #endif |
4006 | + |
4007 | + /* Allow the window to be deleted by the window manager */ |
4008 | + XSetWMProtocols(SDL_Display, WMwindow, &WM_DELETE_WINDOW, 1); |
4009 | +} |
4010 | + |
4011 | +static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat) |
4012 | +{ |
4013 | + const char *env; |
4014 | + char *display; |
4015 | + int i; |
4016 | + |
4017 | + /* Open the X11 display */ |
4018 | + display = NULL; /* Get it from DISPLAY environment variable */ |
4019 | + |
4020 | + if ( (SDL_strncmp(XDisplayName(display), ":", 1) == 0) || |
4021 | + (SDL_strncmp(XDisplayName(display), "unix:", 5) == 0) ) { |
4022 | + local_X11 = 1; |
4023 | + } else { |
4024 | + local_X11 = 0; |
4025 | + } |
4026 | + SDL_Display = XOpenDisplay(display); |
4027 | +#if defined(__osf__) && defined(SDL_VIDEO_DRIVER_X11_DYNAMIC) |
4028 | + /* On Tru64 if linking without -lX11, it fails and you get following message. |
4029 | + * Xlib: connection to ":0.0" refused by server |
4030 | + * Xlib: XDM authorization key matches an existing client! |
4031 | + * |
4032 | + * It succeeds if retrying 1 second later |
4033 | + * or if running xhost +localhost on shell. |
4034 | + * |
4035 | + */ |
4036 | + if ( SDL_Display == NULL ) { |
4037 | + SDL_Delay(1000); |
4038 | + SDL_Display = XOpenDisplay(display); |
4039 | + } |
4040 | +#endif |
4041 | + if ( SDL_Display == NULL ) { |
4042 | + SDL_SetError("Couldn't open X11 display"); |
4043 | + return(-1); |
4044 | + } |
4045 | +#ifdef X11_DEBUG |
4046 | + XSynchronize(SDL_Display, True); |
4047 | +#endif |
4048 | + |
4049 | + /* Create an alternate X display for graphics updates -- allows us |
4050 | + to do graphics updates in a separate thread from event handling. |
4051 | + Thread-safe X11 doesn't seem to exist. |
4052 | + */ |
4053 | + GFX_Display = XOpenDisplay(display); |
4054 | + if ( GFX_Display == NULL ) { |
4055 | + XCloseDisplay(SDL_Display); |
4056 | + SDL_Display = NULL; |
4057 | + SDL_SetError("Couldn't open X11 display"); |
4058 | + return(-1); |
4059 | + } |
4060 | + |
4061 | + /* Set the normal X error handler */ |
4062 | + X_handler = XSetErrorHandler(x_errhandler); |
4063 | + |
4064 | + /* Set the error handler if we lose the X display */ |
4065 | + XIO_handler = XSetIOErrorHandler(xio_errhandler); |
4066 | + |
4067 | + /* Set the X extension error handler */ |
4068 | + Xext_handler = XSetExtensionErrorHandler(xext_errhandler); |
4069 | + |
4070 | + /* use default screen (from $DISPLAY) */ |
4071 | + SDL_Screen = DefaultScreen(SDL_Display); |
4072 | + |
4073 | +#ifndef NO_SHARED_MEMORY |
4074 | + /* Check for MIT shared memory extension */ |
4075 | + use_mitshm = 0; |
4076 | + if ( local_X11 ) { |
4077 | + use_mitshm = XShmQueryExtension(SDL_Display); |
4078 | + } |
4079 | +#endif /* NO_SHARED_MEMORY */ |
4080 | + |
4081 | + /* Get the available video modes */ |
4082 | + if(X11_GetVideoModes(this) < 0) { |
4083 | + XCloseDisplay(GFX_Display); |
4084 | + GFX_Display = NULL; |
4085 | + XCloseDisplay(SDL_Display); |
4086 | + SDL_Display = NULL; |
4087 | + return -1; |
4088 | + } |
4089 | + |
4090 | + /* Determine the current screen size */ |
4091 | + this->info.current_w = DisplayWidth(SDL_Display, SDL_Screen); |
4092 | + this->info.current_h = DisplayHeight(SDL_Display, SDL_Screen); |
4093 | + |
4094 | + /* Determine the default screen depth: |
4095 | + Use the default visual (or at least one with the same depth) */ |
4096 | + SDL_DisplayColormap = DefaultColormap(SDL_Display, SDL_Screen); |
4097 | + for(i = 0; i < this->hidden->nvisuals; i++) |
4098 | + if(this->hidden->visuals[i].depth == DefaultDepth(SDL_Display, |
4099 | + SDL_Screen)) |
4100 | + break; |
4101 | + if(i == this->hidden->nvisuals) { |
4102 | + /* default visual was useless, take the deepest one instead */ |
4103 | + i = 0; |
4104 | + } |
4105 | + SDL_Visual = this->hidden->visuals[i].visual; |
4106 | + if ( SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen) ) { |
4107 | + SDL_XColorMap = SDL_DisplayColormap; |
4108 | + } else { |
4109 | + SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, |
4110 | + SDL_Visual, AllocNone); |
4111 | + } |
4112 | + this->hidden->depth = this->hidden->visuals[i].depth; |
4113 | + vformat->BitsPerPixel = this->hidden->visuals[i].bpp; |
4114 | + if ( vformat->BitsPerPixel > 8 ) { |
4115 | + vformat->Rmask = SDL_Visual->red_mask; |
4116 | + vformat->Gmask = SDL_Visual->green_mask; |
4117 | + vformat->Bmask = SDL_Visual->blue_mask; |
4118 | + } |
4119 | + if ( this->hidden->depth == 32 ) { |
4120 | + vformat->Amask = (0xFFFFFFFF & ~(vformat->Rmask|vformat->Gmask|vformat->Bmask)); |
4121 | + } |
4122 | + X11_SaveVidModeGamma(this); |
4123 | + |
4124 | + /* Allow environment override of screensaver disable. */ |
4125 | + env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER"); |
4126 | + if ( env ) { |
4127 | + allow_screensaver = SDL_atoi(env); |
4128 | + } else { |
4129 | +#ifdef SDL_VIDEO_DISABLE_SCREENSAVER |
4130 | + allow_screensaver = 0; |
4131 | +#else |
4132 | + allow_screensaver = 1; |
4133 | +#endif |
4134 | + } |
4135 | + |
4136 | + /* See if we have been passed a window to use */ |
4137 | + SDL_windowid = SDL_getenv("SDL_WINDOWID"); |
4138 | + |
4139 | + /* Create the fullscreen and managed windows */ |
4140 | + create_aux_windows(this); |
4141 | + |
4142 | + /* Create the blank cursor */ |
4143 | + SDL_BlankCursor = this->CreateWMCursor(this, blank_cdata, blank_cmask, |
4144 | + BLANK_CWIDTH, BLANK_CHEIGHT, |
4145 | + BLANK_CHOTX, BLANK_CHOTY); |
4146 | + |
4147 | + /* Fill in some window manager capabilities */ |
4148 | + this->info.wm_available = 1; |
4149 | + |
4150 | + /* We're done! */ |
4151 | + XFlush(SDL_Display); |
4152 | + return(0); |
4153 | +} |
4154 | + |
4155 | +static void X11_DestroyWindow(_THIS, SDL_Surface *screen) |
4156 | +{ |
4157 | + /* Clean up OpenGL */ |
4158 | + if ( screen ) { |
4159 | + screen->flags &= ~(SDL_OPENGL|SDL_OPENGLBLIT); |
4160 | + } |
4161 | + X11_GL_Shutdown(this); |
4162 | + |
4163 | + if ( ! SDL_windowid ) { |
4164 | + /* Hide the managed window */ |
4165 | + if ( WMwindow ) { |
4166 | + XUnmapWindow(SDL_Display, WMwindow); |
4167 | + } |
4168 | + if ( screen && (screen->flags & SDL_FULLSCREEN) ) { |
4169 | + screen->flags &= ~SDL_FULLSCREEN; |
4170 | + X11_LeaveFullScreen(this); |
4171 | + } |
4172 | + |
4173 | + /* Destroy the output window */ |
4174 | + if ( SDL_Window ) { |
4175 | + XDestroyWindow(SDL_Display, SDL_Window); |
4176 | + } |
4177 | + |
4178 | + /* Free the colormap entries */ |
4179 | + if ( SDL_XPixels ) { |
4180 | + int numcolors; |
4181 | + unsigned long pixel; |
4182 | + numcolors = SDL_Visual->map_entries; |
4183 | + for ( pixel=0; pixel<numcolors; ++pixel ) { |
4184 | + while ( SDL_XPixels[pixel] > 0 ) { |
4185 | + XFreeColors(GFX_Display, |
4186 | + SDL_DisplayColormap,&pixel,1,0); |
4187 | + --SDL_XPixels[pixel]; |
4188 | + } |
4189 | + } |
4190 | + SDL_free(SDL_XPixels); |
4191 | + SDL_XPixels = NULL; |
4192 | + } |
4193 | + |
4194 | + /* Free the graphics context */ |
4195 | + if ( SDL_GC ) { |
4196 | + XFreeGC(SDL_Display, SDL_GC); |
4197 | + SDL_GC = 0; |
4198 | + } |
4199 | + } |
4200 | +} |
4201 | + |
4202 | +static SDL_bool X11_WindowPosition(_THIS, int *x, int *y, int w, int h) |
4203 | +{ |
4204 | + const char *window = SDL_getenv("SDL_VIDEO_WINDOW_POS"); |
4205 | + const char *center = SDL_getenv("SDL_VIDEO_CENTERED"); |
4206 | + if ( window ) { |
4207 | + if ( SDL_sscanf(window, "%d,%d", x, y) == 2 ) { |
4208 | + return SDL_TRUE; |
4209 | + } |
4210 | + if ( SDL_strcmp(window, "center") == 0 ) { |
4211 | + center = window; |
4212 | + } |
4213 | + } |
4214 | + if ( center ) { |
4215 | + *x = (DisplayWidth(SDL_Display, SDL_Screen) - w)/2; |
4216 | + *y = (DisplayHeight(SDL_Display, SDL_Screen) - h)/2; |
4217 | + return SDL_TRUE; |
4218 | + } |
4219 | + return SDL_FALSE; |
4220 | +} |
4221 | + |
4222 | +static void X11_SetSizeHints(_THIS, int w, int h, Uint32 flags) |
4223 | +{ |
4224 | + XSizeHints *hints; |
4225 | + |
4226 | + hints = XAllocSizeHints(); |
4227 | + if ( hints ) { |
4228 | + if (!(flags & SDL_RESIZABLE)) { |
4229 | + hints->min_width = hints->max_width = w; |
4230 | + hints->min_height = hints->max_height = h; |
4231 | + hints->flags = PMaxSize | PMinSize; |
4232 | + } |
4233 | + if ( flags & SDL_FULLSCREEN ) { |
4234 | + hints->x = 0; |
4235 | + hints->y = 0; |
4236 | + hints->flags |= USPosition; |
4237 | + } else |
4238 | + /* Center it, if desired */ |
4239 | + if ( X11_WindowPosition(this, &hints->x, &hints->y, w, h) ) { |
4240 | + hints->flags |= USPosition; |
4241 | + |
4242 | + /* Hints must be set before moving the window, otherwise an |
4243 | + unwanted ConfigureNotify event will be issued */ |
4244 | + XSetWMNormalHints(SDL_Display, WMwindow, hints); |
4245 | + |
4246 | + XMoveWindow(SDL_Display, WMwindow, hints->x, hints->y); |
4247 | + |
4248 | + /* Flush the resize event so we don't catch it later */ |
4249 | + XSync(SDL_Display, True); |
4250 | + } |
4251 | + XSetWMNormalHints(SDL_Display, WMwindow, hints); |
4252 | + XFree(hints); |
4253 | + } |
4254 | + |
4255 | + /* Respect the window caption style */ |
4256 | + if ( flags & SDL_NOFRAME ) { |
4257 | + SDL_bool set; |
4258 | + Atom WM_HINTS; |
4259 | + |
4260 | + /* We haven't modified the window manager hints yet */ |
4261 | + set = SDL_FALSE; |
4262 | + |
4263 | + /* First try to set MWM hints */ |
4264 | + WM_HINTS = XInternAtom(SDL_Display, "_MOTIF_WM_HINTS", True); |
4265 | + if ( WM_HINTS != None ) { |
4266 | + /* Hints used by Motif compliant window managers */ |
4267 | + struct { |
4268 | + unsigned long flags; |
4269 | + unsigned long functions; |
4270 | + unsigned long decorations; |
4271 | + long input_mode; |
4272 | + unsigned long status; |
4273 | + } MWMHints = { (1L << 1), 0, 0, 0, 0 }; |
4274 | + |
4275 | + XChangeProperty(SDL_Display, WMwindow, |
4276 | + WM_HINTS, WM_HINTS, 32, |
4277 | + PropModeReplace, |
4278 | + (unsigned char *)&MWMHints, |
4279 | + sizeof(MWMHints)/sizeof(long)); |
4280 | + set = SDL_TRUE; |
4281 | + } |
4282 | + /* Now try to set KWM hints */ |
4283 | + WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True); |
4284 | + if ( WM_HINTS != None ) { |
4285 | + long KWMHints = 0; |
4286 | + |
4287 | + XChangeProperty(SDL_Display, WMwindow, |
4288 | + WM_HINTS, WM_HINTS, 32, |
4289 | + PropModeReplace, |
4290 | + (unsigned char *)&KWMHints, |
4291 | + sizeof(KWMHints)/sizeof(long)); |
4292 | + set = SDL_TRUE; |
4293 | + } |
4294 | + /* Now try to set GNOME hints */ |
4295 | + WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True); |
4296 | + if ( WM_HINTS != None ) { |
4297 | + long GNOMEHints = 0; |
4298 | + |
4299 | + XChangeProperty(SDL_Display, WMwindow, |
4300 | + WM_HINTS, WM_HINTS, 32, |
4301 | + PropModeReplace, |
4302 | + (unsigned char *)&GNOMEHints, |
4303 | + sizeof(GNOMEHints)/sizeof(long)); |
4304 | + set = SDL_TRUE; |
4305 | + } |
4306 | + /* Finally set the transient hints if necessary */ |
4307 | + if ( ! set ) { |
4308 | + XSetTransientForHint(SDL_Display, WMwindow, SDL_Root); |
4309 | + } |
4310 | + } else { |
4311 | + SDL_bool set; |
4312 | + Atom WM_HINTS; |
4313 | + |
4314 | + /* We haven't modified the window manager hints yet */ |
4315 | + set = SDL_FALSE; |
4316 | + |
4317 | + /* First try to unset MWM hints */ |
4318 | + WM_HINTS = XInternAtom(SDL_Display, "_MOTIF_WM_HINTS", True); |
4319 | + if ( WM_HINTS != None ) { |
4320 | + XDeleteProperty(SDL_Display, WMwindow, WM_HINTS); |
4321 | + set = SDL_TRUE; |
4322 | + } |
4323 | + /* Now try to unset KWM hints */ |
4324 | + WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True); |
4325 | + if ( WM_HINTS != None ) { |
4326 | + XDeleteProperty(SDL_Display, WMwindow, WM_HINTS); |
4327 | + set = SDL_TRUE; |
4328 | + } |
4329 | + /* Now try to unset GNOME hints */ |
4330 | + WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True); |
4331 | + if ( WM_HINTS != None ) { |
4332 | + XDeleteProperty(SDL_Display, WMwindow, WM_HINTS); |
4333 | + set = SDL_TRUE; |
4334 | + } |
4335 | + /* Finally unset the transient hints if necessary */ |
4336 | + if ( ! set ) { |
4337 | + XDeleteProperty(SDL_Display, WMwindow, XA_WM_TRANSIENT_FOR); |
4338 | + } |
4339 | + } |
4340 | +} |
4341 | + |
4342 | +static int X11_CreateWindow(_THIS, SDL_Surface *screen, |
4343 | + int w, int h, int bpp, Uint32 flags) |
4344 | +{ |
4345 | + int i, depth; |
4346 | + Visual *vis; |
4347 | + int vis_change; |
4348 | + Uint32 Amask; |
4349 | + |
4350 | + /* If a window is already present, destroy it and start fresh */ |
4351 | + if ( SDL_Window ) { |
4352 | + X11_DestroyWindow(this, screen); |
4353 | + switch_waiting = 0; /* Prevent jump back to now-meaningless state. */ |
4354 | + } |
4355 | + |
4356 | + /* See if we have been given a window id */ |
4357 | + if ( SDL_windowid ) { |
4358 | + SDL_Window = SDL_strtol(SDL_windowid, NULL, 0); |
4359 | + } else { |
4360 | + SDL_Window = 0; |
4361 | + } |
4362 | + |
4363 | + /* find out which visual we are going to use */ |
4364 | + if ( flags & SDL_OPENGL ) { |
4365 | + XVisualInfo *vi; |
4366 | + |
4367 | + vi = X11_GL_GetVisual(this); |
4368 | + if( !vi ) { |
4369 | + return -1; |
4370 | + } |
4371 | + vis = vi->visual; |
4372 | + depth = vi->depth; |
4373 | + } else if ( SDL_windowid ) { |
4374 | + XWindowAttributes a; |
4375 | + |
4376 | + XGetWindowAttributes(SDL_Display, SDL_Window, &a); |
4377 | + vis = a.visual; |
4378 | + depth = a.depth; |
4379 | + } else { |
4380 | + for ( i = 0; i < this->hidden->nvisuals; i++ ) { |
4381 | + if ( this->hidden->visuals[i].bpp == bpp ) |
4382 | + break; |
4383 | + } |
4384 | + if ( i == this->hidden->nvisuals ) { |
4385 | + SDL_SetError("No matching visual for requested depth"); |
4386 | + return -1; /* should never happen */ |
4387 | + } |
4388 | + vis = this->hidden->visuals[i].visual; |
4389 | + depth = this->hidden->visuals[i].depth; |
4390 | + } |
4391 | +#ifdef X11_DEBUG |
4392 | + printf("Choosing %s visual at %d bpp - %d colormap entries\n", vis->class == PseudoColor ? "PseudoColor" : (vis->class == TrueColor ? "TrueColor" : (vis->class == DirectColor ? "DirectColor" : "Unknown")), depth, vis->map_entries); |
4393 | +#endif |
4394 | + vis_change = (vis != SDL_Visual); |
4395 | + SDL_Visual = vis; |
4396 | + this->hidden->depth = depth; |
4397 | + |
4398 | + /* Allocate the new pixel format for this video mode */ |
4399 | + if ( this->hidden->depth == 32 ) { |
4400 | + Amask = (0xFFFFFFFF & ~(vis->red_mask|vis->green_mask|vis->blue_mask)); |
4401 | + } else { |
4402 | + Amask = 0; |
4403 | + } |
4404 | + if ( ! SDL_ReallocFormat(screen, bpp, |
4405 | + vis->red_mask, vis->green_mask, vis->blue_mask, Amask) ) { |
4406 | + return -1; |
4407 | + } |
4408 | + |
4409 | + /* Create the appropriate colormap */ |
4410 | + if ( SDL_XColorMap != SDL_DisplayColormap ) { |
4411 | + XFreeColormap(SDL_Display, SDL_XColorMap); |
4412 | + } |
4413 | + if ( SDL_Visual->class == PseudoColor ) { |
4414 | + int ncolors; |
4415 | + |
4416 | + /* Allocate the pixel flags */ |
4417 | + ncolors = SDL_Visual->map_entries; |
4418 | + SDL_XPixels = SDL_malloc(ncolors * sizeof(int)); |
4419 | + if(SDL_XPixels == NULL) { |
4420 | + SDL_OutOfMemory(); |
4421 | + return -1; |
4422 | + } |
4423 | + SDL_memset(SDL_XPixels, 0, ncolors * sizeof(*SDL_XPixels)); |
4424 | + |
4425 | + /* always allocate a private colormap on non-default visuals */ |
4426 | + if ( SDL_Visual != DefaultVisual(SDL_Display, SDL_Screen) ) { |
4427 | + flags |= SDL_HWPALETTE; |
4428 | + } |
4429 | + if ( flags & SDL_HWPALETTE ) { |
4430 | + screen->flags |= SDL_HWPALETTE; |
4431 | + SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, |
4432 | + SDL_Visual, AllocAll); |
4433 | + } else { |
4434 | + SDL_XColorMap = SDL_DisplayColormap; |
4435 | + } |
4436 | + } else if ( SDL_Visual->class == DirectColor ) { |
4437 | + |
4438 | + /* Create a colormap which we can manipulate for gamma */ |
4439 | + SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, |
4440 | + SDL_Visual, AllocAll); |
4441 | + XSync(SDL_Display, False); |
4442 | + |
4443 | + /* Initialize the colormap to the identity mapping */ |
4444 | + SDL_GetGammaRamp(0, 0, 0); |
4445 | + this->screen = screen; |
4446 | + X11_SetGammaRamp(this, this->gamma); |
4447 | + this->screen = NULL; |
4448 | + } else { |
4449 | + /* Create a read-only colormap for our window */ |
4450 | + SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, |
4451 | + SDL_Visual, AllocNone); |
4452 | + } |
4453 | + |
4454 | + /* Recreate the auxiliary windows, if needed (required for GL) */ |
4455 | + if ( vis_change ) |
4456 | + create_aux_windows(this); |
4457 | + |
4458 | + if(screen->flags & SDL_HWPALETTE) { |
4459 | + /* Since the full-screen window might have got a nonzero background |
4460 | + colour (0 is white on some displays), we should reset the |
4461 | + background to 0 here since that is what the user expects |
4462 | + with a private colormap */ |
4463 | + XSetWindowBackground(SDL_Display, FSwindow, 0); |
4464 | + XClearWindow(SDL_Display, FSwindow); |
4465 | + } |
4466 | + |
4467 | + /* resize the (possibly new) window manager window */ |
4468 | + if( !SDL_windowid ) { |
4469 | + X11_SetSizeHints(this, w, h, flags); |
4470 | + window_w = w; |
4471 | + window_h = h; |
4472 | + XResizeWindow(SDL_Display, WMwindow, w, h); |
4473 | + } |
4474 | + |
4475 | + /* Create (or use) the X11 display window */ |
4476 | + if ( !SDL_windowid ) { |
4477 | + if ( flags & SDL_OPENGL ) { |
4478 | + if ( X11_GL_CreateWindow(this, w, h) < 0 ) { |
4479 | + return(-1); |
4480 | + } |
4481 | + } else { |
4482 | + XSetWindowAttributes swa; |
4483 | + |
4484 | + swa.background_pixel = 0; |
4485 | + swa.border_pixel = 0; |
4486 | + swa.colormap = SDL_XColorMap; |
4487 | + SDL_Window = XCreateWindow(SDL_Display, WMwindow, |
4488 | + 0, 0, w, h, 0, depth, |
4489 | + InputOutput, SDL_Visual, |
4490 | + CWBackPixel | CWBorderPixel |
4491 | + | CWColormap, &swa); |
4492 | + } |
4493 | + /* Only manage our input if we own the window */ |
4494 | + XSelectInput(SDL_Display, SDL_Window, |
4495 | + ( EnterWindowMask | LeaveWindowMask |
4496 | + | ButtonPressMask | ButtonReleaseMask |
4497 | + | PointerMotionMask | ExposureMask )); |
4498 | + } |
4499 | + /* Create the graphics context here, once we have a window */ |
4500 | + if ( flags & SDL_OPENGL ) { |
4501 | + if ( X11_GL_CreateContext(this) < 0 ) { |
4502 | + return(-1); |
4503 | + } else { |
4504 | + screen->flags |= SDL_OPENGL; |
4505 | + } |
4506 | + } else { |
4507 | + XGCValues gcv; |
4508 | + |
4509 | + gcv.graphics_exposures = False; |
4510 | + SDL_GC = XCreateGC(SDL_Display, SDL_Window, |
4511 | + GCGraphicsExposures, &gcv); |
4512 | + if ( ! SDL_GC ) { |
4513 | + SDL_SetError("Couldn't create graphics context"); |
4514 | + return(-1); |
4515 | + } |
4516 | + } |
4517 | + |
4518 | + /* Set our colormaps when not setting a GL mode */ |
4519 | + if ( ! (flags & SDL_OPENGL) ) { |
4520 | + XSetWindowColormap(SDL_Display, SDL_Window, SDL_XColorMap); |
4521 | + if( !SDL_windowid ) { |
4522 | + XSetWindowColormap(SDL_Display, FSwindow, SDL_XColorMap); |
4523 | + XSetWindowColormap(SDL_Display, WMwindow, SDL_XColorMap); |
4524 | + } |
4525 | + } |
4526 | + |
4527 | +#if 0 /* This is an experiment - are the graphics faster now? - nope. */ |
4528 | + if ( SDL_getenv("SDL_VIDEO_X11_BACKINGSTORE") ) |
4529 | +#endif |
4530 | + /* Cache the window in the server, when possible */ |
4531 | + { |
4532 | + Screen *xscreen; |
4533 | + XSetWindowAttributes a; |
4534 | + |
4535 | + xscreen = ScreenOfDisplay(SDL_Display, SDL_Screen); |
4536 | + a.backing_store = DoesBackingStore(xscreen); |
4537 | + if ( a.backing_store != NotUseful ) { |
4538 | + XChangeWindowAttributes(SDL_Display, SDL_Window, |
4539 | + CWBackingStore, &a); |
4540 | + } |
4541 | + } |
4542 | + |
4543 | + /* Map them both and go fullscreen, if requested */ |
4544 | + if ( ! SDL_windowid ) { |
4545 | + XMapWindow(SDL_Display, SDL_Window); |
4546 | + XMapWindow(SDL_Display, WMwindow); |
4547 | + X11_WaitMapped(this, WMwindow); |
4548 | + if ( flags & SDL_FULLSCREEN ) { |
4549 | + screen->flags |= SDL_FULLSCREEN; |
4550 | + X11_EnterFullScreen(this); |
4551 | + } else { |
4552 | + screen->flags &= ~SDL_FULLSCREEN; |
4553 | + } |
4554 | + } |
4555 | + |
4556 | + return(0); |
4557 | +} |
4558 | + |
4559 | +static int X11_ResizeWindow(_THIS, |
4560 | + SDL_Surface *screen, int w, int h, Uint32 flags) |
4561 | +{ |
4562 | + if ( ! SDL_windowid ) { |
4563 | + /* Resize the window manager window */ |
4564 | + X11_SetSizeHints(this, w, h, flags); |
4565 | + window_w = w; |
4566 | + window_h = h; |
4567 | + XResizeWindow(SDL_Display, WMwindow, w, h); |
4568 | + |
4569 | + /* Resize the fullscreen and display windows */ |
4570 | + if ( flags & SDL_FULLSCREEN ) { |
4571 | + if ( screen->flags & SDL_FULLSCREEN ) { |
4572 | + X11_ResizeFullScreen(this); |
4573 | + } else { |
4574 | + screen->flags |= SDL_FULLSCREEN; |
4575 | + X11_EnterFullScreen(this); |
4576 | + } |
4577 | + } else { |
4578 | + if ( screen->flags & SDL_FULLSCREEN ) { |
4579 | + screen->flags &= ~SDL_FULLSCREEN; |
4580 | + X11_LeaveFullScreen(this); |
4581 | + } |
4582 | + } |
4583 | + XResizeWindow(SDL_Display, SDL_Window, w, h); |
4584 | + } |
4585 | + return(0); |
4586 | +} |
4587 | + |
4588 | +SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current, |
4589 | + int width, int height, int bpp, Uint32 flags) |
4590 | +{ |
4591 | + Uint32 saved_flags; |
4592 | + |
4593 | + /* Lock the event thread, in multi-threading environments */ |
4594 | + SDL_Lock_EventThread(); |
4595 | + |
4596 | + /* Check the combination of flags we were passed */ |
4597 | + if ( flags & SDL_FULLSCREEN ) { |
4598 | + /* Clear fullscreen flag if not supported */ |
4599 | + if ( SDL_windowid ) { |
4600 | + flags &= ~SDL_FULLSCREEN; |
4601 | + } |
4602 | + } |
4603 | + |
4604 | + /* Flush any delayed updates */ |
4605 | + XSync(GFX_Display, False); |
4606 | + |
4607 | + /* Set up the X11 window */ |
4608 | + saved_flags = current->flags; |
4609 | + if ( (SDL_Window) && ((saved_flags&SDL_OPENGL) == (flags&SDL_OPENGL)) |
4610 | + && (bpp == current->format->BitsPerPixel) |
4611 | + && ((saved_flags&SDL_NOFRAME) == (flags&SDL_NOFRAME)) ) { |
4612 | + if (X11_ResizeWindow(this, current, width, height, flags) < 0) { |
4613 | + current = NULL; |
4614 | + goto done; |
4615 | + } |
4616 | + X11_PendingConfigureNotifyWidth = width; |
4617 | + X11_PendingConfigureNotifyHeight = height; |
4618 | + } else { |
4619 | + if (X11_CreateWindow(this,current,width,height,bpp,flags) < 0) { |
4620 | + current = NULL; |
4621 | + goto done; |
4622 | + } |
4623 | + } |
4624 | + |
4625 | + /* Update the internal keyboard state */ |
4626 | + X11_SetKeyboardState(SDL_Display, NULL); |
4627 | + |
4628 | + /* When the window is first mapped, ignore non-modifier keys */ |
4629 | + if ( !current->w && !current->h ) { |
4630 | + Uint8 *keys = SDL_GetKeyState(NULL); |
4631 | + int i; |
4632 | + for ( i = 0; i < SDLK_LAST; ++i ) { |
4633 | + switch (i) { |
4634 | + case SDLK_NUMLOCK: |
4635 | + case SDLK_CAPSLOCK: |
4636 | + case SDLK_LCTRL: |
4637 | + case SDLK_RCTRL: |
4638 | + case SDLK_LSHIFT: |
4639 | + case SDLK_RSHIFT: |
4640 | + case SDLK_LALT: |
4641 | + case SDLK_RALT: |
4642 | + case SDLK_LMETA: |
4643 | + case SDLK_RMETA: |
4644 | + case SDLK_MODE: |
4645 | + break; |
4646 | + default: |
4647 | + keys[i] = SDL_RELEASED; |
4648 | + break; |
4649 | + } |
4650 | + } |
4651 | + } |
4652 | + |
4653 | + /* Set up the new mode framebuffer */ |
4654 | + if ( ((current->w != width) || (current->h != height)) || |
4655 | + ((saved_flags&SDL_OPENGL) != (flags&SDL_OPENGL)) ) { |
4656 | + current->w = width; |
4657 | + current->h = height; |
4658 | + current->pitch = SDL_CalculatePitch(current); |
4659 | + if (X11_ResizeImage(this, current, flags) < 0) { |
4660 | + current = NULL; |
4661 | + goto done; |
4662 | + } |
4663 | + } |
4664 | + |
4665 | + /* Clear these flags and set them only if they are in the new set. */ |
4666 | + current->flags &= ~(SDL_RESIZABLE|SDL_NOFRAME); |
4667 | + current->flags |= (flags&(SDL_RESIZABLE|SDL_NOFRAME)); |
4668 | + |
4669 | + done: |
4670 | + /* Release the event thread */ |
4671 | + XSync(SDL_Display, False); |
4672 | + SDL_Unlock_EventThread(); |
4673 | + |
4674 | + /* We're done! */ |
4675 | + return(current); |
4676 | +} |
4677 | + |
4678 | +static int X11_ToggleFullScreen(_THIS, int on) |
4679 | +{ |
4680 | + Uint32 event_thread; |
4681 | + |
4682 | + /* Don't switch if we don't own the window */ |
4683 | + if ( SDL_windowid ) { |
4684 | + return(0); |
4685 | + } |
4686 | + |
4687 | + /* Don't lock if we are the event thread */ |
4688 | + event_thread = SDL_EventThreadID(); |
4689 | + if ( event_thread && (SDL_ThreadID() == event_thread) ) { |
4690 | + event_thread = 0; |
4691 | + } |
4692 | + if ( event_thread ) { |
4693 | + SDL_Lock_EventThread(); |
4694 | + } |
4695 | + if ( on ) { |
4696 | + this->screen->flags |= SDL_FULLSCREEN; |
4697 | + X11_EnterFullScreen(this); |
4698 | + } else { |
4699 | + this->screen->flags &= ~SDL_FULLSCREEN; |
4700 | + X11_LeaveFullScreen(this); |
4701 | + } |
4702 | + X11_RefreshDisplay(this); |
4703 | + if ( event_thread ) { |
4704 | + SDL_Unlock_EventThread(); |
4705 | + } |
4706 | + SDL_ResetKeyboard(); |
4707 | + return(1); |
4708 | +} |
4709 | + |
4710 | +/* Update the current mouse state and position */ |
4711 | +static void X11_UpdateMouse(_THIS) |
4712 | +{ |
4713 | + Window u1; int u2; |
4714 | + Window current_win; |
4715 | + int x, y; |
4716 | + unsigned int mask; |
4717 | + |
4718 | + /* Lock the event thread, in multi-threading environments */ |
4719 | + SDL_Lock_EventThread(); |
4720 | + if ( XQueryPointer(SDL_Display, SDL_Window, &u1, ¤t_win, |
4721 | + &u2, &u2, &x, &y, &mask) ) { |
4722 | + if ( (x >= 0) && (x < SDL_VideoSurface->w) && |
4723 | + (y >= 0) && (y < SDL_VideoSurface->h) ) { |
4724 | + SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); |
4725 | + SDL_PrivateMouseMotion(0, 0, x, y); |
4726 | + } else { |
4727 | + SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); |
4728 | + } |
4729 | + } |
4730 | + SDL_Unlock_EventThread(); |
4731 | +} |
4732 | + |
4733 | +/* simple colour distance metric. Supposed to be better than a plain |
4734 | + Euclidian distance anyway. */ |
4735 | +#define COLOUR_FACTOR 3 |
4736 | +#define LIGHT_FACTOR 1 |
4737 | +#define COLOUR_DIST(r1, g1, b1, r2, g2, b2) \ |
4738 | + (COLOUR_FACTOR * (abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2)) \ |
4739 | + + LIGHT_FACTOR * abs(r1 + g1 + b1 - (r2 + g2 + b2))) |
4740 | + |
4741 | +static void allocate_nearest(_THIS, SDL_Color *colors, |
4742 | + SDL_Color *want, int nwant) |
4743 | +{ |
4744 | + /* |
4745 | + * There is no way to know which ones to choose from, so we retrieve |
4746 | + * the entire colormap and try the nearest possible, until we find one |
4747 | + * that is shared. |
4748 | + */ |
4749 | + XColor all[256]; |
4750 | + int i; |
4751 | + for(i = 0; i < 256; i++) |
4752 | + all[i].pixel = i; |
4753 | + /* |
4754 | + * XQueryColors sets the flags in the XColor struct, so we use |
4755 | + * that to keep track of which colours are available |
4756 | + */ |
4757 | + XQueryColors(GFX_Display, SDL_XColorMap, all, 256); |
4758 | + |
4759 | + for(i = 0; i < nwant; i++) { |
4760 | + XColor *c; |
4761 | + int j; |
4762 | + int best = 0; |
4763 | + int mindist = 0x7fffffff; |
4764 | + int ri = want[i].r; |
4765 | + int gi = want[i].g; |
4766 | + int bi = want[i].b; |
4767 | + for(j = 0; j < 256; j++) { |
4768 | + int rj, gj, bj, d2; |
4769 | + if(!all[j].flags) |
4770 | + continue; /* unavailable colour cell */ |
4771 | + rj = all[j].red >> 8; |
4772 | + gj = all[j].green >> 8; |
4773 | + bj = all[j].blue >> 8; |
4774 | + d2 = COLOUR_DIST(ri, gi, bi, rj, gj, bj); |
4775 | + if(d2 < mindist) { |
4776 | + mindist = d2; |
4777 | + best = j; |
4778 | + } |
4779 | + } |
4780 | + if(SDL_XPixels[best]) |
4781 | + continue; /* already allocated, waste no more time */ |
4782 | + c = all + best; |
4783 | + if(XAllocColor(GFX_Display, SDL_XColorMap, c)) { |
4784 | + /* got it */ |
4785 | + colors[c->pixel].r = c->red >> 8; |
4786 | + colors[c->pixel].g = c->green >> 8; |
4787 | + colors[c->pixel].b = c->blue >> 8; |
4788 | + ++SDL_XPixels[c->pixel]; |
4789 | + } else { |
4790 | + /* |
4791 | + * The colour couldn't be allocated, probably being |
4792 | + * owned as a r/w cell by another client. Flag it as |
4793 | + * unavailable and try again. The termination of the |
4794 | + * loop is guaranteed since at least black and white |
4795 | + * are always there. |
4796 | + */ |
4797 | + c->flags = 0; |
4798 | + i--; |
4799 | + } |
4800 | + } |
4801 | +} |
4802 | + |
4803 | +int X11_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) |
4804 | +{ |
4805 | + int nrej = 0; |
4806 | + |
4807 | + /* Check to make sure we have a colormap allocated */ |
4808 | + if ( SDL_XPixels == NULL ) { |
4809 | + return(0); |
4810 | + } |
4811 | + if ( (this->screen->flags & SDL_HWPALETTE) == SDL_HWPALETTE ) { |
4812 | + /* private writable colormap: just set the colours we need */ |
4813 | + XColor *xcmap; |
4814 | + int i; |
4815 | + xcmap = SDL_stack_alloc(XColor, ncolors); |
4816 | + if(xcmap == NULL) |
4817 | + return 0; |
4818 | + for ( i=0; i<ncolors; ++i ) { |
4819 | + xcmap[i].pixel = i + firstcolor; |
4820 | + xcmap[i].red = (colors[i].r<<8)|colors[i].r; |
4821 | + xcmap[i].green = (colors[i].g<<8)|colors[i].g; |
4822 | + xcmap[i].blue = (colors[i].b<<8)|colors[i].b; |
4823 | + xcmap[i].flags = (DoRed|DoGreen|DoBlue); |
4824 | + } |
4825 | + XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors); |
4826 | + XSync(GFX_Display, False); |
4827 | + SDL_stack_free(xcmap); |
4828 | + } else { |
4829 | + /* |
4830 | + * Shared colormap: We only allocate read-only cells, which |
4831 | + * increases the likelyhood of colour sharing with other |
4832 | + * clients. The pixel values will almost certainly be |
4833 | + * different from the requested ones, so the user has to |
4834 | + * walk the colormap and see which index got what colour. |
4835 | + * |
4836 | + * We can work directly with the logical palette since it |
4837 | + * has already been set when we get here. |
4838 | + */ |
4839 | + SDL_Color *want, *reject; |
4840 | + unsigned long *freelist; |
4841 | + int i; |
4842 | + int nfree = 0; |
4843 | + int nc = this->screen->format->palette->ncolors; |
4844 | + colors = this->screen->format->palette->colors; |
4845 | + freelist = SDL_stack_alloc(unsigned long, nc); |
4846 | + /* make sure multiple allocations of the same cell are freed */ |
4847 | + for(i = 0; i < ncolors; i++) { |
4848 | + int pixel = firstcolor + i; |
4849 | + while(SDL_XPixels[pixel]) { |
4850 | + freelist[nfree++] = pixel; |
4851 | + --SDL_XPixels[pixel]; |
4852 | + } |
4853 | + } |
4854 | + XFreeColors(GFX_Display, SDL_XColorMap, freelist, nfree, 0); |
4855 | + SDL_stack_free(freelist); |
4856 | + |
4857 | + want = SDL_stack_alloc(SDL_Color, ncolors); |
4858 | + reject = SDL_stack_alloc(SDL_Color, ncolors); |
4859 | + SDL_memcpy(want, colors + firstcolor, ncolors * sizeof(SDL_Color)); |
4860 | + /* make sure the user isn't fooled by her own wishes |
4861 | + (black is safe, always available in the default colormap) */ |
4862 | + SDL_memset(colors + firstcolor, 0, ncolors * sizeof(SDL_Color)); |
4863 | + |
4864 | + /* now try to allocate the colours */ |
4865 | + for(i = 0; i < ncolors; i++) { |
4866 | + XColor col; |
4867 | + col.red = want[i].r << 8; |
4868 | + col.green = want[i].g << 8; |
4869 | + col.blue = want[i].b << 8; |
4870 | + col.flags = DoRed | DoGreen | DoBlue; |
4871 | + if(XAllocColor(GFX_Display, SDL_XColorMap, &col)) { |
4872 | + /* We got the colour, or at least the nearest |
4873 | + the hardware could get. */ |
4874 | + colors[col.pixel].r = col.red >> 8; |
4875 | + colors[col.pixel].g = col.green >> 8; |
4876 | + colors[col.pixel].b = col.blue >> 8; |
4877 | + ++SDL_XPixels[col.pixel]; |
4878 | + } else { |
4879 | + /* |
4880 | + * no more free cells, add it to the list |
4881 | + * of rejected colours |
4882 | + */ |
4883 | + reject[nrej++] = want[i]; |
4884 | + } |
4885 | + } |
4886 | + if(nrej) |
4887 | + allocate_nearest(this, colors, reject, nrej); |
4888 | + SDL_stack_free(reject); |
4889 | + SDL_stack_free(want); |
4890 | + } |
4891 | + return nrej == 0; |
4892 | +} |
4893 | + |
4894 | +int X11_SetGammaRamp(_THIS, Uint16 *ramp) |
4895 | +{ |
4896 | + int i, ncolors; |
4897 | + XColor xcmap[256]; |
4898 | + |
4899 | + /* See if actually setting the gamma is supported */ |
4900 | + if ( SDL_Visual->class != DirectColor ) { |
4901 | + SDL_SetError("Gamma correction not supported on this visual"); |
4902 | + return(-1); |
4903 | + } |
4904 | + |
4905 | + /* Calculate the appropriate palette for the given gamma ramp */ |
4906 | + ncolors = SDL_Visual->map_entries; |
4907 | + for ( i=0; i<ncolors; ++i ) { |
4908 | + Uint8 c = (256 * i / ncolors); |
4909 | + xcmap[i].pixel = SDL_MapRGB(this->screen->format, c, c, c); |
4910 | + xcmap[i].red = ramp[0*256+c]; |
4911 | + xcmap[i].green = ramp[1*256+c]; |
4912 | + xcmap[i].blue = ramp[2*256+c]; |
4913 | + xcmap[i].flags = (DoRed|DoGreen|DoBlue); |
4914 | + } |
4915 | + XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors); |
4916 | + XSync(GFX_Display, False); |
4917 | + return(0); |
4918 | +} |
4919 | + |
4920 | +/* Note: If we are terminated, this could be called in the middle of |
4921 | + another SDL video routine -- notably UpdateRects. |
4922 | +*/ |
4923 | +void X11_VideoQuit(_THIS) |
4924 | +{ |
4925 | + /* Shutdown everything that's still up */ |
4926 | + /* The event thread should be done, so we can touch SDL_Display */ |
4927 | + if ( SDL_Display != NULL ) { |
4928 | + /* Flush any delayed updates */ |
4929 | + XSync(GFX_Display, False); |
4930 | + |
4931 | + /* Close the connection with the IM server */ |
4932 | + #ifdef X_HAVE_UTF8_STRING |
4933 | + if (SDL_IC != NULL) { |
4934 | + XUnsetICFocus(SDL_IC); |
4935 | + XDestroyIC(SDL_IC); |
4936 | + SDL_IC = NULL; |
4937 | + } |
4938 | + if (SDL_IM != NULL) { |
4939 | + XCloseIM(SDL_IM); |
4940 | + SDL_IM = NULL; |
4941 | + } |
4942 | + #endif |
4943 | + |
4944 | + /* Start shutting down the windows */ |
4945 | + X11_DestroyImage(this, this->screen); |
4946 | + X11_DestroyWindow(this, this->screen); |
4947 | + X11_FreeVideoModes(this); |
4948 | + if ( SDL_XColorMap != SDL_DisplayColormap ) { |
4949 | + XFreeColormap(SDL_Display, SDL_XColorMap); |
4950 | + } |
4951 | + if ( SDL_iconcolors ) { |
4952 | + unsigned long pixel; |
4953 | + Colormap dcmap = DefaultColormap(SDL_Display, |
4954 | + SDL_Screen); |
4955 | + for(pixel = 0; pixel < 256; ++pixel) { |
4956 | + while(SDL_iconcolors[pixel] > 0) { |
4957 | + XFreeColors(GFX_Display, |
4958 | + dcmap, &pixel, 1, 0); |
4959 | + --SDL_iconcolors[pixel]; |
4960 | + } |
4961 | + } |
4962 | + SDL_free(SDL_iconcolors); |
4963 | + SDL_iconcolors = NULL; |
4964 | + } |
4965 | + |
4966 | + /* Restore gamma settings if they've changed */ |
4967 | + if ( SDL_GetAppState() & SDL_APPACTIVE ) { |
4968 | + X11_SwapVidModeGamma(this); |
4969 | + } |
4970 | + |
4971 | + /* Free that blank cursor */ |
4972 | + if ( SDL_BlankCursor != NULL ) { |
4973 | + this->FreeWMCursor(this, SDL_BlankCursor); |
4974 | + SDL_BlankCursor = NULL; |
4975 | + } |
4976 | + |
4977 | + /* Close the X11 graphics connection */ |
4978 | + if ( GFX_Display != NULL ) { |
4979 | + XCloseDisplay(GFX_Display); |
4980 | + GFX_Display = NULL; |
4981 | + } |
4982 | + |
4983 | + /* Close the X11 display connection */ |
4984 | + XCloseDisplay(SDL_Display); |
4985 | + SDL_Display = NULL; |
4986 | + |
4987 | + /* Reset the X11 error handlers */ |
4988 | + if ( XIO_handler ) { |
4989 | + XSetIOErrorHandler(XIO_handler); |
4990 | + } |
4991 | + if ( X_handler ) { |
4992 | + XSetErrorHandler(X_handler); |
4993 | + } |
4994 | + |
4995 | + /* Unload GL library after X11 shuts down */ |
4996 | + X11_GL_UnloadLibrary(this); |
4997 | + } |
4998 | + if ( this->screen && (this->screen->flags & SDL_HWSURFACE) ) { |
4999 | + /* Direct screen access, no memory buffer */ |
5000 | + this->screen->pixels = NULL; |