static int xim_forward_event (XIMS xims, IMForwardEventStruct *call_data) { X11IC *x11ic; XKeyEvent *xevent; GdkEventKey event; gboolean retval; LOG (1, "XIM_FORWARD_EVENT ic=%d connect_id=%d", call_data->icid, call_data->connect_id); x11ic = (X11IC *) g_hash_table_lookup (_x11_ic_table, GINT_TO_POINTER ((gint) call_data->icid)); g_return_val_if_fail (x11ic != NULL, 0); xevent = (XKeyEvent*) &(call_data->event); translate_key_event (gdk_display_get_default (), (GdkEvent *)&event, (XEvent *)xevent); event.send_event = xevent->send_event; event.window = NULL; if (event.type == GDK_KEY_RELEASE) { event.state |= IBUS_RELEASE_MASK; } retval = ibus_input_context_process_key_event (x11ic->context, event.keyval, event.hardware_keycode - 8, event.state); if (retval) { if (! x11ic->has_preedit_area) { _xim_set_cursor_location (x11ic); } return 1; } IMForwardEventStruct fe; memset (&fe, 0, sizeof (fe)); fe.major_code = XIM_FORWARD_EVENT; fe.icid = x11ic->icid; fe.connect_id = x11ic->connect_id; fe.sync_bit = 0; fe.serial_number = 0L; fe.event = call_data->event; IMForwardEvent (_xims, (XPointer) &fe); return 1; }
bool CannaJRKanji::process_key_event (const KeyEvent &key) { int size = 1024, n, ch; char buf[1024 + 1]; if (match_key_event (m_canna->m_factory->m_on_off_key, key, 0)) { m_enabled = !m_enabled; set_mode_line (); m_canna->reset (); return true; } if (!m_enabled) return false; ch = translate_key_event (key); if (ch == 0xffff) return false; n = jrKanjiString (m_context_id, ch, buf, size, &m_ks); // commit string if (n > 0 && !(m_ks.info & KanjiThroughInfo)) { buf[n] = '\0'; WideString dest; m_iconv.convert (dest, buf); m_canna->commit_string (dest); } // mode line string if (m_ks.info & KanjiModeInfo) set_mode_line (); // guide line string set_guide_line (); // preedit string if (m_ks.length > 0) { WideString dest; AttributeList attrs; unsigned int pos; pos = convert_string (dest, attrs, (const char *) m_ks.echoStr, m_ks.length, m_ks.revPos, m_ks.revLen); m_canna->update_preedit_string (dest, attrs); m_canna->update_preedit_caret (pos); if (!m_preediting && dest.length () <= 0) { m_canna->hide_preedit_string (); return !(m_ks.info & KanjiThroughInfo); } else { m_preediting = true; m_canna->show_preedit_string (); m_canna->hide_lookup_table (); return true; } } else if (m_ks.length == 0) { m_canna->update_preedit_string (utf8_mbstowcs ("")); m_canna->hide_preedit_string (); m_canna->hide_lookup_table (); if (m_preediting) { m_preediting = false; return true; } else { return !(m_ks.info & KanjiThroughInfo); } } m_canna->hide_lookup_table (); return !(m_ks.info & KanjiThroughInfo); }
static gboolean gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator, GdkDisplay *display, GdkEvent *event, XEvent *xevent) { GdkX11DeviceManagerCore *device_manager; GdkWindow *window; gboolean return_val; GdkToplevelX11 *toplevel = NULL; GdkX11Display *display_x11 = GDK_X11_DISPLAY (display); device_manager = GDK_X11_DEVICE_MANAGER_CORE (translator); return_val = FALSE; window = get_event_window (translator, xevent); if (window) { if (GDK_WINDOW_DESTROYED (window) || !GDK_IS_WINDOW (window)) return FALSE; toplevel = _gdk_x11_window_get_toplevel (window); g_object_ref (window); } event->any.window = window; event->any.send_event = xevent->xany.send_event ? TRUE : FALSE; if (window && GDK_WINDOW_DESTROYED (window)) { if (xevent->type != DestroyNotify) { return_val = FALSE; goto done; } } if (window && (xevent->type == MotionNotify || xevent->type == ButtonRelease)) { if (_gdk_x11_moveresize_handle_event (xevent)) { return_val = FALSE; goto done; } } /* We do a "manual" conversion of the XEvent to a * GdkEvent. The structures are mostly the same so * the conversion is fairly straightforward. We also * optionally print debugging info regarding events * received. */ return_val = TRUE; switch (xevent->type) { case KeyPress: if (window == NULL) { return_val = FALSE; break; } translate_key_event (display, device_manager, event, xevent); set_user_time (window, event); break; case KeyRelease: if (window == NULL) { return_val = FALSE; break; } /* Emulate detectable auto-repeat by checking to see * if the next event is a key press with the same * keycode and timestamp, and if so, ignoring the event. */ if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display)) { XEvent next_event; XPeekEvent (xevent->xkey.display, &next_event); if (next_event.type == KeyPress && next_event.xkey.keycode == xevent->xkey.keycode && next_event.xkey.time == xevent->xkey.time) { return_val = FALSE; break; } } translate_key_event (display, device_manager, event, xevent); break; case ButtonPress: GDK_NOTE (EVENTS, g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d", xevent->xbutton.window, xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.button)); if (window == NULL) { return_val = FALSE; break; } /* If we get a ButtonPress event where the button is 4 or 5, it's a Scroll event */ switch (xevent->xbutton.button) { case 4: /* up */ case 5: /* down */ case 6: /* left */ case 7: /* right */ event->scroll.type = GDK_SCROLL; if (xevent->xbutton.button == 4) event->scroll.direction = GDK_SCROLL_UP; else if (xevent->xbutton.button == 5) event->scroll.direction = GDK_SCROLL_DOWN; else if (xevent->xbutton.button == 6) event->scroll.direction = GDK_SCROLL_LEFT; else event->scroll.direction = GDK_SCROLL_RIGHT; event->scroll.window = window; event->scroll.time = xevent->xbutton.time; event->scroll.x = (gdouble) xevent->xbutton.x; event->scroll.y = (gdouble) xevent->xbutton.y; event->scroll.x_root = (gdouble) xevent->xbutton.x_root; event->scroll.y_root = (gdouble) xevent->xbutton.y_root; event->scroll.state = (GdkModifierType) xevent->xbutton.state; event->scroll.device = device_manager->core_pointer; if (!set_screen_from_root (display, event, xevent->xbutton.root)) { return_val = FALSE; break; } break; default: event->button.type = GDK_BUTTON_PRESS; event->button.window = window; event->button.time = xevent->xbutton.time; event->button.x = (gdouble) xevent->xbutton.x; event->button.y = (gdouble) xevent->xbutton.y; event->button.x_root = (gdouble) xevent->xbutton.x_root; event->button.y_root = (gdouble) xevent->xbutton.y_root; event->button.axes = NULL; event->button.state = (GdkModifierType) xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.device = device_manager->core_pointer; if (!set_screen_from_root (display, event, xevent->xbutton.root)) return_val = FALSE; break; } set_user_time (window, event); break; case ButtonRelease: GDK_NOTE (EVENTS, g_message ("button release:\twindow: %ld x,y: %d %d button: %d", xevent->xbutton.window, xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.button)); if (window == NULL) { return_val = FALSE; break; } /* We treat button presses as scroll wheel events, so ignore the release */ if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 || xevent->xbutton.button == 6 || xevent->xbutton.button == 7) { return_val = FALSE; break; } event->button.type = GDK_BUTTON_RELEASE; event->button.window = window; event->button.time = xevent->xbutton.time; event->button.x = (gdouble) xevent->xbutton.x; event->button.y = (gdouble) xevent->xbutton.y; event->button.x_root = (gdouble) xevent->xbutton.x_root; event->button.y_root = (gdouble) xevent->xbutton.y_root; event->button.axes = NULL; event->button.state = (GdkModifierType) xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.device = device_manager->core_pointer; if (!set_screen_from_root (display, event, xevent->xbutton.root)) return_val = FALSE; break; case MotionNotify: GDK_NOTE (EVENTS, g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s", xevent->xmotion.window, xevent->xmotion.x, xevent->xmotion.y, (xevent->xmotion.is_hint) ? "true" : "false")); if (window == NULL) { return_val = FALSE; break; } event->motion.type = GDK_MOTION_NOTIFY; event->motion.window = window; event->motion.time = xevent->xmotion.time; event->motion.x = (gdouble) xevent->xmotion.x; event->motion.y = (gdouble) xevent->xmotion.y; event->motion.x_root = (gdouble) xevent->xmotion.x_root; event->motion.y_root = (gdouble) xevent->xmotion.y_root; event->motion.axes = NULL; event->motion.state = (GdkModifierType) xevent->xmotion.state; event->motion.is_hint = xevent->xmotion.is_hint; event->motion.device = device_manager->core_pointer; if (!set_screen_from_root (display, event, xevent->xbutton.root)) { return_val = FALSE; break; } break; case EnterNotify: GDK_NOTE (EVENTS, g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld", xevent->xcrossing.window, xevent->xcrossing.detail, xevent->xcrossing.subwindow)); if (window == NULL) { return_val = FALSE; break; } if (!set_screen_from_root (display, event, xevent->xbutton.root)) { return_val = FALSE; break; } event->crossing.type = GDK_ENTER_NOTIFY; event->crossing.window = window; gdk_event_set_device (event, device_manager->core_pointer); /* If the subwindow field of the XEvent is non-NULL, then * lookup the corresponding GdkWindow. */ if (xevent->xcrossing.subwindow != None) event->crossing.subwindow = gdk_x11_window_lookup_for_display (display, xevent->xcrossing.subwindow); else event->crossing.subwindow = NULL; event->crossing.time = xevent->xcrossing.time; event->crossing.x = (gdouble) xevent->xcrossing.x; event->crossing.y = (gdouble) xevent->xcrossing.y; event->crossing.x_root = (gdouble) xevent->xcrossing.x_root; event->crossing.y_root = (gdouble) xevent->xcrossing.y_root; event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode); event->crossing.detail = translate_notify_type (xevent->xcrossing.detail); event->crossing.focus = xevent->xcrossing.focus; event->crossing.state = xevent->xcrossing.state; break; case LeaveNotify: GDK_NOTE (EVENTS, g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld", xevent->xcrossing.window, xevent->xcrossing.detail, xevent->xcrossing.subwindow)); if (window == NULL) { return_val = FALSE; break; } if (!set_screen_from_root (display, event, xevent->xbutton.root)) { return_val = FALSE; break; } event->crossing.type = GDK_LEAVE_NOTIFY; event->crossing.window = window; gdk_event_set_device (event, device_manager->core_pointer); /* If the subwindow field of the XEvent is non-NULL, then * lookup the corresponding GdkWindow. */ if (xevent->xcrossing.subwindow != None) event->crossing.subwindow = gdk_x11_window_lookup_for_display (display, xevent->xcrossing.subwindow); else event->crossing.subwindow = NULL; event->crossing.time = xevent->xcrossing.time; event->crossing.x = (gdouble) xevent->xcrossing.x; event->crossing.y = (gdouble) xevent->xcrossing.y; event->crossing.x_root = (gdouble) xevent->xcrossing.x_root; event->crossing.y_root = (gdouble) xevent->xcrossing.y_root; event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode); event->crossing.detail = translate_notify_type (xevent->xcrossing.detail); event->crossing.focus = xevent->xcrossing.focus; event->crossing.state = xevent->xcrossing.state; break; /* We only care about focus events that indicate that _this_ * window (not a ancestor or child) got or lost the focus */ case FocusIn: GDK_NOTE (EVENTS, g_message ("focus in:\t\twindow: %ld, detail: %s, mode: %s", xevent->xfocus.window, notify_details[xevent->xfocus.detail], notify_modes[xevent->xfocus.mode])); if (toplevel) { gboolean had_focus = HAS_FOCUS (toplevel); switch (xevent->xfocus.detail) { case NotifyAncestor: case NotifyVirtual: /* When the focus moves from an ancestor of the window to * the window or a descendent of the window, *and* the * pointer is inside the window, then we were previously * receiving keystroke events in the has_pointer_focus * case and are now receiving them in the * has_focus_window case. */ if (toplevel->has_pointer && xevent->xfocus.mode != NotifyGrab && xevent->xfocus.mode != NotifyUngrab) toplevel->has_pointer_focus = FALSE; /* fall through */ case NotifyNonlinear: case NotifyNonlinearVirtual: if (xevent->xfocus.mode != NotifyGrab && xevent->xfocus.mode != NotifyUngrab) toplevel->has_focus_window = TRUE; /* We pretend that the focus moves to the grab * window, so we pay attention to NotifyGrab * NotifyUngrab, and ignore NotifyWhileGrabbed */ if (xevent->xfocus.mode != NotifyWhileGrabbed) toplevel->has_focus = TRUE; break; case NotifyPointer: /* The X server sends NotifyPointer/NotifyGrab, * but the pointer focus is ignored while a * grab is in effect */ if (xevent->xfocus.mode != NotifyGrab && xevent->xfocus.mode != NotifyUngrab) toplevel->has_pointer_focus = TRUE; break; case NotifyInferior: case NotifyPointerRoot: case NotifyDetailNone: break; } if (HAS_FOCUS (toplevel) != had_focus) generate_focus_event (device_manager, window, TRUE); } break; case FocusOut: GDK_NOTE (EVENTS, g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s", xevent->xfocus.window, notify_details[xevent->xfocus.detail], notify_modes[xevent->xfocus.mode])); if (toplevel) { gboolean had_focus = HAS_FOCUS (toplevel); switch (xevent->xfocus.detail) { case NotifyAncestor: case NotifyVirtual: /* When the focus moves from the window or a descendent * of the window to an ancestor of the window, *and* the * pointer is inside the window, then we were previously * receiving keystroke events in the has_focus_window * case and are now receiving them in the * has_pointer_focus case. */ if (toplevel->has_pointer && xevent->xfocus.mode != NotifyGrab && xevent->xfocus.mode != NotifyUngrab) toplevel->has_pointer_focus = TRUE; /* fall through */ case NotifyNonlinear: case NotifyNonlinearVirtual: if (xevent->xfocus.mode != NotifyGrab && xevent->xfocus.mode != NotifyUngrab) toplevel->has_focus_window = FALSE; if (xevent->xfocus.mode != NotifyWhileGrabbed) toplevel->has_focus = FALSE; break; case NotifyPointer: if (xevent->xfocus.mode != NotifyGrab && xevent->xfocus.mode != NotifyUngrab) toplevel->has_pointer_focus = FALSE; break; case NotifyInferior: case NotifyPointerRoot: case NotifyDetailNone: break; } if (HAS_FOCUS (toplevel) != had_focus) generate_focus_event (device_manager, window, FALSE); } break; default: return_val = FALSE; } done: if (return_val) { if (event->any.window) g_object_ref (event->any.window); if (((event->any.type == GDK_ENTER_NOTIFY) || (event->any.type == GDK_LEAVE_NOTIFY)) && (event->crossing.subwindow != NULL)) g_object_ref (event->crossing.subwindow); } else { /* Mark this event as having no resources to be freed */ event->any.window = NULL; event->any.type = GDK_NOTHING; } if (window) g_object_unref (window); return return_val; }
static gboolean event_translate (ClutterBackend *backend, ClutterEvent *event, XEvent *xevent) { ClutterBackendX11 *backend_x11; ClutterStageX11 *stage_x11; ClutterStage *stage; ClutterStageWindow *impl; ClutterDeviceManager *manager; gboolean res, not_yet_handled = FALSE; Window xwindow, stage_xwindow; ClutterInputDevice *device; backend_x11 = CLUTTER_BACKEND_X11 (backend); xwindow = xevent->xany.window; if (backend_x11->event_filters) { GSList *node; node = backend_x11->event_filters; while (node) { ClutterX11EventFilter *filter = node->data; switch (filter->func (xevent, event, filter->data)) { case CLUTTER_X11_FILTER_CONTINUE: break; case CLUTTER_X11_FILTER_TRANSLATE: return TRUE; case CLUTTER_X11_FILTER_REMOVE: return FALSE; default: break; } node = node->next; } } /* Do further processing only on events for the stage window (the x11 * filters might be getting events for other windows, so do not mess * them about. */ stage = clutter_x11_get_stage_from_window (xwindow); if (stage == NULL) return FALSE; impl = _clutter_stage_get_window (stage); stage_x11 = CLUTTER_STAGE_X11 (impl); stage_xwindow = xwindow; /* clutter_x11_get_stage_window (stage); */ event->any.stage = stage; res = TRUE; update_last_event_time (backend_x11, xevent); manager = clutter_device_manager_get_default (); switch (xevent->type) { case ConfigureNotify: if (!stage_x11->is_foreign_xwin) { CLUTTER_NOTE (BACKEND, "%s: ConfigureNotify[%x] (%d, %d)", G_STRLOC, (unsigned int) stage_x11->xwin, xevent->xconfigure.width, xevent->xconfigure.height); /* Queue a relayout - we want glViewport to be called * with the correct values, and this is done in ClutterStage * via _cogl_onscreen_clutter_backend_set_size (). * * We queue a relayout, because if this ConfigureNotify is * in response to a size we set in the application, the * set_size above is essentially a null-op. * * Make sure we do this only when the size has changed, * otherwise we end up relayouting on window moves. */ if ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) || (stage_x11->xwin_width != xevent->xconfigure.width) || (stage_x11->xwin_height != xevent->xconfigure.height)) clutter_actor_queue_relayout (CLUTTER_ACTOR (stage)); /* If we're fullscreened, we want these variables to * represent the size of the window before it was set * to fullscreen. */ if (!(stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN)) { stage_x11->xwin_width = xevent->xconfigure.width; stage_x11->xwin_height = xevent->xconfigure.height; } clutter_actor_set_size (CLUTTER_ACTOR (stage), xevent->xconfigure.width, xevent->xconfigure.height); CLUTTER_UNSET_PRIVATE_FLAGS (stage_x11->wrapper, CLUTTER_STAGE_IN_RESIZE); /* the resize process is complete, so we can ask the stage * to set up the GL viewport with the new size */ clutter_stage_ensure_viewport (stage); } res = FALSE; break; case PropertyNotify: if (xevent->xproperty.atom == backend_x11->atom_NET_WM_STATE && xevent->xproperty.window == stage_xwindow && !stage_x11->is_foreign_xwin) { Atom type; gint format; gulong n_items, bytes_after; guchar *data = NULL; gboolean fullscreen_set = FALSE; clutter_x11_trap_x_errors (); XGetWindowProperty (backend_x11->xdpy, stage_xwindow, backend_x11->atom_NET_WM_STATE, 0, G_MAXLONG, False, XA_ATOM, &type, &format, &n_items, &bytes_after, &data); clutter_x11_untrap_x_errors (); if (type != None && data != NULL) { Atom *atoms = (Atom *) data; gulong i; gboolean is_fullscreen = FALSE; for (i = 0; i < n_items; i++) { if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN) fullscreen_set = TRUE; } is_fullscreen = (stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN); if (fullscreen_set != is_fullscreen) { if (fullscreen_set) stage_x11->state |= CLUTTER_STAGE_STATE_FULLSCREEN; else stage_x11->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN; stage_x11->fullscreening = fullscreen_set; event->type = CLUTTER_STAGE_STATE; event->stage_state.changed_mask = CLUTTER_STAGE_STATE_FULLSCREEN; event->stage_state.new_state = stage_x11->state; } else res = FALSE; XFree (data); } else res = FALSE; } else res = FALSE; break; case MapNotify: res = FALSE; break; case UnmapNotify: res = FALSE; break; case FocusIn: if (!(stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED)) { /* TODO: check xevent->xfocus.detail ? */ stage_x11->state |= CLUTTER_STAGE_STATE_ACTIVATED; event->type = CLUTTER_STAGE_STATE; event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED; event->stage_state.new_state = stage_x11->state; } else res = FALSE; break; case FocusOut: if (stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED) { stage_x11->state &= ~CLUTTER_STAGE_STATE_ACTIVATED; event->type = CLUTTER_STAGE_STATE; event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED; event->stage_state.new_state = stage_x11->state; } else res = FALSE; break; case Expose: { CLUTTER_NOTE (MULTISTAGE, "expose for stage: %p, redrawing", stage); clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); res = FALSE; } break; case DestroyNotify: CLUTTER_NOTE (EVENT, "destroy notify:\txid: %ld", xevent->xdestroywindow.window); if (xevent->xdestroywindow.window == stage_xwindow && !stage_x11->is_foreign_xwin) event->type = event->any.type = CLUTTER_DESTROY_NOTIFY; else res = FALSE; break; case ClientMessage: CLUTTER_NOTE (EVENT, "client message"); event->type = event->any.type = CLUTTER_CLIENT_MESSAGE; if (xevent->xclient.message_type == backend_x11->atom_XEMBED) res = handle_xembed_event (backend_x11, xevent); else if (xevent->xclient.message_type == backend_x11->atom_WM_PROTOCOLS) { res = handle_wm_protocols_event (backend_x11, stage_xwindow, xevent); event->type = event->any.type = CLUTTER_DELETE; } break; case KeyPress: event->key.type = event->type = CLUTTER_KEY_PRESS; event->key.device = clutter_device_manager_get_core_device (manager, CLUTTER_KEYBOARD_DEVICE); translate_key_event (backend, event, xevent); set_user_time (backend_x11, &xwindow, xevent->xkey.time); break; case KeyRelease: /* old-style X11 terminals require that even modern X11 send * KeyPress/KeyRelease pairs when auto-repeating. for this * reason modern(-ish) API like XKB has a way to detect * auto-repeat and do a single KeyRelease at the end of a * KeyPress sequence. * * this check emulates XKB's detectable auto-repeat; we peek * the next event and check if it's a KeyPress for the same key * and timestamp - and then ignore it if it matches the * KeyRelease */ if (XPending (xevent->xkey.display)) { XEvent next_event; XPeekEvent (xevent->xkey.display, &next_event); if (next_event.type == KeyPress && next_event.xkey.keycode == xevent->xkey.keycode && next_event.xkey.time == xevent->xkey.time) { res = FALSE; break; } } event->key.type = event->type = CLUTTER_KEY_RELEASE; event->key.device = clutter_device_manager_get_core_device (manager, CLUTTER_KEYBOARD_DEVICE); translate_key_event (backend, event, xevent); break; default: /* ignore every other event */ not_yet_handled = TRUE; break; } /* Input device event handling.. */ if (not_yet_handled) { device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE); /* Regular X event */ switch (xevent->type) { case ButtonPress: switch (xevent->xbutton.button) { case 4: /* up */ case 5: /* down */ case 6: /* left */ case 7: /* right */ event->scroll.type = event->type = CLUTTER_SCROLL; if (xevent->xbutton.button == 4) event->scroll.direction = CLUTTER_SCROLL_UP; else if (xevent->xbutton.button == 5) event->scroll.direction = CLUTTER_SCROLL_DOWN; else if (xevent->xbutton.button == 6) event->scroll.direction = CLUTTER_SCROLL_LEFT; else event->scroll.direction = CLUTTER_SCROLL_RIGHT; event->scroll.time = xevent->xbutton.time; event->scroll.x = xevent->xbutton.x; event->scroll.y = xevent->xbutton.y; event->scroll.modifier_state = xevent->xbutton.state; event->scroll.device = device; break; default: event->button.type = event->type = CLUTTER_BUTTON_PRESS; event->button.time = xevent->xbutton.time; event->button.x = xevent->xbutton.x; event->button.y = xevent->xbutton.y; event->button.modifier_state = xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.device = device; break; } set_user_time (backend_x11, &xwindow, event->button.time); res = TRUE; break; case ButtonRelease: /* scroll events don't have a corresponding release */ if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 || xevent->xbutton.button == 6 || xevent->xbutton.button == 7) { res = FALSE; goto out; } event->button.type = event->type = CLUTTER_BUTTON_RELEASE; event->button.time = xevent->xbutton.time; event->button.x = xevent->xbutton.x; event->button.y = xevent->xbutton.y; event->button.modifier_state = xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.device = device; res = TRUE; break; case MotionNotify: event->motion.type = event->type = CLUTTER_MOTION; event->motion.time = xevent->xmotion.time; event->motion.x = xevent->xmotion.x; event->motion.y = xevent->xmotion.y; event->motion.modifier_state = xevent->xmotion.state; event->motion.device = device; res = TRUE; break; case EnterNotify: /* we know that we are entering the stage here */ _clutter_input_device_set_stage (device, stage); CLUTTER_NOTE (EVENT, "Entering the stage"); /* Convert enter notifies to motion events because X doesn't emit the corresponding motion notify */ event->motion.type = event->type = CLUTTER_MOTION; event->motion.time = xevent->xcrossing.time; event->motion.x = xevent->xcrossing.x; event->motion.y = xevent->xcrossing.y; event->motion.modifier_state = xevent->xcrossing.state; event->motion.source = CLUTTER_ACTOR (stage); event->motion.device = device; res = TRUE; break; case LeaveNotify: if (device->stage == NULL) { CLUTTER_NOTE (EVENT, "Discarding LeaveNotify for ButtonRelease " "event off-stage"); res = FALSE; goto out; } /* we know that we are leaving the stage here */ _clutter_input_device_set_stage (device, NULL); CLUTTER_NOTE (EVENT, "Leaving the stage (time:%u)", event->crossing.time); event->crossing.type = event->type = CLUTTER_LEAVE; event->crossing.time = xevent->xcrossing.time; event->crossing.x = xevent->xcrossing.x; event->crossing.y = xevent->xcrossing.y; event->crossing.source = CLUTTER_ACTOR (stage); event->crossing.device = device; res = TRUE; break; default: res = FALSE; break; } } /* XInput fun...*/ if (!res && clutter_x11_has_xinput ()) { #ifdef HAVE_XINPUT int *ev_types = backend_x11->event_types; int button_press, button_release; int key_press, key_release; int motion_notify; button_press = ev_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT]; button_release = ev_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT]; motion_notify = ev_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT]; key_press = ev_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT]; key_release = ev_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT]; CLUTTER_NOTE (EVENT, "XInput event type: %d", xevent->type); if (xevent->type == button_press) { XDeviceButtonEvent *xbev = (XDeviceButtonEvent *) xevent; device = _clutter_x11_get_device_for_xid (xbev->deviceid); _clutter_input_device_set_stage (device, stage); CLUTTER_NOTE (EVENT, "XI ButtonPress for %li ('%s') at %d, %d", xbev->deviceid, device->device_name, xbev->x, xbev->y); switch (xbev->button) { case 4: case 5: case 6: case 7: event->scroll.type = event->type = CLUTTER_SCROLL; if (xbev->button == 4) event->scroll.direction = CLUTTER_SCROLL_UP; else if (xbev->button == 5) event->scroll.direction = CLUTTER_SCROLL_DOWN; else if (xbev->button == 6) event->scroll.direction = CLUTTER_SCROLL_LEFT; else event->scroll.direction = CLUTTER_SCROLL_RIGHT; event->scroll.time = xbev->time; event->scroll.x = xbev->x; event->scroll.y = xbev->y; event->scroll.modifier_state = xbev->state; event->scroll.device = device; break; default: event->button.type = event->type = CLUTTER_BUTTON_PRESS; event->button.time = xbev->time; event->button.x = xbev->x; event->button.y = xbev->y; event->button.modifier_state = xbev->state; event->button.button = xbev->button; event->button.device = device; break; } set_user_time (backend_x11, &xwindow, xbev->time); res = TRUE; } else if (xevent->type == button_release) { XDeviceButtonEvent *xbev = (XDeviceButtonEvent *)xevent; device = _clutter_x11_get_device_for_xid (xbev->deviceid); _clutter_input_device_set_stage (device, stage); CLUTTER_NOTE (EVENT, "XI ButtonRelease for %li ('%s') at %d, %d", xbev->deviceid, device->device_name, xbev->x, xbev->y); /* scroll events don't have a corresponding release */ if (xbev->button == 4 || xbev->button == 5 || xbev->button == 6 || xbev->button == 7) { res = FALSE; goto out; } event->button.type = event->type = CLUTTER_BUTTON_RELEASE; event->button.time = xbev->time; event->button.x = xbev->x; event->button.y = xbev->y; event->button.modifier_state = xbev->state; event->button.button = xbev->button; event->button.device = device; res = TRUE; } else if (xevent->type == motion_notify) { XDeviceMotionEvent *xmev = (XDeviceMotionEvent *)xevent; device = _clutter_x11_get_device_for_xid (xmev->deviceid); _clutter_input_device_set_stage (device, stage); CLUTTER_NOTE (EVENT, "XI Motion for %li ('%s') at %d, %d", xmev->deviceid, device->device_name, xmev->x, xmev->y); event->motion.type = event->type = CLUTTER_MOTION; event->motion.time = xmev->time; event->motion.x = xmev->x; event->motion.y = xmev->y; event->motion.modifier_state = xmev->state; event->motion.device = device; res = TRUE; } else if (xevent->type == key_press || xevent->type == key_release) { /* the XInput 1.x handling of key presses/releases is broken: * it makes key repeat, key presses and releases outside the * window not generate events even when the window has focus */ XDeviceKeyEvent *xkev = (XDeviceKeyEvent *) xevent; XEvent xevent_converted; convert_xdevicekey_to_xkey (xkev, &xevent_converted); event->key.type = event->type = (xevent->type == key_press) ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE; translate_key_event (backend, event, &xevent_converted); if (xevent->type == key_press) set_user_time (backend_x11, &xwindow, xkev->time); } else #endif /* HAVE_XINPUT */ { CLUTTER_NOTE (EVENT, "Uknown Event"); res = FALSE; } } out: return res; }
static gboolean gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator, GdkDisplay *display, GdkEvent *event, XEvent *xevent) { GdkWindowImplX11 *impl; GdkX11DeviceManagerCore *device_manager; GdkWindow *window; gboolean return_val; int scale; GdkX11Display *display_x11 = GDK_X11_DISPLAY (display); device_manager = GDK_X11_DEVICE_MANAGER_CORE (translator); window = get_event_window (translator, xevent); scale = 1; if (window) { if (GDK_WINDOW_DESTROYED (window) || !GDK_IS_WINDOW (window)) return FALSE; g_object_ref (window); impl = GDK_WINDOW_IMPL_X11 (window->impl); scale = impl->window_scale; } event->any.window = window; event->any.send_event = xevent->xany.send_event ? TRUE : FALSE; if (window && GDK_WINDOW_DESTROYED (window)) { if (xevent->type != DestroyNotify) { return_val = FALSE; goto done; } } if (window && (xevent->type == MotionNotify || xevent->type == ButtonRelease)) { if (_gdk_x11_moveresize_handle_event (xevent)) { return_val = FALSE; goto done; } } /* We do a "manual" conversion of the XEvent to a * GdkEvent. The structures are mostly the same so * the conversion is fairly straightforward. We also * optionally print debugging info regarding events * received. */ return_val = TRUE; switch (xevent->type) { case KeyPress: if (window == NULL) { return_val = FALSE; break; } translate_key_event (display, device_manager, event, xevent); set_user_time (window, event); break; case KeyRelease: if (window == NULL) { return_val = FALSE; break; } /* Emulate detectable auto-repeat by checking to see * if the next event is a key press with the same * keycode and timestamp, and if so, ignoring the event. */ if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display)) { XEvent next_event; XPeekEvent (xevent->xkey.display, &next_event); if (next_event.type == KeyPress && next_event.xkey.keycode == xevent->xkey.keycode && next_event.xkey.time == xevent->xkey.time) { return_val = FALSE; break; } } translate_key_event (display, device_manager, event, xevent); break; case ButtonPress: GDK_NOTE (EVENTS, g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d", xevent->xbutton.window, xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.button)); if (window == NULL) { return_val = FALSE; break; } /* If we get a ButtonPress event where the button is 4 or 5, it's a Scroll event */ switch (xevent->xbutton.button) { case 4: /* up */ case 5: /* down */ case 6: /* left */ case 7: /* right */ event->scroll.type = GDK_SCROLL; if (xevent->xbutton.button == 4) event->scroll.direction = GDK_SCROLL_UP; else if (xevent->xbutton.button == 5) event->scroll.direction = GDK_SCROLL_DOWN; else if (xevent->xbutton.button == 6) event->scroll.direction = GDK_SCROLL_LEFT; else event->scroll.direction = GDK_SCROLL_RIGHT; event->scroll.window = window; event->scroll.time = xevent->xbutton.time; event->scroll.x = (gdouble) xevent->xbutton.x / scale; event->scroll.y = (gdouble) xevent->xbutton.y / scale; event->scroll.x_root = (gdouble) xevent->xbutton.x_root / scale; event->scroll.y_root = (gdouble) xevent->xbutton.y_root / scale; event->scroll.state = (GdkModifierType) xevent->xbutton.state; event->scroll.device = device_manager->core_pointer; event->scroll.delta_x = 0; event->scroll.delta_y = 0; if (!set_screen_from_root (display, event, xevent->xbutton.root)) { return_val = FALSE; break; } break; default: event->button.type = GDK_BUTTON_PRESS; event->button.window = window; event->button.time = xevent->xbutton.time; event->button.x = (gdouble) xevent->xbutton.x / scale; event->button.y = (gdouble) xevent->xbutton.y / scale; event->button.x_root = (gdouble) xevent->xbutton.x_root / scale; event->button.y_root = (gdouble) xevent->xbutton.y_root / scale; event->button.axes = NULL; event->button.state = (GdkModifierType) xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.device = device_manager->core_pointer; if (!set_screen_from_root (display, event, xevent->xbutton.root)) return_val = FALSE; break; } set_user_time (window, event); break; case ButtonRelease: GDK_NOTE (EVENTS, g_message ("button release:\twindow: %ld x,y: %d %d button: %d", xevent->xbutton.window, xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.button)); if (window == NULL) { return_val = FALSE; break; } /* We treat button presses as scroll wheel events, so ignore the release */ if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 || xevent->xbutton.button == 6 || xevent->xbutton.button == 7) { return_val = FALSE; break; } event->button.type = GDK_BUTTON_RELEASE; event->button.window = window; event->button.time = xevent->xbutton.time; event->button.x = (gdouble) xevent->xbutton.x / scale; event->button.y = (gdouble) xevent->xbutton.y / scale; event->button.x_root = (gdouble) xevent->xbutton.x_root / scale; event->button.y_root = (gdouble) xevent->xbutton.y_root / scale; event->button.axes = NULL; event->button.state = (GdkModifierType) xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.device = device_manager->core_pointer; if (!set_screen_from_root (display, event, xevent->xbutton.root)) return_val = FALSE; break; case MotionNotify: GDK_NOTE (EVENTS, g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s", xevent->xmotion.window, xevent->xmotion.x, xevent->xmotion.y, (xevent->xmotion.is_hint) ? "true" : "false")); if (window == NULL) { return_val = FALSE; break; } event->motion.type = GDK_MOTION_NOTIFY; event->motion.window = window; event->motion.time = xevent->xmotion.time; event->motion.x = (gdouble) xevent->xmotion.x / scale; event->motion.y = (gdouble) xevent->xmotion.y / scale; event->motion.x_root = (gdouble) xevent->xmotion.x_root / scale; event->motion.y_root = (gdouble) xevent->xmotion.y_root / scale; event->motion.axes = NULL; event->motion.state = (GdkModifierType) xevent->xmotion.state; event->motion.is_hint = xevent->xmotion.is_hint; event->motion.device = device_manager->core_pointer; if (!set_screen_from_root (display, event, xevent->xbutton.root)) { return_val = FALSE; break; } break; case EnterNotify: GDK_NOTE (EVENTS, g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld", xevent->xcrossing.window, xevent->xcrossing.detail, xevent->xcrossing.subwindow)); if (window == NULL) { return_val = FALSE; break; } if (!set_screen_from_root (display, event, xevent->xbutton.root)) { return_val = FALSE; break; } event->crossing.type = GDK_ENTER_NOTIFY; event->crossing.window = window; gdk_event_set_device (event, device_manager->core_pointer); /* If the subwindow field of the XEvent is non-NULL, then * lookup the corresponding GdkWindow. */ if (xevent->xcrossing.subwindow != None) event->crossing.subwindow = gdk_x11_window_lookup_for_display (display, xevent->xcrossing.subwindow); else event->crossing.subwindow = NULL; event->crossing.time = xevent->xcrossing.time; event->crossing.x = (gdouble) xevent->xcrossing.x / scale; event->crossing.y = (gdouble) xevent->xcrossing.y / scale; event->crossing.x_root = (gdouble) xevent->xcrossing.x_root / scale; event->crossing.y_root = (gdouble) xevent->xcrossing.y_root / scale; event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode); event->crossing.detail = translate_notify_type (xevent->xcrossing.detail); event->crossing.focus = xevent->xcrossing.focus; event->crossing.state = xevent->xcrossing.state; break; case LeaveNotify: GDK_NOTE (EVENTS, g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld", xevent->xcrossing.window, xevent->xcrossing.detail, xevent->xcrossing.subwindow)); if (window == NULL) { return_val = FALSE; break; } if (!set_screen_from_root (display, event, xevent->xbutton.root)) { return_val = FALSE; break; } event->crossing.type = GDK_LEAVE_NOTIFY; event->crossing.window = window; gdk_event_set_device (event, device_manager->core_pointer); /* If the subwindow field of the XEvent is non-NULL, then * lookup the corresponding GdkWindow. */ if (xevent->xcrossing.subwindow != None) event->crossing.subwindow = gdk_x11_window_lookup_for_display (display, xevent->xcrossing.subwindow); else event->crossing.subwindow = NULL; event->crossing.time = xevent->xcrossing.time; event->crossing.x = (gdouble) xevent->xcrossing.x / scale; event->crossing.y = (gdouble) xevent->xcrossing.y / scale; event->crossing.x_root = (gdouble) xevent->xcrossing.x_root / scale; event->crossing.y_root = (gdouble) xevent->xcrossing.y_root / scale; event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode); event->crossing.detail = translate_notify_type (xevent->xcrossing.detail); event->crossing.focus = xevent->xcrossing.focus; event->crossing.state = xevent->xcrossing.state; break; case FocusIn: case FocusOut: if (window) _gdk_device_manager_core_handle_focus (window, xevent->xfocus.window, device_manager->core_keyboard, NULL, xevent->type == FocusIn, xevent->xfocus.detail, xevent->xfocus.mode); return_val = FALSE; break; default: return_val = FALSE; } done: if (return_val) { if (event->any.window) g_object_ref (event->any.window); if (((event->any.type == GDK_ENTER_NOTIFY) || (event->any.type == GDK_LEAVE_NOTIFY)) && (event->crossing.subwindow != NULL)) g_object_ref (event->crossing.subwindow); } else { /* Mark this event as having no resources to be freed */ event->any.window = NULL; event->any.type = GDK_NOTHING; } if (window) g_object_unref (window); return return_val; }