/* * Wayland Support * * Copyright (C) 2012,2013 Intel Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include "config.h" #include "meta-wayland.h" #include #include #include #include #include #include #include #include "meta-wayland-private.h" #include "meta-xwayland-private.h" #include "meta-wayland-region.h" #include "meta-wayland-seat.h" #include "meta-wayland-outputs.h" #include "meta-wayland-data-device.h" static MetaWaylandCompositor _meta_wayland_compositor; MetaWaylandCompositor * meta_wayland_compositor_get_default (void) { return &_meta_wayland_compositor; } static guint32 get_time (void) { struct timeval tv; gettimeofday (&tv, NULL); return tv.tv_sec * 1000 + tv.tv_usec / 1000; } static gboolean wayland_event_source_prepare (GSource *base, int *timeout) { WaylandEventSource *source = (WaylandEventSource *)base; *timeout = -1; wl_display_flush_clients (source->display); return FALSE; } static gboolean wayland_event_source_check (GSource *base) { WaylandEventSource *source = (WaylandEventSource *)base; return source->pfd.revents; } static gboolean wayland_event_source_dispatch (GSource *base, GSourceFunc callback, void *data) { WaylandEventSource *source = (WaylandEventSource *)base; struct wl_event_loop *loop = wl_display_get_event_loop (source->display); wl_event_loop_dispatch (loop, 0); return TRUE; } static GSourceFuncs wayland_event_source_funcs = { wayland_event_source_prepare, wayland_event_source_check, wayland_event_source_dispatch, NULL }; static GSource * wayland_event_source_new (struct wl_display *display) { WaylandEventSource *source; struct wl_event_loop *loop = wl_display_get_event_loop (display); source = (WaylandEventSource *) g_source_new (&wayland_event_source_funcs, sizeof (WaylandEventSource)); source->display = display; source->pfd.fd = wl_event_loop_get_fd (loop); source->pfd.events = G_IO_IN | G_IO_ERR; g_source_add_poll (&source->source, &source->pfd); return &source->source; } void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor, MetaWindow *window) { MetaWaylandSurface *surface = window ? window->surface : NULL; meta_wayland_seat_set_input_focus (compositor->seat, surface); } void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor) { meta_wayland_seat_repick (compositor->seat); } static void wl_compositor_create_surface (struct wl_client *client, struct wl_resource *resource, guint32 id) { MetaWaylandCompositor *compositor = wl_resource_get_user_data (resource); meta_wayland_surface_create (compositor, client, resource, id); } static void wl_compositor_create_region (struct wl_client *client, struct wl_resource *resource, uint32_t id) { MetaWaylandCompositor *compositor = wl_resource_get_user_data (resource); meta_wayland_region_create (compositor, client, resource, id); } const static struct wl_compositor_interface meta_wayland_wl_compositor_interface = { wl_compositor_create_surface, wl_compositor_create_region }; static void compositor_bind (struct wl_client *client, void *data, guint32 version, guint32 id) { MetaWaylandCompositor *compositor = data; struct wl_resource *resource; resource = wl_resource_create (client, &wl_compositor_interface, version, id); wl_resource_set_implementation (resource, &meta_wayland_wl_compositor_interface, compositor, NULL); } /** * meta_wayland_compositor_update: * @compositor: the #MetaWaylandCompositor instance * @event: the #ClutterEvent used to update @seat's state * * This is used to update display server state like updating cursor * position and keeping track of buttons and keys pressed. It must be * called for all input events coming from the underlying devices. */ void meta_wayland_compositor_update (MetaWaylandCompositor *compositor, const ClutterEvent *event) { meta_wayland_seat_update (compositor->seat, event); } void meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor) { while (!wl_list_empty (&compositor->frame_callbacks)) { MetaWaylandFrameCallback *callback = wl_container_of (compositor->frame_callbacks.next, callback, link); wl_callback_send_done (callback->resource, get_time ()); wl_resource_destroy (callback->resource); } } /** * meta_wayland_compositor_handle_event: * @compositor: the #MetaWaylandCompositor instance * @event: the #ClutterEvent to be sent * * This method sends events to the focused wayland client, if any. * * Return value: whether @event was sent to a wayland client. */ gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor, const ClutterEvent *event) { return meta_wayland_seat_handle_event (compositor->seat, event); } static void set_gnome_env (const char *name, const char *value) { GDBusConnection *session_bus; GError *error = NULL; setenv (name, value, TRUE); session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); g_assert (session_bus); g_dbus_connection_call_sync (session_bus, "org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", "Setenv", g_variant_new ("(ss)", name, value), NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, NULL, &error); if (error) { if (g_strcmp0 (g_dbus_error_get_remote_error (error), "org.gnome.SessionManager.NotInInitialization") != 0) meta_warning ("Failed to set environment variable %s for gnome-session: %s\n", name, error->message); g_error_free (error); } } static void meta_wayland_log_func (const char *fmt, va_list arg) { char *str = g_strdup_vprintf (fmt, arg); g_warning ("WL: %s", str); g_free (str); } static void meta_wayland_compositor_init (MetaWaylandCompositor *compositor) { memset (compositor, 0, sizeof (MetaWaylandCompositor)); wl_list_init (&compositor->frame_callbacks); } void meta_wayland_pre_clutter_init (void) { MetaWaylandCompositor *compositor = &_meta_wayland_compositor; meta_wayland_compositor_init (compositor); /* Set up our logging. */ wl_log_set_handler_server (meta_wayland_log_func); compositor->wayland_display = wl_display_create (); if (compositor->wayland_display == NULL) g_error ("Failed to create the global wl_display"); clutter_wayland_set_compositor_display (compositor->wayland_display); } 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)); } const char * meta_wayland_get_wayland_display_name (MetaWaylandCompositor *compositor) { return compositor->display_name; } const char * meta_wayland_get_xwayland_display_name (MetaWaylandCompositor *compositor) { return compositor->xwayland_manager.display_name; } void meta_wayland_finalize (void) { MetaWaylandCompositor *compositor; compositor = meta_wayland_compositor_get_default (); meta_xwayland_stop (&compositor->xwayland_manager); }