comparison mupdf-source/thirdparty/freeglut/src/x11/fg_spaceball_x11.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /* Spaceball support for Linux.
2 * Written by John Tsiombikas <nuclear@member.fsf.org>
3 * Copied for Platform code by Evan Felix <karcaw at gmail.com>
4 * Creation date: Thur Feb 2 2012
5 *
6 * This code supports 3Dconnexion's 6-dof space-whatever devices.
7 * It can communicate with either the proprietary 3Dconnexion daemon (3dxsrv)
8 * free spacenavd (http://spacenav.sourceforge.net), through the "standard"
9 * magellan X-based protocol.
10 */
11
12 #include <GL/freeglut.h>
13 #include "../fg_internal.h"
14
15 #include <X11/Xlib.h>
16
17 extern int sball_initialized;
18
19 enum {
20 SPNAV_EVENT_ANY, /* used by spnav_remove_events() */
21 SPNAV_EVENT_MOTION,
22 SPNAV_EVENT_BUTTON /* includes both press and release */
23 };
24
25 struct spnav_event_motion {
26 int type;
27 int x, y, z;
28 int rx, ry, rz;
29 unsigned int period;
30 int *data;
31 };
32
33 struct spnav_event_button {
34 int type;
35 int press;
36 int bnum;
37 };
38
39 typedef union spnav_event {
40 int type;
41 struct spnav_event_motion motion;
42 struct spnav_event_button button;
43 } spnav_event;
44
45
46 static int spnav_x11_open(Display *dpy, Window win);
47 static int spnav_x11_window(Window win);
48 static int spnav_x11_event(const XEvent *xev, spnav_event *event);
49 static int spnav_close(void);
50 static int spnav_fd(void);
51 static int spnav_remove_events(int type);
52
53 static SFG_Window *spnav_win;
54
55 void fgPlatformInitializeSpaceball(void)
56 {
57 Window w;
58
59 sball_initialized = 1;
60 if(!fgStructure.CurrentWindow)
61 {
62 sball_initialized = -1;
63 return;
64 }
65
66 w = fgStructure.CurrentWindow->Window.Handle;
67 if(spnav_x11_open(fgDisplay.pDisplay.Display, w) == -1)
68 {
69 sball_initialized = -1;
70 return;
71 }
72 }
73
74 void fgPlatformSpaceballClose(void)
75 {
76 spnav_close();
77 }
78
79 int fgPlatformHasSpaceball(void)
80 {
81 /* XXX this function should somehow query the driver if there's a device
82 * plugged in, as opposed to just checking if there's a driver to talk to.
83 */
84 return spnav_fd() == -1 ? 0 : 1;
85 }
86
87 int fgPlatformSpaceballNumButtons(void) {
88 return 2;
89 }
90
91 void fgPlatformSpaceballSetWindow(SFG_Window *window)
92 {
93 if(spnav_win != window) {
94 spnav_x11_window(window->Window.Handle);
95 spnav_win = window;
96 }
97 }
98
99 int fgIsSpaceballXEvent(const XEvent *xev)
100 {
101 spnav_event sev;
102
103 if(spnav_win != fgStructure.CurrentWindow) {
104 /* this will also initialize spaceball if needed (first call) */
105 fgSpaceballSetWindow(fgStructure.CurrentWindow);
106 }
107
108 if(sball_initialized != 1) {
109 return 0;
110 }
111
112 return spnav_x11_event(xev, &sev);
113 }
114
115 void fgSpaceballHandleXEvent(const XEvent *xev)
116 {
117 spnav_event sev;
118
119 if(sball_initialized == 0) {
120 fgInitialiseSpaceball();
121 if(sball_initialized != 1) {
122 return;
123 }
124 }
125
126 if(spnav_x11_event(xev, &sev)) {
127 switch(sev.type) {
128 case SPNAV_EVENT_MOTION:
129 if(sev.motion.x | sev.motion.y | sev.motion.z) {
130 INVOKE_WCB(*spnav_win, SpaceMotion, (sev.motion.x, sev.motion.y, sev.motion.z));
131 }
132 if(sev.motion.rx | sev.motion.ry | sev.motion.rz) {
133 INVOKE_WCB(*spnav_win, SpaceRotation, (sev.motion.rx, sev.motion.ry, sev.motion.rz));
134 }
135 spnav_remove_events(SPNAV_EVENT_MOTION);
136 break;
137
138 case SPNAV_EVENT_BUTTON:
139 INVOKE_WCB(*spnav_win, SpaceButton, (sev.button.bnum, sev.button.press ? GLUT_DOWN : GLUT_UP));
140 break;
141
142 default:
143 break;
144 }
145 }
146 }
147
148 /*
149 The following code is part of libspnav, part of the spacenav project (spacenav.sf.net)
150 Copyright (C) 2007-2009 John Tsiombikas <nuclear@member.fsf.org>
151
152 Redistribution and use in source and binary forms, with or without
153 modification, are permitted provided that the following conditions are met:
154
155 1. Redistributions of source code must retain the above copyright notice, this
156 list of conditions and the following disclaimer.
157 2. Redistributions in binary form must reproduce the above copyright notice,
158 this list of conditions and the following disclaimer in the documentation
159 and/or other materials provided with the distribution.
160 3. The name of the author may not be used to endorse or promote products
161 derived from this software without specific prior written permission.
162
163 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
164 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
165 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
166 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
167 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
168 OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
169 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
170 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
171 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
172 OF SUCH DAMAGE.
173 */
174 #include <stdio.h>
175 #include <stdlib.h>
176 #include <string.h>
177 #include <errno.h>
178
179 #include <X11/Xlib.h>
180 #include <X11/Xutil.h>
181
182 static Window get_daemon_window(Display *dpy);
183 static int catch_badwin(Display *dpy, XErrorEvent *err);
184
185 static Display *dpy;
186 static Window app_win;
187 static Atom motion_event, button_press_event, button_release_event, command_event;
188
189 enum {
190 CMD_APP_WINDOW = 27695,
191 CMD_APP_SENS
192 };
193
194 #define IS_OPEN dpy
195
196 struct event_node {
197 spnav_event event;
198 struct event_node *next;
199 };
200
201 static int spnav_x11_open(Display *display, Window win)
202 {
203 if(IS_OPEN) {
204 return -1;
205 }
206
207 dpy = display;
208
209 motion_event = XInternAtom(dpy, "MotionEvent", True);
210 button_press_event = XInternAtom(dpy, "ButtonPressEvent", True);
211 button_release_event = XInternAtom(dpy, "ButtonReleaseEvent", True);
212 command_event = XInternAtom(dpy, "CommandEvent", True);
213
214 if(!motion_event || !button_press_event || !button_release_event || !command_event) {
215 dpy = 0;
216 return -1; /* daemon not started */
217 }
218
219 if(spnav_x11_window(win) == -1) {
220 dpy = 0;
221 return -1; /* daemon not started */
222 }
223
224 app_win = win;
225 return 0;
226 }
227
228 static int spnav_close(void)
229 {
230 if(dpy) {
231 spnav_x11_window(DefaultRootWindow(dpy));
232 app_win = 0;
233 dpy = 0;
234 return 0;
235 }
236 return -1;
237 }
238
239 static int spnav_x11_window(Window win)
240 {
241 int (*prev_xerr_handler)(Display*, XErrorEvent*);
242 XEvent xev;
243 Window daemon_win;
244
245 if(!IS_OPEN) {
246 return -1;
247 }
248
249 if(!(daemon_win = get_daemon_window(dpy))) {
250 return -1;
251 }
252
253 prev_xerr_handler = XSetErrorHandler(catch_badwin);
254
255 xev.type = ClientMessage;
256 xev.xclient.send_event = False;
257 xev.xclient.display = dpy;
258 xev.xclient.window = win;
259 xev.xclient.message_type = command_event;
260 xev.xclient.format = 16;
261 xev.xclient.data.s[0] = ((unsigned int)win & 0xffff0000) >> 16;
262 xev.xclient.data.s[1] = (unsigned int)win & 0xffff;
263 xev.xclient.data.s[2] = CMD_APP_WINDOW;
264
265 XSendEvent(dpy, daemon_win, False, 0, &xev);
266 XSync(dpy, False);
267
268 XSetErrorHandler(prev_xerr_handler);
269 return 0;
270 }
271
272 static int spnav_fd(void)
273 {
274 if(dpy) {
275 return ConnectionNumber(dpy);
276 }
277 return -1;
278 }
279
280 /*static int spnav_wait_event(spnav_event *event)
281 {
282 if(dpy) {
283 for(;;) {
284 XEvent xev;
285 XNextEvent(dpy, &xev);
286
287 if(spnav_x11_event(&xev, event) > 0) {
288 return event->type;
289 }
290 }
291 }
292 return 0;
293 }
294
295 static int spnav_poll_event(spnav_event *event)
296 {
297 if(dpy) {
298 if(XPending(dpy)) {
299 XEvent xev;
300 XNextEvent(dpy, &xev);
301
302 return spnav_x11_event(&xev, event);
303 }
304 }
305 return 0;
306 }*/
307
308 static Bool match_events(Display *dpy, XEvent *xev, char *arg)
309 {
310 int evtype = *(int*)arg;
311
312 if(xev->type != ClientMessage) {
313 return False;
314 }
315
316 if(xev->xclient.message_type == motion_event) {
317 return !evtype || evtype == SPNAV_EVENT_MOTION ? True : False;
318 }
319 if(xev->xclient.message_type == button_press_event ||
320 xev->xclient.message_type == button_release_event) {
321 return !evtype || evtype == SPNAV_EVENT_BUTTON ? True : False;
322 }
323 return False;
324 }
325
326 static int spnav_remove_events(int type)
327 {
328 int rm_count = 0;
329
330 if(dpy) {
331 XEvent xev;
332
333 while(XCheckIfEvent(dpy, &xev, match_events, (char*)&type)) {
334 rm_count++;
335 }
336 return rm_count;
337 }
338 return 0;
339 }
340
341 static int spnav_x11_event(const XEvent *xev, spnav_event *event)
342 {
343 int i;
344 int xmsg_type;
345
346 if(xev->type != ClientMessage) {
347 return 0;
348 }
349
350 xmsg_type = xev->xclient.message_type;
351
352 if(xmsg_type != motion_event && xmsg_type != button_press_event &&
353 xmsg_type != button_release_event) {
354 return 0;
355 }
356
357 if(xmsg_type == motion_event) {
358 event->type = SPNAV_EVENT_MOTION;
359 event->motion.data = &event->motion.x;
360
361 for(i=0; i<6; i++) {
362 event->motion.data[i] = xev->xclient.data.s[i + 2];
363 }
364 event->motion.period = xev->xclient.data.s[8];
365 } else {
366 event->type = SPNAV_EVENT_BUTTON;
367 event->button.press = xmsg_type == button_press_event ? 1 : 0;
368 event->button.bnum = xev->xclient.data.s[2];
369 }
370 return event->type;
371 }
372
373
374 static Window get_daemon_window(Display *dpy)
375 {
376 Window win, root_win;
377 XTextProperty wname;
378 Atom type;
379 int fmt;
380 unsigned long nitems, bytes_after;
381 unsigned char *prop;
382
383 root_win = DefaultRootWindow(dpy);
384
385 XGetWindowProperty(dpy, root_win, command_event, 0, 1, False, AnyPropertyType, &type, &fmt, &nitems, &bytes_after, &prop);
386 if(!prop) {
387 return 0;
388 }
389
390 win = *(Window*)prop;
391 XFree(prop);
392
393 if(!XGetWMName(dpy, win, &wname) || strcmp("Magellan Window", (char*)wname.value) != 0) {
394 return 0;
395 }
396
397 return win;
398 }
399
400 static int catch_badwin(Display *dpy, XErrorEvent *err)
401 {
402 char buf[256];
403
404 if(err->error_code == BadWindow) {
405 /* do nothing? */
406 } else {
407 XGetErrorText(dpy, err->error_code, buf, sizeof buf);
408 fprintf(stderr, "Caught unexpected X error: %s\n", buf);
409 }
410 return 0;
411 }
412