static void processEvent(XEvent *event) { _GLFWwindow* window; switch (event->type) { case KeyPress: { // A keyboard key was pressed window = findWindow(event->xkey.window); if (window == NULL) return; _glfwInputKey(window, translateKey(event->xkey.keycode), GLFW_PRESS); _glfwInputChar(window, translateChar(&event->xkey)); break; } case KeyRelease: { // A keyboard key was released window = findWindow(event->xkey.window); if (window == NULL) return; // Do not report key releases for key repeats. For key repeats we // will get KeyRelease/KeyPress pairs with similar or identical // time stamps. User selected key repeat filtering is handled in // _glfwInputKey/_glfwInputChar. if (XEventsQueued(_glfwLibrary.X11.display, QueuedAfterReading)) { XEvent nextEvent; XPeekEvent(_glfwLibrary.X11.display, &nextEvent); if (nextEvent.type == KeyPress && nextEvent.xkey.window == event->xkey.window && nextEvent.xkey.keycode == event->xkey.keycode) { // This last check is a hack to work around key repeats // leaking through due to some sort of time drift // Toshiyuki Takahashi can press a button 16 times per // second so it's fairly safe to assume that no human is // pressing the key 50 times per second (value is ms) if ((nextEvent.xkey.time - event->xkey.time) < 20) { // Do not report anything for this event break; } } } _glfwInputKey(window, translateKey(event->xkey.keycode), GLFW_RELEASE); break; } case ButtonPress: { // A mouse button was pressed or a scrolling event occurred window = findWindow(event->xbutton.window); if (window == NULL) return; if (event->xbutton.button == Button1) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS); else if (event->xbutton.button == Button2) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS); else if (event->xbutton.button == Button3) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS); // XFree86 3.3.2 and later translates mouse wheel up/down into // mouse button 4 & 5 presses else if (event->xbutton.button == Button4) _glfwInputScroll(window, 0.0, 1.0); else if (event->xbutton.button == Button5) _glfwInputScroll(window, 0.0, -1.0); else if (event->xbutton.button == Button6) _glfwInputScroll(window, -1.0, 0.0); else if (event->xbutton.button == Button7) _glfwInputScroll(window, 1.0, 0.0); break; } case ButtonRelease: { // A mouse button was released window = findWindow(event->xbutton.window); if (window == NULL) return; if (event->xbutton.button == Button1) { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE); } else if (event->xbutton.button == Button2) { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE); } else if (event->xbutton.button == Button3) { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE); } break; } case EnterNotify: { // The cursor entered the window window = findWindow(event->xcrossing.window); if (window == NULL) return; if (window->cursorMode == GLFW_CURSOR_HIDDEN) hideCursor(window); _glfwInputCursorEnter(window, GL_TRUE); break; } case LeaveNotify: { // The cursor left the window window = findWindow(event->xcrossing.window); if (window == NULL) return; if (window->cursorMode == GLFW_CURSOR_HIDDEN) showCursor(window); _glfwInputCursorEnter(window, GL_FALSE); break; } case MotionNotify: { // The cursor was moved window = findWindow(event->xmotion.window); if (window == NULL) return; if (event->xmotion.x != window->X11.cursorPosX || event->xmotion.y != window->X11.cursorPosY) { // The cursor was moved by something other than GLFW int x, y; if (window->cursorMode == GLFW_CURSOR_CAPTURED) { if (_glfwLibrary.activeWindow != window) break; x = event->xmotion.x - window->X11.cursorPosX; y = event->xmotion.y - window->X11.cursorPosY; } else { x = event->xmotion.x; y = event->xmotion.y; } window->X11.cursorPosX = event->xmotion.x; window->X11.cursorPosY = event->xmotion.y; window->X11.cursorCentered = GL_FALSE; _glfwInputCursorMotion(window, x, y); } break; } case ConfigureNotify: { // The window configuration changed somehow window = findWindow(event->xconfigure.window); if (window == NULL) return; _glfwInputWindowSize(window, event->xconfigure.width, event->xconfigure.height); _glfwInputWindowPos(window, event->xconfigure.x, event->xconfigure.y); break; } case ClientMessage: { // Custom client message, probably from the window manager window = findWindow(event->xclient.window); if (window == NULL) return; if ((Atom) event->xclient.data.l[0] == _glfwLibrary.X11.wmDeleteWindow) { // The window manager was asked to close the window, for example by // the user pressing a 'close' window decoration button _glfwInputWindowCloseRequest(window); } else if (_glfwLibrary.X11.wmPing != None && (Atom) event->xclient.data.l[0] == _glfwLibrary.X11.wmPing) { // The window manager is pinging the application to ensure it's // still responding to events event->xclient.window = _glfwLibrary.X11.root; XSendEvent(_glfwLibrary.X11.display, event->xclient.window, False, SubstructureNotifyMask | SubstructureRedirectMask, event); } break; } case MapNotify: { // The window was mapped window = findWindow(event->xmap.window); if (window == NULL) return; _glfwInputWindowVisibility(window, GL_TRUE); _glfwInputWindowIconify(window, GL_FALSE); break; } case UnmapNotify: { // The window was unmapped window = findWindow(event->xmap.window); if (window == NULL) return; _glfwInputWindowVisibility(window, GL_FALSE); _glfwInputWindowIconify(window, GL_TRUE); break; } case FocusIn: { // The window gained focus window = findWindow(event->xfocus.window); if (window == NULL) return; _glfwInputWindowFocus(window, GL_TRUE); if (window->cursorMode == GLFW_CURSOR_CAPTURED) captureCursor(window); break; } case FocusOut: { // The window lost focus window = findWindow(event->xfocus.window); if (window == NULL) return; _glfwInputWindowFocus(window, GL_FALSE); if (window->cursorMode == GLFW_CURSOR_CAPTURED) showCursor(window); break; } case Expose: { // The window's contents was damaged window = findWindow(event->xexpose.window); if (window == NULL) return; _glfwInputWindowDamage(window); break; } case SelectionClear: { // The ownership of the selection was lost free(_glfwLibrary.X11.selection.string); _glfwLibrary.X11.selection.string = NULL; break; } case SelectionNotify: { // The selection conversion status is available XSelectionEvent* request = &event->xselection; if (_glfwReadSelection(request)) _glfwLibrary.X11.selection.status = _GLFW_CONVERSION_SUCCEEDED; else _glfwLibrary.X11.selection.status = _GLFW_CONVERSION_FAILED; break; } case SelectionRequest: { // The contents of the selection was requested XSelectionRequestEvent* request = &event->xselectionrequest; XEvent response; memset(&response, 0, sizeof(response)); response.xselection.property = _glfwWriteSelection(request); response.xselection.type = SelectionNotify; response.xselection.display = request->display; response.xselection.requestor = request->requestor; response.xselection.selection = request->selection; response.xselection.target = request->target; response.xselection.time = request->time; XSendEvent(_glfwLibrary.X11.display, request->requestor, False, 0, &response); break; } case DestroyNotify: return; default: { #if defined(_GLFW_HAS_XRANDR) switch (event->type - _glfwLibrary.X11.RandR.eventBase) { case RRScreenChangeNotify: { XRRUpdateConfiguration(event); break; } } #endif /*_GLFW_HAS_XRANDR*/ break; } } }
// Process the specified X event // static void processEvent(XEvent *event) { _GLFWwindow* window = NULL; if (event->type != GenericEvent) { window = _glfwFindWindowByHandle(event->xany.window); if (window == NULL) { // This is either an event for a destroyed GLFW window or an event // of a type not currently supported by GLFW return; } } switch (event->type) { case KeyPress: { _glfwInputKey(window, translateKey(event->xkey.keycode), GLFW_PRESS); if (!(event->xkey.state & ControlMask) && !(event->xkey.state & Mod1Mask /*Alt*/)) { _glfwInputChar(window, translateChar(&event->xkey)); } break; } case KeyRelease: { _glfwInputKey(window, translateKey(event->xkey.keycode), GLFW_RELEASE); break; } case ButtonPress: { if (event->xbutton.button == Button1) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS); else if (event->xbutton.button == Button2) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS); else if (event->xbutton.button == Button3) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS); // Modern X provides scroll events as mouse button presses else if (event->xbutton.button == Button4) _glfwInputScroll(window, 0.0, 1.0); else if (event->xbutton.button == Button5) _glfwInputScroll(window, 0.0, -1.0); else if (event->xbutton.button == Button6) _glfwInputScroll(window, -1.0, 0.0); else if (event->xbutton.button == Button7) _glfwInputScroll(window, 1.0, 0.0); break; } case ButtonRelease: { if (event->xbutton.button == Button1) { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE); } else if (event->xbutton.button == Button2) { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE); } else if (event->xbutton.button == Button3) { _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE); } break; } case EnterNotify: { if (window->cursorMode == GLFW_CURSOR_HIDDEN) hideCursor(window); _glfwInputCursorEnter(window, GL_TRUE); break; } case LeaveNotify: { if (window->cursorMode == GLFW_CURSOR_HIDDEN) showCursor(window); _glfwInputCursorEnter(window, GL_FALSE); break; } case MotionNotify: { if (event->xmotion.x != window->x11.cursorPosX || event->xmotion.y != window->x11.cursorPosY) { // The cursor was moved by something other than GLFW int x, y; if (window->cursorMode == GLFW_CURSOR_CAPTURED) { if (_glfw.focusedWindow != window) break; x = event->xmotion.x - window->x11.cursorPosX; y = event->xmotion.y - window->x11.cursorPosY; } else { x = event->xmotion.x; y = event->xmotion.y; } window->x11.cursorPosX = event->xmotion.x; window->x11.cursorPosY = event->xmotion.y; window->x11.cursorCentered = GL_FALSE; _glfwInputCursorMotion(window, x, y); } break; } case ConfigureNotify: { _glfwInputWindowSize(window, event->xconfigure.width, event->xconfigure.height); _glfwInputWindowPos(window, event->xconfigure.x, event->xconfigure.y); break; } case ClientMessage: { // Custom client message, probably from the window manager if ((Atom) event->xclient.data.l[0] == _glfw.x11.WM_DELETE_WINDOW) { // The window manager was asked to close the window, for example by // the user pressing a 'close' window decoration button _glfwInputWindowCloseRequest(window); } else if (_glfw.x11.NET_WM_PING != None && (Atom) event->xclient.data.l[0] == _glfw.x11.NET_WM_PING) { // The window manager is pinging the application to ensure it's // still responding to events event->xclient.window = _glfw.x11.root; XSendEvent(_glfw.x11.display, event->xclient.window, False, SubstructureNotifyMask | SubstructureRedirectMask, event); } break; } case MapNotify: { _glfwInputWindowVisibility(window, GL_TRUE); break; } case UnmapNotify: { _glfwInputWindowVisibility(window, GL_FALSE); break; } case FocusIn: { _glfwInputWindowFocus(window, GL_TRUE); if (window->cursorMode == GLFW_CURSOR_CAPTURED) captureCursor(window); break; } case FocusOut: { _glfwInputWindowFocus(window, GL_FALSE); if (window->cursorMode == GLFW_CURSOR_CAPTURED) showCursor(window); break; } case Expose: { _glfwInputWindowDamage(window); break; } case PropertyNotify: { if (event->xproperty.atom == _glfw.x11.WM_STATE && event->xproperty.state == PropertyNewValue) { struct { CARD32 state; Window icon; } *state = NULL; if (_glfwGetWindowProperty(window->x11.handle, _glfw.x11.WM_STATE, _glfw.x11.WM_STATE, (unsigned char**) &state) >= 2) { if (state->state == IconicState) _glfwInputWindowIconify(window, GL_TRUE); else if (state->state == NormalState) _glfwInputWindowIconify(window, GL_FALSE); } XFree(state); } break; } case SelectionClear: { // The ownership of the clipboard selection was lost free(_glfw.x11.selection.string); _glfw.x11.selection.string = NULL; break; } case SelectionRequest: { // The contents of the clipboard selection was requested XSelectionRequestEvent* request = &event->xselectionrequest; XEvent response; memset(&response, 0, sizeof(response)); response.xselection.property = _glfwWriteSelection(request); response.xselection.type = SelectionNotify; response.xselection.display = request->display; response.xselection.requestor = request->requestor; response.xselection.selection = request->selection; response.xselection.target = request->target; response.xselection.time = request->time; XSendEvent(_glfw.x11.display, request->requestor, False, 0, &response); break; } case DestroyNotify: return; case GenericEvent: { if (event->xcookie.extension == _glfw.x11.xi2.majorOpcode && XGetEventData(_glfw.x11.display, &event->xcookie)) { if (event->xcookie.evtype == XI_Motion) { XIDeviceEvent* data = (XIDeviceEvent*) event->xcookie.data; window = _glfwFindWindowByHandle(data->event); if (window) { if (data->event_x != window->x11.cursorPosX || data->event_y != window->x11.cursorPosY) { // The cursor was moved by something other than GLFW double x, y; if (window->cursorMode == GLFW_CURSOR_CAPTURED) { if (_glfw.focusedWindow != window) break; x = data->event_x - window->x11.cursorPosX; y = data->event_y - window->x11.cursorPosY; } else { x = data->event_x; y = data->event_y; } window->x11.cursorPosX = data->event_x; window->x11.cursorPosY = data->event_y; window->x11.cursorCentered = GL_FALSE; _glfwInputCursorMotion(window, x, y); } } } } XFreeEventData(_glfw.x11.display, &event->xcookie); break; } default: { switch (event->type - _glfw.x11.randr.eventBase) { case RRScreenChangeNotify: { XRRUpdateConfiguration(event); break; } } break; } } }