Fixed broken X11 menus. The MPX patch would naively just call the
[freeglut] / src / x11 / fg_xinput_x11.c
1 /* Written for XI1 by Nikolas Doerfler <doerflen@in.tum.de> (c) 2008 *
2  * Rewritten for XI2 by Florian Echtler <echtler@in.tum.de> (c) 2009 */
3
4 #include <GL/freeglut.h>
5
6 #include "../fg_internal.h"
7
8 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
9
10 #include <errno.h>
11 #include <stdarg.h>
12
13 #include <X11/Xlib.h>
14 #include <X11/extensions/XInput2.h>
15
16 /* import function from freeglut_main.c */
17 extern int fgPlatformGetModifiers( int state );
18
19 /* extension opcode for XInput */
20 int xi_opcode = -1;
21
22 /**
23  * \brief Sets window up for XI2 events.
24  */
25 void fgRegisterDevices( Display* dpy, Window* win ) {
26
27         XIEventMask mask;
28         unsigned char flags[2] = { 0, 0 };
29         int event, error;
30
31         /*Display* dpy = fgDisplay.pDisplay.Display;
32         Window* win = glutGetXWindow();*/
33
34         /* get XInput extension opcode */
35         if (!XQueryExtension( dpy, "XInputExtension", &xi_opcode, &event, &error )) { xi_opcode = -1; }
36
37         /* Select for motion events */
38         mask.deviceid = XIAllMasterDevices;
39         mask.mask_len = 2;
40         mask.mask = flags;
41
42         XISetMask(mask.mask, XI_Enter);
43         XISetMask(mask.mask, XI_Motion);
44         XISetMask(mask.mask, XI_ButtonPress);
45         XISetMask(mask.mask, XI_ButtonRelease);
46         XISetMask(mask.mask, XI_Leave);
47         /*XISetMask(mask.mask, XI_KeyPress);
48         XISetMask(mask.mask, XI_KeyRelease);
49         XISetMask(mask.mask, XI_DeviceChanged);
50         XISetMask(mask.mask, XI_RawEvent);
51         XISetMask(mask.mask, XI_FocusIn);
52         XISetMask(mask.mask, XI_FocusOut);
53         XISetMask(mask.mask, XI_HierarchyChanged);*/
54
55         XISelectEvents( dpy, *win, &mask, 1 );
56 }
57
58
59 void fgPrintXILeaveEvent(XILeaveEvent* event)
60 {
61     char* mode = "";
62                 char* detail = "";
63     int i;
64
65     printf("    windows: root 0x%lx event 0x%lx child 0x%ld\n",
66             event->root, event->event, event->child);
67     switch(event->mode)
68     {
69         case NotifyNormal:       mode = "NotifyNormal"; break;
70         case NotifyGrab:         mode = "NotifyGrab"; break;
71         case NotifyUngrab:       mode = "NotifyUngrab"; break;
72         case NotifyWhileGrabbed: mode = "NotifyWhileGrabbed"; break;
73     }
74     switch (event->detail)
75     {
76         case NotifyAncestor: detail = "NotifyAncestor"; break;
77         case NotifyVirtual: detail = "NotifyVirtual"; break;
78         case NotifyInferior: detail = "NotifyInferior"; break;
79         case NotifyNonlinear: detail = "NotifyNonlinear"; break;
80         case NotifyNonlinearVirtual: detail = "NotifyNonlinearVirtual"; break;
81         case NotifyPointer: detail = "NotifyPointer"; break;
82         case NotifyPointerRoot: detail = "NotifyPointerRoot"; break;
83         case NotifyDetailNone: detail = "NotifyDetailNone"; break;
84     }
85     printf("    mode: %s (detail %s)\n", mode, detail);
86     printf("    flags: %s %s\n", event->focus ? "[focus]" : "",
87                                  event->same_screen ? "[same screen]" : "");
88     printf("    buttons:");
89     for (i = 0; i < event->buttons.mask_len * 8; i++)
90         if (XIMaskIsSet(event->buttons.mask, i))
91             printf(" %d", i);
92     printf("\n");
93
94     printf("    modifiers: locked 0x%x latched 0x%x base 0x%x\n",
95             event->mods.locked, event->mods.latched,
96             event->mods.base);
97     printf("    group: locked 0x%x latched 0x%x base 0x%x\n",
98             event->group.locked, event->group.latched,
99             event->group.base);
100
101     printf("    root x/y:  %.2f / %.2f\n", event->root_x, event->root_y);
102     printf("    event x/y: %.2f / %.2f\n", event->event_x, event->event_y);
103
104 }
105
106
107 void fgPrintXIDeviceEvent(XIDeviceEvent* event)
108 {
109     double *val;
110     int i;
111
112     printf("    device: %d (%d)\n", event->deviceid, event->sourceid);
113     printf("    detail: %d\n", event->detail);
114     printf("    buttons:");
115           for (i = 0; i < event->buttons.mask_len * 8; i++)
116             if (XIMaskIsSet(event->buttons.mask, i))
117               printf(" %d", i);
118     printf("\n");
119
120     printf("    modifiers: locked 0x%x latched 0x%x base 0x%x\n",
121             event->mods.locked, event->mods.latched,
122             event->mods.base);
123     printf("    group: locked 0x%x latched 0x%x base 0x%x\n",
124             event->group.locked, event->group.latched,
125             event->group.base);
126     printf("    valuators:");
127
128     val = event->valuators.values;
129     for (i = 0; i < event->valuators.mask_len * 8; i++)
130         if (XIMaskIsSet(event->valuators.mask, i))
131             printf(" %d: %.2f", i, *val++);
132     printf("\n");
133
134     printf("    windows: root 0x%lx event 0x%lx child 0x%ld\n",
135             event->root, event->event, event->child);
136     printf("    root x/y:  %.2f / %.2f\n", event->root_x, event->root_y);
137     printf("    event x/y: %.2f / %.2f\n", event->event_x, event->event_y);
138
139 }
140
141 /**
142  * \brief This function is called when an Extension Event is received
143  * and calls the corresponding callback functions for these events.
144  */
145 void fgHandleExtensionEvents( XEvent* base_ev )
146 {
147         XEvent std_ev;  /* standard single-pointer event to be added to the event queue */
148         int i, button = 0;
149         XGenericEventCookie* cookie = (XGenericEventCookie*)&(base_ev->xcookie);
150
151         /* initialize the generic fields from base_ev */
152         std_ev.xany = base_ev->xany;
153
154         if ( XGetEventData( fgDisplay.pDisplay.Display, cookie ) && (cookie->type == GenericEvent) && (cookie->extension == xi_opcode) ) {
155
156                 XIDeviceEvent* event = (XIDeviceEvent*)(cookie->data);
157                 XIEnterEvent *evcross;
158                 /*printf("XI2 event type: %d - %d\n", cookie->evtype, event->type );*/
159
160                 SFG_Window* window = fgWindowByHandle( event->event );
161                 if (!window) return;
162
163                 switch (cookie->evtype) {
164                 case XI_Enter:
165                 case XI_Leave:
166                         evcross = (XIEnterEvent*)event;
167
168                         fgState.Modifiers = fgPlatformGetModifiers( evcross->mods.base );
169                         INVOKE_WCB( *window, MultiEntry, (
170                                 event->deviceid,
171                                 (event->evtype == XI_Enter ? GLUT_ENTERED : GLUT_LEFT)
172                         ));
173                         #if _DEBUG
174                         fgPrintXILeaveEvent((XILeaveEvent*)event);
175                         #endif
176
177                         /* Also process the standard crossing event */
178                         std_ev.type = evcross->evtype == XI_Enter ? EnterNotify : LeaveNotify;
179                         std_ev.xcrossing.window = evcross->event;
180                         std_ev.xcrossing.root = evcross->root;
181                         std_ev.xcrossing.subwindow = evcross->child;
182                         std_ev.xcrossing.x = evcross->event_x;
183                         std_ev.xcrossing.y = evcross->event_y;
184                         std_ev.xcrossing.x_root = evcross->root_x;
185                         std_ev.xcrossing.y_root = evcross->root_y;
186                         std_ev.xcrossing.mode = evcross->mode;
187                         std_ev.xcrossing.detail = evcross->detail;
188                         std_ev.xcrossing.same_screen = evcross->same_screen;
189                         std_ev.xcrossing.focus = evcross->focus;
190                         std_ev.xcrossing.state = *(unsigned int*)evcross->buttons.mask;
191
192                         XPutBackEvent(fgDisplay.pDisplay.Display, &std_ev);
193                         break;
194
195                 case XI_ButtonPress:
196                 case XI_ButtonRelease:
197                         fgState.Modifiers = fgPlatformGetModifiers( event->mods.base );
198                         INVOKE_WCB( *window, MultiButton, (
199                                 event->deviceid,
200                                 event->event_x,
201                                 event->event_y,
202                                 event->detail-1,
203                                 (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP)
204                         ));
205
206                         /* Also process the standard button event */
207                         std_ev.type = event->evtype == XI_ButtonPress ? ButtonPress : ButtonRelease;
208                         std_ev.xbutton.window = event->event;
209                         std_ev.xbutton.root = event->root;
210                         std_ev.xbutton.subwindow = event->child;
211                         std_ev.xbutton.x = event->event_x;
212                         std_ev.xbutton.y = event->event_y;
213                         std_ev.xbutton.x_root = event->root_x;
214                         std_ev.xbutton.y_root = event->root_y;
215                         std_ev.xbutton.state = *(unsigned int*)event->buttons.mask;
216                         std_ev.xbutton.button = event->detail;
217
218                         XPutBackEvent(fgDisplay.pDisplay.Display, &std_ev);
219                         break;
220
221                 case XI_Motion:
222                         fgState.Modifiers = fgPlatformGetModifiers( event->mods.base );
223                         for (i = 0; i < event->buttons.mask_len; i++) {
224                                 if (event->buttons.mask[i]) {
225                                         button = 1;
226                                 }
227                         }
228                         if (button) {
229                                 INVOKE_WCB( *window, MultiMotion,  ( event->deviceid, event->event_x, event->event_y ) );
230                         } else {
231                                 INVOKE_WCB( *window, MultiPassive, ( event->deviceid, event->event_x, event->event_y ) );
232                         }
233                         #if _DEBUG
234                         fgPrintXIDeviceEvent(event);
235                         #endif
236
237                         /* Also process the standard motion event */
238                         std_ev.type = MotionNotify;
239                         std_ev.xmotion.window = event->event;
240                         std_ev.xmotion.root = event->root;
241                         std_ev.xmotion.subwindow = event->child;
242                         std_ev.xmotion.time = event->time;
243                         std_ev.xmotion.x = event->event_x;
244                         std_ev.xmotion.y = event->event_y;
245                         std_ev.xmotion.x_root = event->root_x;
246                         std_ev.xmotion.y_root = event->root_y;
247                         std_ev.xmotion.state = *(unsigned int*)event->buttons.mask;
248                         std_ev.xmotion.is_hint = NotifyNormal;
249
250                         XPutBackEvent(fgDisplay.pDisplay.Display, &std_ev);
251                         break;
252
253                 default:
254                         #if _DEBUG
255                         fgWarning( "Unknown XI2 device event:" );
256                         fgPrintXIDeviceEvent( event );
257                         #endif
258                         break;
259                 }
260                 fgState.Modifiers = INVALID_MODIFIERS;
261         }
262         XFreeEventData( fgDisplay.pDisplay.Display, cookie );
263 }
264
265 #endif