#define VERBOSE_ON 1 #include "XCBEvent.h" #include <xcb/xcb.h> #include <xcb/xcb_event.h> #include <xcb/xproto.h> #include <xcb/xcb_keysyms.h> #include <X11/Xlib-xcb.h> void XCBSetEventQueueOwner(Display *dpy) { XSetEventQueueOwner(dpy, XCBOwnsEventQueue); } void XCBEventPoll(JNIEnv *env, jobject obj, Display *dpy, jlong javaObjectAtom, jlong wmDeleteAtom) { int num_events = 100; xcb_connection_t *conn = NULL; if ( NULL == dpy ) { return; } conn = XGetXCBConnection(dpy); // Periodically take a break while( num_events > 0 ) { jobject jwindow = NULL; xcb_generic_event_t *evt; // KeySym keySym = 0; jint modifiers = 0; char keyChar = 0; // char text[255]; evt = xcb_poll_for_event(conn); if(NULL == evt) { // DBG_PRINT( "X11: DispatchMessages 0x%X - Leave 1\n", dpy); return; } num_events--; /*if( 0==evt.xany.window ) { free(evt); NewtCommon_throwNewRuntimeException(env, "event window NULL, bail out!"); return ; } if(dpy!=evt.xany.display) { free(evt); NewtCommon_throwNewRuntimeException(env, "wrong display, bail out!"); return ; }*/ // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, evt.type); // X11WindowDisplayErrorHandlerEnable(1, env); // jwindow = X11WindowGetJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom, VERBOSE_BOOL); //X11WindowDisplayErrorHandlerEnable(0, env); /*if(NULL==jwindow) { 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); continue; }*/ uint8_t xcb_event_type = evt->response_type & ~0x80; xcb_window_t event_window = 0; switch( xcb_event_type ) { case XCB_BUTTON_PRESS: case XCB_BUTTON_RELEASE: event_window = ((xcb_button_press_event_t *)evt)->event; modifiers = X11InputState2NewtModifiers(((xcb_button_press_event_t *)evt)->state); break; case XCB_MOTION_NOTIFY: event_window = ((xcb_motion_notify_event_t *)evt)->event; break; case XCB_KEY_PRESS: case XCB_KEY_RELEASE: { xcb_key_press_event_t *_evt = (xcb_key_press_event_t *)evt; event_window = _evt->event; /* xcb_keycode_t detail = _evt->detail; if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) { KeySym lower_return = 0, upper_return = 0; keyChar=text[0]; XConvertCase(keySym, &lower_return, &upper_return); // always return upper case, set modifier masks (SHIFT, ..) keySym = upper_return; modifiers = X11InputState2NewtModifiers(evt.xkey.state); } else { keyChar=0; }*/ } break; case XCB_EXPOSE: event_window = ((xcb_expose_event_t *)evt)->window; break; case XCB_MAP_NOTIFY: event_window = ((xcb_map_notify_event_t *)evt)->window; break; case XCB_UNMAP_NOTIFY: event_window = ((xcb_unmap_notify_event_t *)evt)->window; break; } if(0==event_window) { fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d, no X11 window associated\n", (void*)dpy, xcb_event_type); continue; } jwindow = getJavaWindowProperty(env, dpy, event_window, javaObjectAtom, #ifdef VERBOSE_ON True #else False #endif ); if(NULL==jwindow) { fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", (void*)(intptr_t)dpy, xcb_event_type, (void*)(intptr_t)event_window); continue; } switch( xcb_event_type ) { case XCB_BUTTON_PRESS: { xcb_button_press_event_t *_evt = (xcb_button_press_event_t *)evt; (*env)->CallVoidMethod(env, jwindow, requestFocusID, JNI_FALSE); #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, modifiers, (jint) _evt->event_x, (jint) _evt->event_y, (jint) _evt->state, 0.0f /*rotation*/); #else (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_PRESSED, modifiers, (jint) _evt->event_x, (jint) _evt->event_y, (jint) _evt->state, 0.0f /*rotation*/); #endif } break; case XCB_BUTTON_RELEASE: { xcb_button_release_event_t *_evt = (xcb_button_release_event_t *)evt; #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED, modifiers, (jint) _evt->event_x, (jint) _evt->event_y, (jint) _evt->state, 0.0f /*rotation*/); #else (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_RELEASED, modifiers, (jint) _evt->event_x, (jint) _evt->event_y, (jint) _evt->state, 0.0f /*rotation*/); #endif } break; case XCB_MOTION_NOTIFY: { xcb_motion_notify_event_t *_evt = (xcb_motion_notify_event_t *)evt; #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_MOVED, modifiers, (jint) _evt->event_x, (jint) _evt->event_y, (jint)0, 0.0f /*rotation*/); #else (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_MOVED, modifiers, (jint) _evt->event_x, (jint) _evt->event_y, (jint)0, 0.0f /*rotation*/); #endif } break; case XCB_KEY_PRESS: { xcb_key_press_event_t *_evt = (xcb_key_press_event_t *)evt; #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED, modifiers, X11KeySym2NewtVKey(_evt->state), (jchar) keyChar); #else (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_PRESSED, modifiers, X11KeySym2NewtVKey(_evt->state), (jchar) keyChar); #endif } break; case XCB_KEY_RELEASE: { xcb_key_release_event_t *_evt = (xcb_key_release_event_t *)evt; event_window = ((xcb_key_release_event_t *)evt)->event; #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED, modifiers, X11KeySym2NewtVKey(_evt->state), (jchar) keyChar); #else (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_RELEASED, modifiers, X11KeySym2NewtVKey(_evt->state), (jchar) keyChar); #endif } break; /* case DestroyNotify: DBG_PRINT( "X11: event . DestroyNotify call %p, parent %p, child-event: %d\n", (void*)evt.xdestroywindow.window, (void*)evt.xdestroywindow.event, evt.xdestroywindow.window != evt.xdestroywindow.event); if ( evt.xdestroywindow.window == evt.xdestroywindow.event ) { // ignore child destroy notification } break; case CreateNotify: DBG_PRINT( "X11: event . CreateNotify call %p, parent %p, child-event: 1\n", (void*)evt.xcreatewindow.window, (void*) evt.xcreatewindow.parent); break; case ConfigureNotify: DBG_PRINT( "X11: event . ConfigureNotify call %p (parent %p, above %p) %d/%d %dx%d %d, child-event: %d\n", (void*)evt.xconfigure.window, (void*)evt.xconfigure.event, (void*)evt.xconfigure.above, evt.xconfigure.x, evt.xconfigure.y, evt.xconfigure.width, evt.xconfigure.height, evt.xconfigure.override_redirect, evt.xconfigure.window != evt.xconfigure.event); if ( evt.xconfigure.window == evt.xconfigure.event ) { // ignore child window change notification (*env)->CallVoidMethod(env, jwindow, sizeChangedID, (jint) evt.xconfigure.width, (jint) evt.xconfigure.height, JNI_FALSE); (*env)->CallVoidMethod(env, jwindow, positionChangedID, (jint) evt.xconfigure.x, (jint) evt.xconfigure.y); } break; case ClientMessage: if (evt.xclient.send_event==True && evt.xclient.data.l[0]==(Atom)wmDeleteAtom) { DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X !!!\n", (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type); (*env)->CallVoidMethod(env, jwindow, windowDestroyNotifyID); // Called by Window.java: CloseWindow(); num_events = 0; // end loop in case of destroyed display } break; case FocusIn: DBG_PRINT( "X11: event . FocusIn call %p\n", (void*)evt.xvisibility.window); (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_TRUE); break; case FocusOut: DBG_PRINT( "X11: event . FocusOut call %p\n", (void*)evt.xvisibility.window); (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_FALSE); break; */ case XCB_EXPOSE: { xcb_expose_event_t *_evt = (xcb_expose_event_t *)evt; DBG_PRINT( "X11: event . Expose call %p %d/%d %dx%d count %d\n", (void*)(intptr_t)_evt->window, _evt->x, _evt->y, _evt->width, _evt->height, _evt->count); if (_evt->count == 0 && _evt->width > 0 && _evt->height > 0) { (*env)->CallVoidMethod(env, jwindow, windowRepaintID, _evt->x, _evt->y, _evt->width, _evt->height); } } break; case XCB_MAP_NOTIFY: { xcb_map_notify_event_t *_evt = (xcb_map_notify_event_t *)evt; DBG_PRINT( "X11: event . MapNotify call Event %p, Window %p, override_redirect %d, child-event: %d\n", (void*)(intptr_t)_evt->event, (void*)(intptr_t)_evt->window, (int)_evt->override_redirect, _evt->event!=_evt->window); if( _evt->event == _evt->window ) { // ignore child window notification (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_TRUE); } } break; case XCB_UNMAP_NOTIFY: { xcb_unmap_notify_event_t *_evt = (xcb_unmap_notify_event_t *)evt; DBG_PRINT( "X11: event . UnmapNotify call Event %p, Window %p, child-event: %d\n", (void*)(intptr_t)_evt->event, (void*)(intptr_t)_evt->window, _evt->event!=_evt->window); if( _evt->event == _evt->window ) { // ignore child window notification (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE); } } break; /* case ReparentNotify: { jlong parentResult; // 0 if root, otherwise proper value Window winRoot, winTopParent; #ifdef VERBOSE_ON Window oldParentRoot, oldParentTopParent; Window parentRoot, parentTopParent; if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.event, &oldParentRoot, &oldParentTopParent) ) { oldParentRoot=0; oldParentTopParent = 0; } if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.parent, &parentRoot, &parentTopParent) ) { parentRoot=0; parentTopParent = 0; } #endif if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.window, &winRoot, &winTopParent) ) { winRoot=0; winTopParent = 0; } if(evt.xreparent.parent == winRoot) { parentResult = 0; // our java indicator for root window } else { parentResult = (jlong) (intptr_t) evt.xreparent.parent; } #ifdef VERBOSE_ON DBG_PRINT( "X11: event . ReparentNotify: call OldParent %p (root %p, top %p), NewParent %p (root %p, top %p), Window %p (root %p, top %p)\n", (void*)evt.xreparent.event, (void*)oldParentRoot, (void*)oldParentTopParent, (void*)evt.xreparent.parent, (void*)parentRoot, (void*)parentTopParent, (void*)evt.xreparent.window, (void*)winRoot, (void*)winTopParent); #endif (*env)->CallVoidMethod(env, jwindow, windowReparentedID, parentResult); } break; */ // unhandled events .. yet .. default: DBG_PRINT("XCB: event . unhandled %d 0x%X call %p\n", (int)xcb_event_type, (unsigned int)xcb_event_type, (void*)(intptr_t)event_window); } free(evt); } }