static void * get_property (ClutterInputDevice *device, const gchar *property, Atom type, int format, gulong nitems) { MetaBackend *backend = meta_get_backend (); Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); gulong nitems_ret, bytes_after_ret; int rc, device_id, format_ret; Atom property_atom, type_ret; guchar *data_ret = NULL; property_atom = XInternAtom (xdisplay, property, False); device_id = clutter_input_device_get_device_id (device); rc = XIGetProperty (xdisplay, device_id, property_atom, 0, 10, False, type, &type_ret, &format_ret, &nitems_ret, &bytes_after_ret, &data_ret); if (rc == Success && type_ret == type && format_ret == format && nitems_ret >= nitems) { if (nitems_ret > nitems) g_warning ("Property '%s' for device '%s' returned %lu items, expected %lu", property, clutter_input_device_get_device_name (device), nitems_ret, nitems); return data_ret; } meta_XFree (data_ret); return NULL; }
static gboolean meta_backend_x11_grab_device (MetaBackend *backend, int device_id, uint32_t timestamp) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; int ret; if (timestamp != CurrentTime) timestamp = MAX (timestamp, priv->latest_evtime); XISetMask (mask.mask, XI_ButtonPress); XISetMask (mask.mask, XI_ButtonRelease); XISetMask (mask.mask, XI_Enter); XISetMask (mask.mask, XI_Leave); XISetMask (mask.mask, XI_Motion); XISetMask (mask.mask, XI_KeyPress); XISetMask (mask.mask, XI_KeyRelease); ret = XIGrabDevice (priv->xdisplay, device_id, meta_backend_x11_get_xwindow (x11), timestamp, None, XIGrabModeAsync, XIGrabModeAsync, False, /* owner_events */ &mask); return (ret == Success); }
static void change_property (ClutterInputDevice *device, const gchar *property, Atom type, int format, void *data, gulong nitems) { MetaBackend *backend = meta_get_backend (); Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); int device_id; Atom property_atom; guchar *data_ret; property_atom = XInternAtom (xdisplay, property, False); device_id = clutter_input_device_get_device_id (device); data_ret = get_property (device, property, type, format, nitems); if (!data_ret) return; XIChangeProperty (xdisplay, device_id, property_atom, type, format, XIPropModeReplace, data, nitems); meta_XFree (data_ret); }
static void meta_backend_x11_lock_layout_group (MetaBackend *backend, guint idx) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, idx); }
static void handle_host_xevent (MetaBackend *backend, XEvent *event) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); gboolean bypass_clutter = FALSE; XGetEventData (priv->xdisplay, &event->xcookie); { MetaDisplay *display = meta_get_display (); if (display) { MetaCompositor *compositor = display->compositor; if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event)) bypass_clutter = TRUE; } } if (event->type == (priv->xsync_event_base + XSyncAlarmNotify)) handle_alarm_notify (backend, event); if (event->type == priv->xkb_event_base) { XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event; if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID) { switch (xkb_ev->xkb_type) { case XkbNewKeyboardNotify: case XkbMapNotify: keymap_changed (backend); default: break; } } } { MetaMonitorManager *manager = meta_backend_get_monitor_manager (backend); if (META_IS_MONITOR_MANAGER_XRANDR (manager) && meta_monitor_manager_xrandr_handle_xevent (META_MONITOR_MANAGER_XRANDR (manager), event)) bypass_clutter = TRUE; } if (!bypass_clutter) { handle_input_event (x11, event); clutter_x11_handle_event (event); } XFreeEventData (priv->xdisplay, &event->xcookie); }
static gboolean x_event_source_check (GSource *source) { XEventSource *x_source = (XEventSource *) source; MetaBackend *backend = x_source->backend; MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); return XPending (priv->xdisplay); }
static void on_device_added (ClutterDeviceManager *device_manager, ClutterInputDevice *device, gpointer user_data) { MetaBackendX11 *x11 = META_BACKEND_X11 (user_data); if (clutter_input_device_get_device_type (device) == CLUTTER_KEYBOARD_DEVICE) apply_keymap (x11); }
static void meta_backend_x11_post_init (MetaBackend *backend) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); int major, minor; priv->xdisplay = clutter_x11_get_default_display (); priv->source = x_event_source_new (backend); if (!XSyncQueryExtension (priv->xdisplay, &priv->xsync_event_base, &priv->xsync_error_base) || !XSyncInitialize (priv->xdisplay, &major, &minor)) meta_fatal ("Could not initialize XSync"); { int major = 2, minor = 3; gboolean has_xi = FALSE; if (XQueryExtension (priv->xdisplay, "XInputExtension", &priv->xinput_opcode, &priv->xinput_error_base, &priv->xinput_event_base)) { if (XIQueryVersion (priv->xdisplay, &major, &minor) == Success) { int version = (major * 10) + minor; if (version >= 22) has_xi = TRUE; } } if (!has_xi) meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n"); } take_touch_grab (backend); priv->xcb = XGetXCBConnection (priv->xdisplay); if (!xkb_x11_setup_xkb_extension (priv->xcb, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION, XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, NULL, NULL, &priv->xkb_event_base, &priv->xkb_error_base)) meta_fatal ("X server doesn't have the XKB extension, version %d.%d or newer\n", XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION); g_signal_connect_object (clutter_device_manager_get_default (), "device-added", G_CALLBACK (on_device_added), backend, 0); META_BACKEND_CLASS (meta_backend_x11_parent_class)->post_init (backend); }
static void meta_input_settings_x11_set_speed (MetaInputSettings *settings, ClutterInputDevice *device, gdouble speed) { MetaBackend *backend = meta_get_backend (); Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); gfloat value = speed; change_property (device, "libinput Accel Speed", XInternAtom (xdisplay, "FLOAT", False), 32, &value, 1); }
static gboolean meta_backend_x11_ungrab_device (MetaBackend *backend, int device_id, uint32_t timestamp) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); int ret; ret = XIUngrabDevice (priv->xdisplay, device_id, timestamp); return (ret == Success); }
static void keymap_changed (MetaBackend *backend) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); if (priv->keymap) { xkb_keymap_unref (priv->keymap); priv->keymap = NULL; } g_signal_emit_by_name (backend, "keymap-changed", 0); }
static gboolean meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite) { MetaCursorRendererX11 *x11 = META_CURSOR_RENDERER_X11 (renderer); MetaCursorRendererX11Private *priv = meta_cursor_renderer_x11_get_instance_private (x11); MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ()); Window xwindow = meta_backend_x11_get_xwindow (backend); Display *xdisplay = meta_backend_x11_get_xdisplay (backend); if (xwindow == None) { if (cursor_sprite) meta_cursor_sprite_realize_texture (cursor_sprite); return FALSE; } gboolean has_server_cursor = FALSE; if (cursor_sprite) { MetaCursor cursor = meta_cursor_sprite_get_meta_cursor (cursor_sprite); if (cursor != META_CURSOR_NONE) { Cursor xcursor = meta_cursor_create_x_cursor (xdisplay, cursor); XDefineCursor (xdisplay, xwindow, xcursor); XFlush (xdisplay); XFreeCursor (xdisplay, xcursor); has_server_cursor = TRUE; } } if (has_server_cursor != priv->server_cursor_visible) { if (has_server_cursor) XFixesShowCursor (xdisplay, xwindow); else XFixesHideCursor (xdisplay, xwindow); priv->server_cursor_visible = has_server_cursor; } if (!priv->server_cursor_visible && cursor_sprite) meta_cursor_sprite_realize_texture (cursor_sprite); return priv->server_cursor_visible; }
static void meta_backend_x11_select_stage_events (MetaBackend *backend) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); Window xwin = meta_backend_x11_get_xwindow (x11); unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; XISetMask (mask.mask, XI_KeyPress); XISetMask (mask.mask, XI_KeyRelease); XISetMask (mask.mask, XI_ButtonPress); XISetMask (mask.mask, XI_ButtonRelease); XISetMask (mask.mask, XI_Enter); XISetMask (mask.mask, XI_Leave); XISetMask (mask.mask, XI_FocusIn); XISetMask (mask.mask, XI_FocusOut); XISetMask (mask.mask, XI_Motion); if (priv->mode == META_BACKEND_X11_MODE_NESTED) { /* When we're an X11 compositor, we can't take these events or else * replaying events from our passive root window grab will cause * them to come back to us. * * When we're a nested application, we want to behave like any other * application, so select these events like normal apps do. */ XISetMask (mask.mask, XI_TouchBegin); XISetMask (mask.mask, XI_TouchEnd); XISetMask (mask.mask, XI_TouchUpdate); } XISelectEvents (priv->xdisplay, xwin, &mask, 1); if (priv->mode == META_BACKEND_X11_MODE_NESTED) { /* We have no way of tracking key changes when the stage doesn't have * focus, so we select for KeymapStateMask so that we get a complete * dump of the keyboard state in a KeymapNotify event that immediately * follows each FocusIn (and EnterNotify, but we ignore that.) */ XWindowAttributes xwa; XGetWindowAttributes(priv->xdisplay, xwin, &xwa); XSelectInput(priv->xdisplay, xwin, xwa.your_event_mask | FocusChangeMask | KeymapStateMask); } }
static void meta_backend_x11_warp_pointer (MetaBackend *backend, int x, int y) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); XIWarpPointer (priv->xdisplay, META_VIRTUAL_CORE_POINTER_ID, None, meta_backend_x11_get_xwindow (x11), 0, 0, 0, 0, x, y); }
static void meta_input_settings_x11_set_matrix (MetaInputSettings *settings, ClutterInputDevice *device, gfloat matrix[6]) { MetaBackend *backend = meta_get_backend (); Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); gfloat full_matrix[9] = { matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], 0, 0, 1 }; change_property (device, "Coordinate Transformation Matrix", XInternAtom (xdisplay, "FLOAT", False), 32, &full_matrix, 9); }
static MetaMonitorManager * meta_backend_x11_create_monitor_manager (MetaBackend *backend) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); switch (priv->mode) { case META_BACKEND_X11_MODE_COMPOSITOR: return g_object_new (META_TYPE_MONITOR_MANAGER_XRANDR, NULL); case META_BACKEND_X11_MODE_NESTED: return g_object_new (META_TYPE_MONITOR_MANAGER_DUMMY, NULL); default: g_assert_not_reached (); } }
static void take_touch_grab (MetaBackend *backend) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; XIEventMask mask = { META_VIRTUAL_CORE_POINTER_ID, sizeof (mask_bits), mask_bits }; XIGrabModifiers mods = { XIAnyModifier, 0 }; XISetMask (mask.mask, XI_TouchBegin); XISetMask (mask.mask, XI_TouchUpdate); XISetMask (mask.mask, XI_TouchEnd); XIGrabTouchBegin (priv->xdisplay, META_VIRTUAL_CORE_POINTER_ID, DefaultRootWindow (priv->xdisplay), False, &mask, 1, &mods); }
static GSource * x_event_source_new (MetaBackend *backend) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); GSource *source; XEventSource *x_source; source = g_source_new (&x_event_funcs, sizeof (XEventSource)); x_source = (XEventSource *) source; x_source->backend = backend; x_source->event_poll_fd.fd = ConnectionNumber (priv->xdisplay); x_source->event_poll_fd.events = G_IO_IN; g_source_add_poll (source, &x_source->event_poll_fd); g_source_attach (source, NULL); return source; }
static void meta_backend_x11_set_keymap (MetaBackend *backend, const char *layouts, const char *variants, const char *options) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); g_free (priv->keymap_layouts); priv->keymap_layouts = g_strdup (layouts); g_free (priv->keymap_variants); priv->keymap_variants = g_strdup (variants); g_free (priv->keymap_options); priv->keymap_options = g_strdup (options); apply_keymap (x11); }
static struct xkb_keymap * meta_backend_x11_get_keymap (MetaBackend *backend) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); if (priv->keymap == NULL) { struct xkb_context *context = xkb_context_new (XKB_CONTEXT_NO_FLAGS); priv->keymap = xkb_x11_keymap_new_from_device (context, priv->xcb, xkb_x11_get_core_keyboard_device_id (priv->xcb), XKB_KEYMAP_COMPILE_NO_FLAGS); xkb_context_unref (context); } return priv->keymap; }
static MetaCursorRenderer * meta_backend_x11_create_cursor_renderer (MetaBackend *backend) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); switch (priv->mode) { case META_BACKEND_X11_MODE_COMPOSITOR: return g_object_new (META_TYPE_CURSOR_RENDERER_X11, NULL); break; case META_BACKEND_X11_MODE_NESTED: return g_object_new (META_TYPE_CURSOR_RENDERER_X11_NESTED, NULL); break; default: g_assert_not_reached (); } }
static void meta_backend_x11_update_screen_size (MetaBackend *backend, int width, int height) { if (meta_is_wayland_compositor ()) { /* For a nested wayland session, we want to go through Clutter to update the * toplevel window size, rather than doing it directly. */ META_BACKEND_CLASS (meta_backend_x11_parent_class)->update_screen_size (backend, width, height); } else { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); Window xwin = meta_backend_x11_get_xwindow (x11); XResizeWindow (priv->xdisplay, xwin, width, height); } }
static void meta_input_settings_x11_set_keyboard_repeat (MetaInputSettings *settings, gboolean enabled, guint delay, guint interval) { MetaBackend *backend = meta_get_backend (); Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); if (enabled) { XAutoRepeatOn (xdisplay); XkbSetAutoRepeatRate (xdisplay, XkbUseCoreKbd, delay, interval); } else { XAutoRepeatOff (xdisplay); } }
static gboolean x_event_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { XEventSource *x_source = (XEventSource *) source; MetaBackend *backend = x_source->backend; MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); while (XPending (priv->xdisplay)) { XEvent event; XNextEvent (priv->xdisplay, &event); handle_host_xevent (backend, &event); } return TRUE; }
static void meta_backend_x11_update_screen_size (MetaBackend *backend, int width, int height) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); if (priv->mode == META_BACKEND_X11_MODE_NESTED) { ClutterActor *stage = meta_backend_get_stage (backend); MetaRenderer *renderer = meta_backend_get_renderer (backend); if (meta_is_stage_views_enabled ()) meta_renderer_rebuild_views (renderer); clutter_actor_set_size (stage, width, height); } else { Window xwin = meta_backend_x11_get_xwindow (x11); XResizeWindow (priv->xdisplay, xwin, width, height); } }
static void meta_backend_x11_select_stage_events (MetaBackend *backend) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); Window xwin = meta_backend_x11_get_xwindow (x11); unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; XISetMask (mask.mask, XI_KeyPress); XISetMask (mask.mask, XI_KeyRelease); XISetMask (mask.mask, XI_ButtonPress); XISetMask (mask.mask, XI_ButtonRelease); XISetMask (mask.mask, XI_Enter); XISetMask (mask.mask, XI_Leave); XISetMask (mask.mask, XI_FocusIn); XISetMask (mask.mask, XI_FocusOut); XISetMask (mask.mask, XI_Motion); XIClearMask (mask.mask, XI_TouchBegin); XIClearMask (mask.mask, XI_TouchEnd); XIClearMask (mask.mask, XI_TouchUpdate); XISelectEvents (priv->xdisplay, xwin, &mask, 1); }
static gboolean meta_display_handle_event (MetaDisplay *display, const ClutterEvent *event) { MetaWindow *window; gboolean bypass_clutter = FALSE; G_GNUC_UNUSED gboolean bypass_wayland = FALSE; MetaGestureTracker *tracker; ClutterEventSequence *sequence; sequence = clutter_event_get_event_sequence (event); /* Set the pointer emulating sequence on touch begin, if eligible */ if (event->type == CLUTTER_TOUCH_BEGIN && !display->pointer_emulating_sequence && sequence_is_pointer_emulated (display, event)) display->pointer_emulating_sequence = sequence; #ifdef HAVE_WAYLAND MetaWaylandCompositor *compositor = NULL; if (meta_is_wayland_compositor ()) { compositor = meta_wayland_compositor_get_default (); meta_wayland_compositor_update (compositor, event); } #endif if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION) { MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (NULL); meta_cursor_tracker_update_position (tracker, event->motion.x, event->motion.y); } handle_idletime_for_event (event); window = get_window_for_event (display, event); display->current_time = event->any.time; if (window && !window->override_redirect && (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_BUTTON_PRESS || event->type == CLUTTER_TOUCH_BEGIN)) { if (CurrentTime == display->current_time) { /* We can't use missing (i.e. invalid) timestamps to set user time, * nor do we want to use them to sanity check other timestamps. * See bug 313490 for more details. */ meta_warning ("Event has no timestamp! You may be using a broken " "program such as xse. Please ask the authors of that " "program to fix it.\n"); } else { meta_window_set_user_time (window, display->current_time); meta_display_sanity_check_timestamps (display, display->current_time); } } tracker = meta_display_get_gesture_tracker (display); if (meta_gesture_tracker_handle_event (tracker, event)) { bypass_wayland = bypass_clutter = TRUE; goto out; } if (display->event_route == META_EVENT_ROUTE_WINDOW_OP) { if (meta_window_handle_mouse_grab_op_event (window, event)) { bypass_clutter = TRUE; bypass_wayland = TRUE; goto out; } } /* For key events, it's important to enforce single-handling, or * we can get into a confused state. So if a keybinding is * handled (because it's one of our hot-keys, or because we are * in a keyboard-grabbed mode like moving a window, we don't * want to pass the key event to the compositor or Wayland at all. */ if (meta_keybindings_process_event (display, window, event)) { bypass_clutter = TRUE; bypass_wayland = TRUE; goto out; } if (window) { if (!clutter_event_get_event_sequence (event)) { /* Swallow all non-touch events on windows that come our way. * Touch events that reach here aren't yet in an accepted state, * so Clutter must see them to maybe trigger gestures into * recognition. */ bypass_clutter = TRUE; } meta_window_handle_ungrabbed_event (window, event); /* This might start a grab op. If it does, then filter out the * event, and if it doesn't, replay the event to release our * own sync grab. */ if (display->event_route == META_EVENT_ROUTE_WINDOW_OP) { bypass_clutter = TRUE; bypass_wayland = TRUE; } else { /* Only replay button press events, since that's where we * have the synchronous grab. */ if (event->type == CLUTTER_BUTTON_PRESS) { MetaBackend *backend = meta_get_backend (); if (META_IS_BACKEND_X11 (backend)) { Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); meta_verbose ("Allowing events time %u\n", (unsigned int)event->button.time); XIAllowEvents (xdisplay, clutter_event_get_device_id (event), XIReplayDevice, event->button.time); } } } goto out; } out: /* If the compositor has a grab, don't pass that through to Wayland */ if (display->event_route == META_EVENT_ROUTE_COMPOSITOR_GRAB) bypass_wayland = TRUE; /* If a Wayland client has a grab, don't pass that through to Clutter */ if (display->event_route == META_EVENT_ROUTE_WAYLAND_POPUP) bypass_clutter = TRUE; #ifdef HAVE_WAYLAND if (compositor && !bypass_wayland) { if (meta_wayland_compositor_handle_event (compositor, event)) bypass_clutter = TRUE; } #endif /* Unset the pointer emulating sequence after its end event is processed */ if (event->type == CLUTTER_TOUCH_END && display->pointer_emulating_sequence == sequence) display->pointer_emulating_sequence = NULL; display->current_time = CurrentTime; return bypass_clutter; }
static gboolean meta_display_handle_event (MetaDisplay *display, const ClutterEvent *event) { MetaWindow *window; gboolean bypass_clutter = FALSE; G_GNUC_UNUSED gboolean bypass_wayland = FALSE; MetaGestureTracker *tracker; ClutterEventSequence *sequence; ClutterInputDevice *source; sequence = clutter_event_get_event_sequence (event); /* Set the pointer emulating sequence on touch begin, if eligible */ if (event->type == CLUTTER_TOUCH_BEGIN) { if (sequence_is_pointer_emulated (display, event)) { /* This is the new pointer emulating sequence */ display->pointer_emulating_sequence = sequence; } else if (display->pointer_emulating_sequence == sequence) { /* This sequence was "pointer emulating" in a prior incarnation, * but now it isn't. We unset the pointer emulating sequence at * this point so the current sequence is not mistaken as pointer * emulating, while we've ensured that it's been deemed * "pointer emulating" throughout all of the event processing * of the previous incarnation. */ display->pointer_emulating_sequence = NULL; } } #ifdef HAVE_WAYLAND MetaWaylandCompositor *compositor = NULL; if (meta_is_wayland_compositor ()) { compositor = meta_wayland_compositor_get_default (); meta_wayland_compositor_update (compositor, event); } #endif if (!display->current_pad_osd && (event->type == CLUTTER_PAD_BUTTON_PRESS || event->type == CLUTTER_PAD_BUTTON_RELEASE)) { MetaBackend *backend = meta_get_backend (); if (meta_input_settings_handle_pad_button (meta_backend_get_input_settings (backend), clutter_event_get_source_device (event), event->type == CLUTTER_PAD_BUTTON_PRESS, event->pad_button.button)) { bypass_wayland = bypass_clutter = TRUE; goto out; } } source = clutter_event_get_source_device (event); if (source) { meta_backend_update_last_device (meta_get_backend (), clutter_input_device_get_device_id (source)); } #ifdef HAVE_WAYLAND if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION) { MetaWaylandCompositor *compositor; compositor = meta_wayland_compositor_get_default (); if (meta_wayland_tablet_manager_consumes_event (compositor->tablet_manager, event)) { meta_wayland_tablet_manager_update_cursor_position (compositor->tablet_manager, event); } else { MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (NULL); meta_cursor_tracker_update_position (tracker, event->motion.x, event->motion.y); } display->monitor_cache_invalidated = TRUE; } #endif handle_idletime_for_event (event); window = get_window_for_event (display, event); display->current_time = event->any.time; if (window && !window->override_redirect && (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_BUTTON_PRESS || event->type == CLUTTER_TOUCH_BEGIN)) { if (CurrentTime == display->current_time) { /* We can't use missing (i.e. invalid) timestamps to set user time, * nor do we want to use them to sanity check other timestamps. * See bug 313490 for more details. */ meta_warning ("Event has no timestamp! You may be using a broken " "program such as xse. Please ask the authors of that " "program to fix it.\n"); } else { meta_window_set_user_time (window, display->current_time); meta_display_sanity_check_timestamps (display, display->current_time); } } tracker = meta_display_get_gesture_tracker (display); if (meta_gesture_tracker_handle_event (tracker, event)) { bypass_wayland = bypass_clutter = TRUE; goto out; } if (display->event_route == META_EVENT_ROUTE_WINDOW_OP) { if (meta_window_handle_mouse_grab_op_event (window, event)) { bypass_clutter = TRUE; bypass_wayland = TRUE; goto out; } } /* For key events, it's important to enforce single-handling, or * we can get into a confused state. So if a keybinding is * handled (because it's one of our hot-keys, or because we are * in a keyboard-grabbed mode like moving a window, we don't * want to pass the key event to the compositor or Wayland at all. */ if (meta_keybindings_process_event (display, window, event)) { bypass_clutter = TRUE; bypass_wayland = TRUE; goto out; } /* Do not pass keyboard events to Wayland if key focus is not on the * stage in normal mode (e.g. during keynav in the panel) */ if (display->event_route == META_EVENT_ROUTE_NORMAL) { if (IS_KEY_EVENT (event) && !stage_has_key_focus ()) { bypass_wayland = TRUE; goto out; } } if (display->current_pad_osd) { bypass_wayland = TRUE; goto out; } if (window) { /* Events that are likely to trigger compositor gestures should * be known to clutter so they can propagate along the hierarchy. * Gesture-wise, there's two groups of events we should be getting * here: * - CLUTTER_TOUCH_* with a touch sequence that's not yet accepted * by the gesture tracker, these might trigger gesture actions * into recognition. Already accepted touch sequences are handled * directly by meta_gesture_tracker_handle_event(). * - CLUTTER_TOUCHPAD_* events over windows. These can likewise * trigger ::captured-event handlers along the way. */ bypass_clutter = !IS_GESTURE_EVENT (event); meta_window_handle_ungrabbed_event (window, event); /* This might start a grab op. If it does, then filter out the * event, and if it doesn't, replay the event to release our * own sync grab. */ if (display->event_route == META_EVENT_ROUTE_WINDOW_OP || display->event_route == META_EVENT_ROUTE_FRAME_BUTTON) { bypass_clutter = TRUE; bypass_wayland = TRUE; } else { /* Only replay button press events, since that's where we * have the synchronous grab. */ if (event->type == CLUTTER_BUTTON_PRESS) { MetaBackend *backend = meta_get_backend (); if (META_IS_BACKEND_X11 (backend)) { Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); meta_verbose ("Allowing events time %u\n", (unsigned int)event->button.time); XIAllowEvents (xdisplay, clutter_event_get_device_id (event), XIReplayDevice, event->button.time); } } } goto out; } out: /* If the compositor has a grab, don't pass that through to Wayland */ if (display->event_route == META_EVENT_ROUTE_COMPOSITOR_GRAB) bypass_wayland = TRUE; /* If a Wayland client has a grab, don't pass that through to Clutter */ if (display->event_route == META_EVENT_ROUTE_WAYLAND_POPUP) bypass_clutter = TRUE; #ifdef HAVE_WAYLAND if (compositor && !bypass_wayland) { if (meta_wayland_compositor_handle_event (compositor, event)) bypass_clutter = TRUE; } #endif display->current_time = CurrentTime; return bypass_clutter; }
void meta_window_ensure_frame (MetaWindow *window) { MetaFrame *frame; XSetWindowAttributes attrs; gulong create_serial; if (window->frame) return; frame = g_new (MetaFrame, 1); frame->window = window; frame->xwindow = None; frame->rect = window->rect; frame->child_x = 0; frame->child_y = 0; frame->bottom_height = 0; frame->right_width = 0; frame->current_cursor = 0; frame->is_flashing = FALSE; frame->borders_cached = FALSE; meta_verbose ("Frame geometry %d,%d %dx%d\n", frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height); frame->ui_frame = meta_ui_create_frame (window->screen->ui, window->display->xdisplay, frame->window, window->xvisual, frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height, &create_serial); frame->xwindow = frame->ui_frame->xwindow; meta_stack_tracker_record_add (window->screen->stack_tracker, frame->xwindow, create_serial); meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow); attrs.event_mask = EVENT_MASK; XChangeWindowAttributes (window->display->xdisplay, frame->xwindow, CWEventMask, &attrs); meta_display_register_x_window (window->display, &frame->xwindow, window); meta_error_trap_push (window->display); if (window->mapped) { window->mapped = FALSE; /* the reparent will unmap the window, * we don't want to take that as a withdraw */ meta_topic (META_DEBUG_WINDOW_STATE, "Incrementing unmaps_pending on %s for reparent\n", window->desc); window->unmaps_pending += 1; } meta_stack_tracker_record_remove (window->screen->stack_tracker, window->xwindow, XNextRequest (window->display->xdisplay)); XReparentWindow (window->display->xdisplay, window->xwindow, frame->xwindow, frame->child_x, frame->child_y); /* FIXME handle this error */ meta_error_trap_pop (window->display); /* stick frame to the window */ window->frame = frame; /* Now that frame->xwindow is registered with window, we can set its * style and background. */ meta_frame_update_style (frame); meta_frame_update_title (frame); meta_ui_map_frame (frame->window->screen->ui, frame->xwindow); { MetaBackend *backend = meta_get_backend (); if (META_IS_BACKEND_X11 (backend)) { Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); /* Since the backend selects for events on another connection, * make sure to sync the GTK+ connection to ensure that the * frame window has been created on the server at this point. */ XSync (window->display->xdisplay, False); unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; XISelectEvents (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, &mask, 1); XISetMask (mask.mask, XI_ButtonPress); XISetMask (mask.mask, XI_ButtonRelease); XISetMask (mask.mask, XI_Motion); XISetMask (mask.mask, XI_Enter); XISetMask (mask.mask, XI_Leave); XISelectEvents (xdisplay, frame->xwindow, &mask, 1); } } /* Move keybindings to frame instead of window */ meta_window_grab_keys (window); }
static void handle_host_xevent (MetaBackend *backend, XEvent *event) { MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); gboolean bypass_clutter = FALSE; XGetEventData (priv->xdisplay, &event->xcookie); { MetaDisplay *display = meta_get_display (); if (display) { MetaCompositor *compositor = display->compositor; if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event)) bypass_clutter = TRUE; } } if (priv->mode == META_BACKEND_X11_MODE_NESTED && event->type == FocusIn) { #ifdef HAVE_WAYLAND Window xwin = meta_backend_x11_get_xwindow(x11); XEvent xev; if (event->xfocus.window == xwin) { /* Since we've selected for KeymapStateMask, every FocusIn is followed immediately * by a KeymapNotify event */ XMaskEvent(priv->xdisplay, KeymapStateMask, &xev); MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); meta_wayland_compositor_update_key_state (compositor, xev.xkeymap.key_vector, 32, 8); } #else g_assert_not_reached (); #endif } if (event->type == (priv->xsync_event_base + XSyncAlarmNotify)) handle_alarm_notify (backend, event); if (event->type == priv->xkb_event_base) { XkbEvent *xkb_ev = (XkbEvent *) event; if (xkb_ev->any.device == META_VIRTUAL_CORE_KEYBOARD_ID) { switch (xkb_ev->any.xkb_type) { case XkbNewKeyboardNotify: case XkbMapNotify: keymap_changed (backend); break; case XkbStateNotify: if (xkb_ev->state.changed & XkbGroupLockMask) { if (priv->locked_group != xkb_ev->state.locked_group) XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, priv->locked_group); } break; default: break; } } } { MetaMonitorManager *manager = meta_backend_get_monitor_manager (backend); if (META_IS_MONITOR_MANAGER_XRANDR (manager) && meta_monitor_manager_xrandr_handle_xevent (META_MONITOR_MANAGER_XRANDR (manager), event)) bypass_clutter = TRUE; } if (!bypass_clutter) { handle_input_event (x11, event); clutter_x11_handle_event (event); } XFreeEventData (priv->xdisplay, &event->xcookie); }