static gboolean meta_backend_x11_nested_handle_host_xevent (MetaBackendX11 *x11, XEvent *event) { #ifdef HAVE_WAYLAND if (event->type == FocusIn) { Window xwin = meta_backend_x11_get_xwindow (x11); XEvent xev; if (event->xfocus.window == xwin) { MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); Display *xdisplay = meta_backend_x11_get_xdisplay (x11); /* * Since we've selected for KeymapStateMask, every FocusIn is * followed immediately by a KeymapNotify event. */ XMaskEvent (xdisplay, KeymapStateMask, &xev); meta_wayland_compositor_update_key_state (compositor, xev.xkeymap.key_vector, 32, 8); } } #endif return FALSE; }
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 meta_backend_x11_nested_translate_device_event (MetaBackendX11 *x11, XIDeviceEvent *device_event) { /* This codepath should only ever trigger as an X11 compositor, * and never under nested, as under nested all backend events * should be reported with respect to the stage window. */ g_assert (device_event->event == meta_backend_x11_get_xwindow (x11)); }
static void translate_crossing_event (MetaBackendX11 *x11, XIEnterEvent *enter_event) { MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); /* Throw out weird events generated by grabs. */ if (enter_event->mode == XINotifyGrab || enter_event->mode == XINotifyUngrab) { enter_event->event = None; return; } Window stage_window = meta_backend_x11_get_xwindow (x11); if (enter_event->event != stage_window && priv->mode == META_BACKEND_X11_MODE_COMPOSITOR) { enter_event->event = meta_backend_x11_get_xwindow (x11); enter_event->event_x = enter_event->root_x; enter_event->event_y = enter_event->root_y; } }
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 translate_crossing_event (MetaBackendX11 *x11, XIEnterEvent *enter_event) { /* Throw out weird events generated by grabs. */ if (enter_event->mode == XINotifyGrab || enter_event->mode == XINotifyUngrab) { enter_event->event = None; return; } enter_event->event = meta_backend_x11_get_xwindow (x11); }
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_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_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 translate_device_event (MetaBackendX11 *x11, XIDeviceEvent *device_event) { MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); Window stage_window = meta_backend_x11_get_xwindow (x11); if (device_event->event != stage_window) { /* This codepath should only ever trigger as an X11 compositor, * and never under nested, as under nested all backend events * should be reported with respect to the stage window. */ g_assert (priv->mode == META_BACKEND_X11_MODE_COMPOSITOR); device_event->event = stage_window; /* As an X11 compositor, the stage window is always at 0,0, so * using root coordinates will give us correct stage coordinates * as well... */ device_event->event_x = device_event->root_x; device_event->event_y = device_event->root_y; } if (!device_event->send_event && device_event->time != CurrentTime) { if (device_event->time < priv->latest_evtime) { /* Emulated pointer events received after XIRejectTouch is received * on a passive touch grab will contain older timestamps, update those * so we dont get InvalidTime at grabs. */ device_event->time = priv->latest_evtime; } /* Update the internal latest evtime, for any possible later use */ priv->latest_evtime = device_event->time; } }
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 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); }
void meta_compositor_manage (MetaCompositor *compositor) { MetaDisplay *display = compositor->display; Display *xdisplay = display->xdisplay; MetaScreen *screen = display->screen; MetaBackend *backend = meta_get_backend (); meta_screen_set_cm_selection (display->screen); compositor->stage = meta_backend_get_stage (backend); /* We use connect_after() here to accomodate code in GNOME Shell that, * when benchmarking drawing performance, connects to ::after-paint * and calls glFinish(). The timing information from that will be * more accurate if we hold off until that completes before we signal * apps to begin drawing the next frame. If there are no other * connections to ::after-paint, connect() vs. connect_after() doesn't * matter. */ g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "after-paint", G_CALLBACK (after_stage_paint), compositor); clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY); compositor->window_group = meta_window_group_new (screen); compositor->top_window_group = meta_window_group_new (screen); compositor->feedback_group = meta_window_group_new (screen); clutter_actor_add_child (compositor->stage, compositor->window_group); clutter_actor_add_child (compositor->stage, compositor->top_window_group); clutter_actor_add_child (compositor->stage, compositor->feedback_group); if (meta_is_wayland_compositor ()) { /* NB: When running as a wayland compositor we don't need an X * composite overlay window, and we don't need to play any input * region tricks to redirect events into clutter. */ compositor->output = None; } else { Window xwin; compositor->output = screen->composite_overlay_window; xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend)); XReparentWindow (xdisplay, xwin, compositor->output, 0, 0); meta_empty_stage_input_region (screen); /* Make sure there isn't any left-over output shape on the * overlay window by setting the whole screen to be an * output region. * * Note: there doesn't seem to be any real chance of that * because the X server will destroy the overlay window * when the last client using it exits. */ XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None); /* Map overlay window before redirecting windows offscreen so we catch their * contents until we show the stage. */ XMapWindow (xdisplay, compositor->output); compositor->have_x11_sync_object = meta_sync_ring_init (xdisplay); } redirect_windows (display->screen); compositor->plugin_mgr = meta_plugin_manager_new (compositor); }