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; }
void meta_xwayland_handle_wl_surface_id (MetaWindow *window, guint32 surface_id) { MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); MetaXWaylandManager *manager = &compositor->xwayland_manager; if (!associate_window_with_surface_id (manager, window, surface_id)) { /* No surface ID yet... it should arrive after the next * iteration through the loop, so queue a later and see * what happens. */ AssociateWindowWithSurfaceOp *op = g_new0 (AssociateWindowWithSurfaceOp, 1); op->manager = manager; op->window = window; op->surface_id = surface_id; op->later_id = meta_later_add (META_LATER_BEFORE_REDRAW, associate_window_with_surface_later, op, NULL); g_signal_connect (op->window, "unmanaged", G_CALLBACK (associate_window_with_surface_window_unmanaged), op); } }
void meta_wayland_finalize (void) { MetaWaylandCompositor *compositor; compositor = meta_wayland_compositor_get_default (); meta_xwayland_stop (&compositor->xwayland_manager); }
void meta_wayland_init (void) { MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); GSource *wayland_event_source; if (!wl_global_create (compositor->wayland_display, &wl_compositor_interface, META_WL_COMPOSITOR_VERSION, compositor, compositor_bind)) g_error ("Failed to register the global wl_compositor"); wayland_event_source = wayland_event_source_new (compositor->wayland_display); /* XXX: Here we are setting the wayland event source to have a * slightly lower priority than the X event source, because we are * much more likely to get confused being told about surface changes * relating to X clients when we don't know what's happened to them * according to the X protocol. * * At some point we could perhaps try and get the X protocol proxied * over the wayland protocol so that we don't have to worry about * synchronizing the two command streams. */ g_source_set_priority (wayland_event_source, GDK_PRIORITY_EVENTS + 1); g_source_attach (wayland_event_source, NULL); wl_display_init_shm (compositor->wayland_display); meta_wayland_outputs_init (compositor); meta_wayland_data_device_manager_init (compositor); meta_wayland_shell_init (compositor); meta_wayland_seat_init (compositor); /* FIXME: find the first free name instead */ compositor->display_name = wl_display_add_socket_auto (compositor->wayland_display); if (compositor->display_name == NULL) g_error ("Failed to create socket"); /* XXX: It's important that we only try and start xwayland after we * have initialized EGL because EGL implements the "wl_drm" * interface which xwayland requires to determine what drm device * name it should use. * * By waiting until we've shown the stage above we ensure that the * underlying GL resources for the surface have also been allocated * and so EGL must be initialized by this point. */ if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display)) g_error ("Failed to start X Wayland"); set_gnome_env ("DISPLAY", meta_wayland_get_xwayland_display_name (compositor)); set_gnome_env ("WAYLAND_DISPLAY", meta_wayland_get_wayland_display_name (compositor)); }
static void after_stage_paint (ClutterStage *stage, gpointer data) { MetaCompositor *compositor = data; GList *l; for (l = compositor->windows; l; l = l->next) meta_window_actor_post_paint (l->data); if (meta_is_wayland_compositor ()) meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ()); }
static TestClient * test_client_new (const char *id, MetaWindowClientType type, GError **error) { TestClient *client = g_new0 (TestClient, 1); GSubprocessLauncher *launcher; GSubprocess *subprocess; launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE); g_assert (meta_is_wayland_compositor ()); MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); g_subprocess_launcher_setenv (launcher, "WAYLAND_DISPLAY", meta_wayland_get_wayland_display_name (compositor), TRUE); g_subprocess_launcher_setenv (launcher, "DISPLAY", meta_wayland_get_xwayland_display_name (compositor), TRUE); subprocess = g_subprocess_launcher_spawn (launcher, error, test_client_path, "--client-id", id, type == META_WINDOW_CLIENT_TYPE_WAYLAND ? "--wayland" : NULL, NULL); g_object_unref (launcher); if (!subprocess) return NULL; client->type = type; client->id = g_strdup (id); client->cancellable = g_cancellable_new (); client->subprocess = subprocess; client->in = g_data_output_stream_new (g_subprocess_get_stdin_pipe (subprocess)); client->out = g_data_input_stream_new (g_subprocess_get_stdout_pipe (subprocess)); client->loop = g_main_loop_new (NULL, FALSE); if (client->type == META_WINDOW_CLIENT_TYPE_X11) client->waiter = async_waiter_new (); return client; }
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); }
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; }
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; }
void meta_compositor_manage (MetaCompositor *compositor) { MetaDisplay *display = compositor->display; Display *xdisplay = display->xdisplay; MetaScreen *screen = display->screen; Window xwin = 0; gint width, height; meta_screen_set_cm_selection (display->screen); if (meta_is_wayland_compositor ()) { MetaWaylandCompositor *wayland_compositor = meta_wayland_compositor_get_default (); compositor->stage = meta_stage_new (); wayland_compositor->stage = compositor->stage; meta_screen_get_size (screen, &width, &height); clutter_actor_set_size (compositor->stage, width, height); clutter_actor_show (compositor->stage); } else { compositor->stage = clutter_stage_new (); meta_screen_get_size (screen, &width, &height); clutter_actor_realize (compositor->stage); xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); XResizeWindow (xdisplay, xwin, width, height); { MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ()); Display *backend_xdisplay = meta_backend_x11_get_xdisplay (backend); 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 (backend_xdisplay, xwin, &mask, 1); } } /* 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); clutter_actor_add_child (compositor->stage, compositor->window_group); clutter_actor_add_child (compositor->stage, compositor->top_window_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 { compositor->output = screen->composite_overlay_window; 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); } redirect_windows (display->screen); compositor->plugin_mgr = meta_plugin_manager_new (compositor); }