1
2 #include "X11Event.h"
3
X11EventPoll(JNIEnv * env,jobject obj,Display * dpy,jlong javaObjectAtom,jlong windowDeleteAtom)4 void X11EventPoll(JNIEnv *env, jobject obj, Display *dpy, jlong javaObjectAtom, jlong windowDeleteAtom) {
5 Atom wm_delete_atom = (Atom)windowDeleteAtom;
6 int num_events = 100;
7 int autoRepeatModifiers = 0;
8
9 if ( NULL == dpy ) {
10 return;
11 }
12
13 // Periodically take a break
14 while( num_events > 0 ) {
15 JavaWindow *w = NULL;
16 XEvent evt;
17 KeySym keySym = 0;
18 jint modifiers = 0;
19 char keyChar = 0;
20 char text[255];
21
22 // XEventsQueued(dpy, X):
23 // QueuedAlready == XQLength(): No I/O Flush or system call doesn't work on some cards (eg ATI) ?)
24 // QueuedAfterFlush == XPending(): I/O Flush only if no already queued events are available
25 // QueuedAfterReading : QueuedAlready + if queue==0, attempt to read more ..
26 // if ( 0 >= XPending(dpy) )
27 if ( 0 >= XEventsQueued(dpy, QueuedAfterFlush) )
28 {
29 // DBG_PRINT( "X11: DispatchMessages 0x%X - Leave 1\n", dpy);
30 return;
31 }
32
33 XNextEvent(dpy, &evt);
34 num_events--;
35
36 if(dpy!=evt.xany.display) {
37 NewtCommon_throwNewRuntimeException(env, "wrong display, bail out!");
38 return ;
39 }
40
41 if( 0==evt.xany.window ) {
42 DBG_PRINT( "X11: DispatchMessages dpy %p, Event %d - Window NULL, ignoring\n", (void*)dpy, (int)evt.type);
43 continue;
44 }
45
46 // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, (int)evt.type);
47
48 w = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom,
49 #ifdef VERBOSE_ON
50 True
51 #else
52 False
53 #endif
54 );
55
56 if(NULL==w) {
57 fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", (void*)dpy, evt.type, (void*)evt.xany.window);
58 continue;
59 }
60
61 switch(evt.type) {
62 case KeyRelease:
63 if (XEventsQueued(dpy, QueuedAfterReading)) {
64 XEvent nevt;
65 XPeekEvent(dpy, &nevt);
66
67 if (nevt.type == KeyPress && nevt.xkey.time == evt.xkey.time &&
68 nevt.xkey.keycode == evt.xkey.keycode)
69 {
70 autoRepeatModifiers |= EVENT_AUTOREPEAT_MASK;
71 } else {
72 autoRepeatModifiers &= ~EVENT_AUTOREPEAT_MASK;
73 }
74 }
75 // fall through intended
76 case KeyPress:
77 if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) {
78 KeySym lower_return = 0, upper_return = 0;
79 keyChar=text[0];
80 XConvertCase(keySym, &lower_return, &upper_return);
81 // always return upper case, set modifier masks (SHIFT, ..)
82 keySym = X11KeySym2NewtVKey(upper_return);
83 } else {
84 keyChar=0;
85 keySym = X11KeySym2NewtVKey(keySym);
86 }
87 modifiers |= X11InputState2NewtModifiers(evt.xkey.state) | autoRepeatModifiers;
88 break;
89
90 case ButtonPress:
91 case ButtonRelease:
92 case MotionNotify:
93 modifiers |= X11InputState2NewtModifiers(evt.xbutton.state);
94 break;
95
96 default:
97 break;
98 }
99
100 switch(evt.type) {
101 case ButtonPress:
102 (*env)->CallVoidMethod(env, w->jwindow, requestFocusID, JNI_FALSE);
103 #ifdef USE_SENDIO_DIRECT
104 (*env)->CallVoidMethod(env, w->jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED,
105 modifiers,
106 (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0.0f /*rotation*/);
107 #else
108 (*env)->CallVoidMethod(env, w->jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_PRESSED,
109 modifiers,
110 (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0.0f /*rotation*/);
111 #endif
112 break;
113 case ButtonRelease:
114 #ifdef USE_SENDIO_DIRECT
115 (*env)->CallVoidMethod(env, w->jwindow, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED,
116 modifiers,
117 (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0.0f /*rotation*/);
118 #else
119 (*env)->CallVoidMethod(env, w->jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_RELEASED,
120 modifiers,
121 (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0.0f /*rotation*/);
122 #endif
123 break;
124 case MotionNotify:
125 #ifdef USE_SENDIO_DIRECT
126 (*env)->CallVoidMethod(env, w->jwindow, sendMouseEventID, (jint) EVENT_MOUSE_MOVED,
127 modifiers,
128 (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0.0f /*rotation*/);
129 #else
130 (*env)->CallVoidMethod(env, w->jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_MOVED,
131 modifiers,
132 (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0.0f /*rotation*/);
133 #endif
134 break;
135 case EnterNotify:
136 DBG_PRINT( "X11: event . EnterNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y);
137 #ifdef USE_SENDIO_DIRECT
138 (*env)->CallVoidMethod(env, w->jwindow, sendMouseEventID, (jint) EVENT_MOUSE_ENTERED,
139 modifiers,
140 (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0.0f /*rotation*/);
141 #else
142 (*env)->CallVoidMethod(env, w->jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_ENTERED,
143 modifiers,
144 (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0.0f /*rotation*/);
145 #endif
146 break;
147 case LeaveNotify:
148 DBG_PRINT( "X11: event . LeaveNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y);
149 #ifdef USE_SENDIO_DIRECT
150 (*env)->CallVoidMethod(env, w->jwindow, sendMouseEventID, (jint) EVENT_MOUSE_EXITED,
151 modifiers,
152 (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0.0f /*rotation*/);
153 #else
154 (*env)->CallVoidMethod(env, w->jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_EXITED,
155 modifiers,
156 (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0.0f /*rotation*/);
157 #endif
158 break;
159 case KeyPress:
160 #ifdef USE_SENDIO_DIRECT
161 (*env)->CallVoidMethod(env, w->jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED,
162 modifiers, keySym, (jchar) -1);
163 #else
164 (*env)->CallVoidMethod(env, w->jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_PRESSED,
165 modifiers, keySym, (jchar) -1);
166 #endif
167
168 break;
169 case KeyRelease:
170 #ifdef USE_SENDIO_DIRECT
171 (*env)->CallVoidMethod(env, w->jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED,
172 modifiers, keySym, (jchar) -1);
173 #else
174 (*env)->CallVoidMethod(env, w->jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_RELEASED,
175 modifiers, keySym, (jchar) -1);
176 #endif
177
178 break;
179 case DestroyNotify:
180 DBG_PRINT( "X11: event . DestroyNotify call %p, parent %p, child-event: %d\n",
181 (void*)evt.xdestroywindow.window, (void*)evt.xdestroywindow.event, evt.xdestroywindow.window != evt.xdestroywindow.event);
182 if ( evt.xdestroywindow.window == evt.xdestroywindow.event ) {
183 // ignore child destroy notification
184 }
185 break;
186 case CreateNotify:
187 DBG_PRINT( "X11: event . CreateNotify call %p, parent %p, child-event: 1\n",
188 (void*)evt.xcreatewindow.window, (void*) evt.xcreatewindow.parent);
189 break;
190 case ConfigureNotify:
191 DBG_PRINT( "X11: event . ConfigureNotify call %p (parent %p, above %p) %d/%d %dx%d %d, child-event: %d\n",
192 (void*)evt.xconfigure.window, (void*)evt.xconfigure.event, (void*)evt.xconfigure.above,
193 evt.xconfigure.x, evt.xconfigure.y, evt.xconfigure.width, evt.xconfigure.height,
194 evt.xconfigure.override_redirect, evt.xconfigure.window != evt.xconfigure.event);
195 if ( evt.xconfigure.window == evt.xconfigure.event ) {
196 // ignore child window change notification
197 {
198 // update insets
199 int left, right, top, bottom;
200 NewtWindows_updateInsets(env, w->jwindow, dpy, evt.xany.window, &left, &right, &top, &bottom);
201 }
202 (*env)->CallVoidMethod(env, w->jwindow, sizeChangedID, JNI_FALSE,
203 (jint) evt.xconfigure.width, (jint) evt.xconfigure.height, JNI_FALSE);
204 (*env)->CallVoidMethod(env, w->jwindow, positionChangedID, JNI_FALSE,
205 (jint) evt.xconfigure.x, (jint) evt.xconfigure.y);
206 }
207 break;
208 case ClientMessage:
209 if (evt.xclient.send_event==True && evt.xclient.data.l[0]==wm_delete_atom) { // windowDeleteAtom
210 jboolean closed;
211 DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X ..\n",
212 (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type);
213 closed = (*env)->CallBooleanMethod(env, w->jwindow, windowDestroyNotifyID, JNI_FALSE);
214 DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X, closed: %d\n",
215 (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type, (int)closed);
216 // Called by Window.java: CloseWindow();
217 num_events = 0; // end loop in case of destroyed display
218 }
219 break;
220
221 case FocusIn:
222 DBG_PRINT( "X11: event . FocusIn call %p\n", (void*)evt.xvisibility.window);
223 (*env)->CallVoidMethod(env, w->jwindow, focusChangedID, JNI_FALSE, JNI_TRUE);
224 break;
225
226 case FocusOut:
227 DBG_PRINT( "X11: event . FocusOut call %p\n", (void*)evt.xvisibility.window);
228 (*env)->CallVoidMethod(env, w->jwindow, focusChangedID, JNI_FALSE, JNI_FALSE);
229 break;
230
231 case Expose:
232 DBG_PRINT( "X11: event . Expose call %p %d/%d %dx%d count %d\n", (void*)evt.xexpose.window,
233 evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height, evt.xexpose.count);
234
235 if (evt.xexpose.count == 0 && evt.xexpose.width > 0 && evt.xexpose.height > 0) {
236 (*env)->CallVoidMethod(env, w->jwindow, windowRepaintID, JNI_FALSE,
237 evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height);
238 }
239 break;
240
241 case MapNotify:
242 DBG_PRINT( "X11: event . MapNotify call Event %p, Window %p, override_redirect %d, child-event: %d\n",
243 (void*)evt.xmap.event, (void*)evt.xmap.window, (int)evt.xmap.override_redirect,
244 evt.xmap.event!=evt.xmap.window);
245 if( evt.xmap.event == evt.xmap.window ) {
246 // ignore child window notification
247 {
248 // update insets
249 int left, right, top, bottom;
250 NewtWindows_updateInsets(env, w->jwindow, dpy, evt.xany.window, &left, &right, &top, &bottom);
251 }
252 (*env)->CallVoidMethod(env, w->jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE);
253 }
254 break;
255
256 case UnmapNotify:
257 DBG_PRINT( "X11: event . UnmapNotify call Event %p, Window %p, from_configure %d, child-event: %d\n",
258 (void*)evt.xunmap.event, (void*)evt.xunmap.window, (int)evt.xunmap.from_configure,
259 evt.xunmap.event!=evt.xunmap.window);
260 if( evt.xunmap.event == evt.xunmap.window ) {
261 // ignore child window notification
262 (*env)->CallVoidMethod(env, w->jwindow, visibleChangedID, JNI_FALSE, JNI_FALSE);
263 }
264 break;
265
266 case ReparentNotify:
267 {
268 jlong parentResult; // 0 if root, otherwise proper value
269 Window winRoot, winTopParent;
270 #ifdef VERBOSE_ON
271 Window oldParentRoot, oldParentTopParent;
272 Window parentRoot, parentTopParent;
273 if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.event, &oldParentRoot, &oldParentTopParent) ) {
274 oldParentRoot=0; oldParentTopParent = 0;
275 }
276 if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.parent, &parentRoot, &parentTopParent) ) {
277 parentRoot=0; parentTopParent = 0;
278 }
279 #endif
280 if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.window, &winRoot, &winTopParent) ) {
281 winRoot=0; winTopParent = 0;
282 }
283 if(evt.xreparent.parent == winRoot) {
284 parentResult = 0; // our java indicator for root window
285 } else {
286 parentResult = (jlong) (intptr_t) evt.xreparent.parent;
287 }
288 #ifdef VERBOSE_ON
289 DBG_PRINT( "X11: event . ReparentNotify: call %d/%d OldParent %p (root %p, top %p), NewParent %p (root %p, top %p), Window %p (root %p, top %p)\n",
290 evt.xreparent.x, evt.xreparent.y,
291 (void*)evt.xreparent.event, (void*)oldParentRoot, (void*)oldParentTopParent,
292 (void*)evt.xreparent.parent, (void*)parentRoot, (void*)parentTopParent,
293 (void*)evt.xreparent.window, (void*)winRoot, (void*)winTopParent);
294 #endif
295 (*env)->CallVoidMethod(env, w->jwindow, reparentNotifyID, (jlong)evt.xreparent.parent);
296 }
297 break;
298
299 // unhandled events .. yet ..
300
301 default:
302 DBG_PRINT("X11: event . unhandled %d 0x%X call %p\n", (int)evt.type, (unsigned int)evt.type, (void*)evt.xunmap.window);
303 }
304 }
305 }
306