2012-01-07 17:21:32 -05:00
|
|
|
/*
|
|
|
|
* 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 <clutter/clutter.h>
|
|
|
|
#include <clutter/wayland/clutter-wayland-compositor.h>
|
|
|
|
#include <clutter/wayland/clutter-wayland-surface.h>
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/wait.h>
|
2013-08-09 11:56:24 -04:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
#include <wayland-server.h>
|
|
|
|
|
|
|
|
#include "meta-wayland-private.h"
|
|
|
|
#include "meta-xwayland-private.h"
|
2012-01-18 18:03:23 -05:00
|
|
|
#include "meta-wayland-stage.h"
|
2012-01-07 17:21:32 -05:00
|
|
|
#include "meta-window-actor-private.h"
|
2013-05-03 13:51:22 -04:00
|
|
|
#include "meta-wayland-seat.h"
|
|
|
|
#include "meta-wayland-keyboard.h"
|
2013-06-15 20:49:03 -04:00
|
|
|
#include "meta-wayland-pointer.h"
|
2013-05-03 13:51:22 -04:00
|
|
|
#include "meta-wayland-data-device.h"
|
2013-08-13 06:57:41 -04:00
|
|
|
#include "meta-cursor-tracker-private.h"
|
2012-01-07 17:21:32 -05:00
|
|
|
#include "display-private.h"
|
|
|
|
#include "window-private.h"
|
|
|
|
#include <meta/types.h>
|
|
|
|
#include <meta/main.h>
|
|
|
|
#include "frame.h"
|
2013-08-19 08:57:16 -04:00
|
|
|
#include "meta-weston-launch.h"
|
2014-03-31 22:04:10 -04:00
|
|
|
#include "meta-monitor-manager.h"
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_buffer_destroy_handler (struct wl_listener *listener,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
MetaWaylandBuffer *buffer =
|
|
|
|
wl_container_of (listener, buffer, destroy_listener);
|
|
|
|
|
|
|
|
wl_signal_emit (&buffer->destroy_signal, buffer);
|
|
|
|
g_slice_free (MetaWaylandBuffer, buffer);
|
|
|
|
}
|
|
|
|
|
2014-02-01 17:45:51 -05:00
|
|
|
void
|
|
|
|
meta_wayland_buffer_ref (MetaWaylandBuffer *buffer)
|
|
|
|
{
|
|
|
|
buffer->ref_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_buffer_unref (MetaWaylandBuffer *buffer)
|
|
|
|
{
|
|
|
|
buffer->ref_count--;
|
|
|
|
if (buffer->ref_count == 0)
|
|
|
|
{
|
|
|
|
g_clear_pointer (&buffer->texture, cogl_object_unref);
|
|
|
|
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-30 12:26:18 -04:00
|
|
|
MetaWaylandBuffer *
|
2012-01-07 17:21:32 -05:00
|
|
|
meta_wayland_buffer_from_resource (struct wl_resource *resource)
|
|
|
|
{
|
|
|
|
MetaWaylandBuffer *buffer;
|
|
|
|
struct wl_listener *listener;
|
|
|
|
|
|
|
|
listener =
|
|
|
|
wl_resource_get_destroy_listener (resource,
|
|
|
|
meta_wayland_buffer_destroy_handler);
|
|
|
|
|
|
|
|
if (listener)
|
|
|
|
{
|
|
|
|
buffer = wl_container_of (listener, buffer, destroy_listener);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
buffer = g_slice_new0 (MetaWaylandBuffer);
|
|
|
|
|
|
|
|
buffer->resource = resource;
|
|
|
|
wl_signal_init (&buffer->destroy_signal);
|
|
|
|
buffer->destroy_listener.notify = meta_wayland_buffer_destroy_handler;
|
|
|
|
wl_resource_add_destroy_listener (resource, &buffer->destroy_listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2013-05-03 13:51:22 -04:00
|
|
|
void
|
|
|
|
meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = window ? window->surface : NULL;
|
|
|
|
|
|
|
|
meta_wayland_keyboard_set_focus (&compositor->seat->keyboard,
|
|
|
|
surface);
|
|
|
|
meta_wayland_data_device_set_keyboard_focus (compositor->seat);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_compositor_repick (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
2013-09-11 08:06:05 -04:00
|
|
|
meta_wayland_seat_repick (compositor->seat, NULL);
|
2013-05-03 13:51:22 -04:00
|
|
|
}
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
static void
|
|
|
|
meta_wayland_compositor_create_surface (struct wl_client *wayland_client,
|
|
|
|
struct wl_resource *wayland_compositor_resource,
|
|
|
|
guint32 id)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor =
|
|
|
|
wl_resource_get_user_data (wayland_compositor_resource);
|
2013-08-30 12:26:18 -04:00
|
|
|
MetaWaylandSurface *surface;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-08-30 12:26:18 -04:00
|
|
|
surface = meta_wayland_surface_create (compositor,
|
2013-09-10 07:45:27 -04:00
|
|
|
wayland_client, id,
|
|
|
|
MIN (META_WL_SURFACE_VERSION,
|
|
|
|
wl_resource_get_version (wayland_compositor_resource)));
|
2013-08-30 12:26:18 -04:00
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
compositor->surfaces = g_list_prepend (compositor->surfaces, surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_region_destroy (struct wl_client *client,
|
|
|
|
struct wl_resource *resource)
|
|
|
|
{
|
|
|
|
wl_resource_destroy (resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_region_add (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
gint32 x,
|
|
|
|
gint32 y,
|
|
|
|
gint32 width,
|
|
|
|
gint32 height)
|
|
|
|
{
|
|
|
|
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
|
|
|
|
cairo_rectangle_int_t rectangle = { x, y, width, height };
|
|
|
|
|
|
|
|
cairo_region_union_rectangle (region->region, &rectangle);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_region_subtract (struct wl_client *client,
|
|
|
|
struct wl_resource *resource,
|
|
|
|
gint32 x,
|
|
|
|
gint32 y,
|
|
|
|
gint32 width,
|
|
|
|
gint32 height)
|
|
|
|
{
|
|
|
|
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
|
|
|
|
cairo_rectangle_int_t rectangle = { x, y, width, height };
|
|
|
|
|
|
|
|
cairo_region_subtract_rectangle (region->region, &rectangle);
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct wl_region_interface meta_wayland_region_interface = {
|
|
|
|
meta_wayland_region_destroy,
|
|
|
|
meta_wayland_region_add,
|
|
|
|
meta_wayland_region_subtract
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_region_resource_destroy_cb (struct wl_resource *resource)
|
|
|
|
{
|
|
|
|
MetaWaylandRegion *region = wl_resource_get_user_data (resource);
|
|
|
|
|
|
|
|
cairo_region_destroy (region->region);
|
|
|
|
g_slice_free (MetaWaylandRegion, region);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_compositor_create_region (struct wl_client *wayland_client,
|
|
|
|
struct wl_resource *compositor_resource,
|
|
|
|
uint32_t id)
|
|
|
|
{
|
|
|
|
MetaWaylandRegion *region = g_slice_new0 (MetaWaylandRegion);
|
|
|
|
|
|
|
|
region->resource = wl_resource_create (wayland_client,
|
2013-09-10 07:13:34 -04:00
|
|
|
&wl_region_interface,
|
2013-09-10 07:45:27 -04:00
|
|
|
MIN (META_WL_REGION_VERSION,
|
|
|
|
wl_resource_get_version (compositor_resource)),
|
2012-01-07 17:21:32 -05:00
|
|
|
id);
|
|
|
|
wl_resource_set_implementation (region->resource,
|
|
|
|
&meta_wayland_region_interface, region,
|
|
|
|
meta_wayland_region_resource_destroy_cb);
|
|
|
|
|
|
|
|
region->region = cairo_region_create ();
|
|
|
|
}
|
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
typedef struct {
|
|
|
|
MetaOutput *output;
|
|
|
|
struct wl_global *global;
|
|
|
|
int x, y;
|
|
|
|
enum wl_output_transform transform;
|
|
|
|
|
|
|
|
GList *resources;
|
|
|
|
} MetaWaylandOutput;
|
|
|
|
|
|
|
|
static void
|
|
|
|
output_resource_destroy (struct wl_resource *res)
|
|
|
|
{
|
|
|
|
MetaWaylandOutput *wayland_output;
|
|
|
|
|
|
|
|
wayland_output = wl_resource_get_user_data (res);
|
|
|
|
wayland_output->resources = g_list_remove (wayland_output->resources, res);
|
|
|
|
}
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
static void
|
|
|
|
bind_output (struct wl_client *client,
|
|
|
|
void *data,
|
|
|
|
guint32 version,
|
|
|
|
guint32 id)
|
|
|
|
{
|
2013-08-19 05:12:42 -04:00
|
|
|
MetaWaylandOutput *wayland_output = data;
|
|
|
|
MetaOutput *output = wayland_output->output;
|
|
|
|
struct wl_resource *resource;
|
|
|
|
guint mode_flags;
|
|
|
|
|
2013-09-10 07:45:27 -04:00
|
|
|
resource = wl_resource_create (client, &wl_output_interface,
|
|
|
|
MIN (META_WL_OUTPUT_VERSION, version), id);
|
2013-08-19 05:12:42 -04:00
|
|
|
wayland_output->resources = g_list_prepend (wayland_output->resources, resource);
|
|
|
|
|
|
|
|
wl_resource_set_user_data (resource, wayland_output);
|
|
|
|
wl_resource_set_destructor (resource, output_resource_destroy);
|
|
|
|
|
|
|
|
meta_verbose ("Binding output %p/%s (%u, %u, %u, %u) x %f\n",
|
|
|
|
output, output->name,
|
|
|
|
output->crtc->rect.x, output->crtc->rect.y,
|
|
|
|
output->crtc->rect.width, output->crtc->rect.height,
|
|
|
|
output->crtc->current_mode->refresh_rate);
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
wl_resource_post_event (resource,
|
|
|
|
WL_OUTPUT_GEOMETRY,
|
2013-08-19 05:12:42 -04:00
|
|
|
(int)output->crtc->rect.x,
|
|
|
|
(int)output->crtc->rect.y,
|
2012-01-07 17:21:32 -05:00
|
|
|
output->width_mm,
|
|
|
|
output->height_mm,
|
2013-08-19 05:12:42 -04:00
|
|
|
/* Cogl values reflect XRandR values,
|
|
|
|
and so does wayland */
|
|
|
|
output->subpixel_order,
|
|
|
|
output->vendor,
|
|
|
|
output->product,
|
|
|
|
output->crtc->transform);
|
|
|
|
|
|
|
|
g_assert (output->crtc->current_mode != NULL);
|
|
|
|
|
|
|
|
mode_flags = WL_OUTPUT_MODE_CURRENT;
|
|
|
|
if (output->crtc->current_mode == output->preferred_mode)
|
|
|
|
mode_flags |= WL_OUTPUT_MODE_PREFERRED;
|
|
|
|
|
|
|
|
wl_resource_post_event (resource,
|
|
|
|
WL_OUTPUT_MODE,
|
|
|
|
mode_flags,
|
|
|
|
(int)output->crtc->current_mode->width,
|
|
|
|
(int)output->crtc->current_mode->height,
|
|
|
|
(int)output->crtc->current_mode->refresh_rate);
|
|
|
|
|
2013-09-10 07:45:27 -04:00
|
|
|
if (version >= META_WL_OUTPUT_HAS_DONE)
|
2013-08-19 05:12:42 -04:00
|
|
|
wl_resource_post_event (resource,
|
|
|
|
WL_OUTPUT_DONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wayland_output_destroy_notify (gpointer data)
|
|
|
|
{
|
|
|
|
MetaWaylandOutput *wayland_output = data;
|
|
|
|
GList *resources;
|
|
|
|
|
|
|
|
/* Make sure the destructors don't mess with the list */
|
|
|
|
resources = wayland_output->resources;
|
|
|
|
wayland_output->resources = NULL;
|
|
|
|
|
|
|
|
wl_global_destroy (wayland_output->global);
|
|
|
|
g_list_free (resources);
|
|
|
|
|
|
|
|
g_slice_free (MetaWaylandOutput, wayland_output);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wayland_output_update_for_output (MetaWaylandOutput *wayland_output,
|
|
|
|
MetaOutput *output)
|
|
|
|
{
|
|
|
|
GList *iter;
|
|
|
|
guint mode_flags;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
g_assert (output->crtc->current_mode != NULL);
|
|
|
|
|
|
|
|
mode_flags = WL_OUTPUT_MODE_CURRENT;
|
|
|
|
if (output->crtc->current_mode == output->preferred_mode)
|
|
|
|
mode_flags |= WL_OUTPUT_MODE_PREFERRED;
|
|
|
|
|
|
|
|
for (iter = wayland_output->resources; iter; iter = iter->next)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
2013-08-19 05:12:42 -04:00
|
|
|
struct wl_resource *resource = iter->data;
|
|
|
|
|
|
|
|
if (wayland_output->x != output->crtc->rect.x ||
|
|
|
|
wayland_output->y != output->crtc->rect.y ||
|
|
|
|
wayland_output->transform != output->crtc->transform)
|
|
|
|
{
|
|
|
|
wl_resource_post_event (resource,
|
|
|
|
WL_OUTPUT_GEOMETRY,
|
|
|
|
(int)output->crtc->rect.x,
|
|
|
|
(int)output->crtc->rect.y,
|
|
|
|
output->width_mm,
|
|
|
|
output->height_mm,
|
|
|
|
output->subpixel_order,
|
|
|
|
output->vendor,
|
|
|
|
output->product,
|
|
|
|
output->crtc->transform);
|
|
|
|
}
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
wl_resource_post_event (resource,
|
|
|
|
WL_OUTPUT_MODE,
|
2013-08-19 05:12:42 -04:00
|
|
|
mode_flags,
|
|
|
|
(int)output->crtc->current_mode->width,
|
|
|
|
(int)output->crtc->current_mode->height,
|
|
|
|
(int)output->crtc->current_mode->refresh_rate);
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
2013-08-19 05:12:42 -04:00
|
|
|
|
|
|
|
/* It's very important that we change the output pointer here, as
|
|
|
|
the old structure is about to be freed by MetaMonitorManager */
|
|
|
|
wayland_output->output = output;
|
|
|
|
wayland_output->x = output->crtc->rect.x;
|
|
|
|
wayland_output->y = output->crtc->rect.y;
|
|
|
|
wayland_output->transform = output->crtc->transform;
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
static GHashTable *
|
|
|
|
meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor,
|
|
|
|
MetaMonitorManager *monitors)
|
|
|
|
{
|
|
|
|
MetaOutput *outputs;
|
|
|
|
unsigned int i, n_outputs;
|
|
|
|
GHashTable *new_table;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
outputs = meta_monitor_manager_get_outputs (monitors, &n_outputs);
|
|
|
|
new_table = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify);
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
for (i = 0; i < n_outputs; i++)
|
|
|
|
{
|
|
|
|
MetaOutput *output = &outputs[i];
|
|
|
|
MetaWaylandOutput *wayland_output;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
/* wayland does not expose disabled outputs */
|
|
|
|
if (output->crtc == NULL)
|
|
|
|
{
|
|
|
|
g_hash_table_remove (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
|
|
|
|
continue;
|
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
wayland_output = g_hash_table_lookup (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
if (wayland_output)
|
|
|
|
{
|
|
|
|
g_hash_table_steal (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wayland_output = g_slice_new0 (MetaWaylandOutput);
|
|
|
|
wayland_output->global = wl_global_create (compositor->wayland_display,
|
2013-09-10 07:45:27 -04:00
|
|
|
&wl_output_interface,
|
|
|
|
META_WL_OUTPUT_VERSION,
|
2013-08-19 05:12:42 -04:00
|
|
|
wayland_output, bind_output);
|
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
wayland_output_update_for_output (wayland_output, output);
|
|
|
|
g_hash_table_insert (new_table, GSIZE_TO_POINTER (output->output_id), wayland_output);
|
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
g_hash_table_destroy (compositor->outputs);
|
|
|
|
return new_table;
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const static struct wl_compositor_interface meta_wayland_compositor_interface = {
|
|
|
|
meta_wayland_compositor_create_surface,
|
|
|
|
meta_wayland_compositor_create_region
|
|
|
|
};
|
|
|
|
|
2013-12-03 14:43:53 -05:00
|
|
|
void
|
|
|
|
meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
|
|
|
while (!wl_list_empty (&compositor->frame_callbacks))
|
|
|
|
{
|
|
|
|
MetaWaylandFrameCallback *callback =
|
|
|
|
wl_container_of (compositor->frame_callbacks.next, callback, link);
|
|
|
|
|
2014-01-31 15:49:27 -05:00
|
|
|
wl_callback_send_done (callback->resource, get_time ());
|
2012-01-07 17:21:32 -05:00
|
|
|
wl_resource_destroy (callback->resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
compositor_bind (struct wl_client *client,
|
|
|
|
void *data,
|
|
|
|
guint32 version,
|
|
|
|
guint32 id)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = data;
|
|
|
|
struct wl_resource *resource;
|
|
|
|
|
2013-09-10 07:45:27 -04:00
|
|
|
resource = wl_resource_create (client, &wl_compositor_interface,
|
|
|
|
MIN (META_WL_COMPOSITOR_VERSION, version), id);
|
2012-01-07 17:21:32 -05:00
|
|
|
wl_resource_set_implementation (resource, &meta_wayland_compositor_interface, compositor, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
stage_destroy_cb (void)
|
|
|
|
{
|
|
|
|
meta_quit (META_EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2014-03-18 13:00:48 -04:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2013-11-13 15:41:29 -05:00
|
|
|
void
|
|
|
|
meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
|
|
|
|
const ClutterEvent *event)
|
2013-08-23 09:07:57 -04:00
|
|
|
{
|
2014-03-18 13:00:48 -04:00
|
|
|
meta_wayland_seat_update (compositor->seat, event);
|
2013-08-23 09:07:57 -04:00
|
|
|
}
|
|
|
|
|
2014-03-18 13:00:48 -04:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2013-10-04 02:29:43 -04:00
|
|
|
gboolean
|
|
|
|
meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
|
|
|
|
const ClutterEvent *event)
|
2013-05-03 13:51:22 -04:00
|
|
|
{
|
2013-10-04 02:33:10 -04:00
|
|
|
return meta_wayland_seat_handle_event (compositor->seat, event);
|
2013-05-03 13:51:22 -04:00
|
|
|
}
|
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
static void
|
|
|
|
on_monitors_changed (MetaMonitorManager *monitors,
|
|
|
|
MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
|
|
|
|
}
|
|
|
|
|
2013-08-20 12:03:26 -04:00
|
|
|
static void
|
|
|
|
set_gnome_env (const char *name,
|
|
|
|
const char *value)
|
|
|
|
{
|
|
|
|
GDBusConnection *session_bus;
|
2014-03-26 12:02:08 -04:00
|
|
|
GError *error = NULL;
|
2013-08-20 12:03:26 -04:00
|
|
|
|
|
|
|
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_NONE,
|
|
|
|
-1, NULL, &error);
|
|
|
|
if (error)
|
|
|
|
{
|
2014-03-26 12:02:08 -04:00
|
|
|
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);
|
2013-08-20 12:03:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-19 20:04:49 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
void
|
|
|
|
meta_wayland_init (void)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
|
2013-08-19 05:12:42 -04:00
|
|
|
MetaMonitorManager *monitors;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
memset (compositor, 0, sizeof (MetaWaylandCompositor));
|
|
|
|
|
|
|
|
compositor->wayland_display = wl_display_create ();
|
|
|
|
if (compositor->wayland_display == NULL)
|
|
|
|
g_error ("failed to create wayland display");
|
|
|
|
|
|
|
|
wl_display_init_shm (compositor->wayland_display);
|
2013-11-19 20:04:49 -05:00
|
|
|
wl_log_set_handler_server(meta_wayland_log_func);
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
wl_list_init (&compositor->frame_callbacks);
|
|
|
|
|
|
|
|
if (!wl_global_create (compositor->wayland_display,
|
2013-09-10 07:45:27 -04:00
|
|
|
&wl_compositor_interface,
|
|
|
|
META_WL_COMPOSITOR_VERSION,
|
2012-01-07 17:21:32 -05:00
|
|
|
compositor, compositor_bind))
|
|
|
|
g_error ("Failed to register wayland compositor object");
|
|
|
|
|
|
|
|
compositor->wayland_loop =
|
|
|
|
wl_display_get_event_loop (compositor->wayland_display);
|
|
|
|
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 (compositor->wayland_event_source,
|
|
|
|
GDK_PRIORITY_EVENTS + 1);
|
|
|
|
g_source_attach (compositor->wayland_event_source, NULL);
|
|
|
|
|
|
|
|
clutter_wayland_set_compositor_display (compositor->wayland_display);
|
|
|
|
|
2014-03-11 17:25:02 -04:00
|
|
|
/* If we're running on bare metal, we're a display server,
|
|
|
|
* so start talking to weston-launch. */
|
2014-02-17 21:23:27 -05:00
|
|
|
#if defined(CLUTTER_WINDOWING_EGL)
|
|
|
|
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
|
2014-01-31 18:51:28 -05:00
|
|
|
compositor->launcher = meta_launcher_new ();
|
2014-02-17 21:23:27 -05:00
|
|
|
#endif
|
2013-08-19 08:57:16 -04:00
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
|
|
|
|
g_error ("Failed to initialize Clutter");
|
|
|
|
|
2013-08-19 05:12:42 -04:00
|
|
|
meta_monitor_manager_initialize ();
|
|
|
|
monitors = meta_monitor_manager_get ();
|
|
|
|
g_signal_connect (monitors, "monitors-changed",
|
|
|
|
G_CALLBACK (on_monitors_changed), compositor);
|
|
|
|
|
|
|
|
compositor->outputs = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify);
|
|
|
|
compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
|
|
|
|
|
2012-01-18 18:03:23 -05:00
|
|
|
compositor->stage = meta_wayland_stage_new ();
|
2012-01-07 17:21:32 -05:00
|
|
|
g_signal_connect (compositor->stage, "destroy",
|
|
|
|
G_CALLBACK (stage_destroy_cb), NULL);
|
|
|
|
|
2013-05-03 13:51:22 -04:00
|
|
|
meta_wayland_data_device_manager_init (compositor->wayland_display);
|
|
|
|
|
2014-02-17 20:49:04 -05:00
|
|
|
compositor->seat = meta_wayland_seat_new (compositor->wayland_display);
|
2013-05-03 13:51:22 -04:00
|
|
|
|
2013-08-30 12:26:18 -04:00
|
|
|
meta_wayland_init_shell (compositor);
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
clutter_actor_show (compositor->stage);
|
|
|
|
|
2013-08-20 12:03:26 -04:00
|
|
|
/* FIXME: find the first free name instead */
|
|
|
|
compositor->display_name = g_strdup ("wayland-0");
|
|
|
|
if (wl_display_add_socket (compositor->wayland_display, compositor->display_name))
|
2012-01-07 17:21:32 -05:00
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2014-02-07 19:26:35 -05:00
|
|
|
if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
|
2012-01-07 17:21:32 -05:00
|
|
|
g_error ("Failed to start X Wayland");
|
|
|
|
|
2014-02-07 19:26:35 -05:00
|
|
|
set_gnome_env ("DISPLAY", compositor->xwayland_manager.display_name);
|
2013-08-20 12:03:26 -04:00
|
|
|
set_gnome_env ("WAYLAND_DISPLAY", compositor->display_name);
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_finalize (void)
|
|
|
|
{
|
2013-08-19 08:57:16 -04:00
|
|
|
MetaWaylandCompositor *compositor;
|
|
|
|
|
|
|
|
compositor = meta_wayland_compositor_get_default ();
|
|
|
|
|
2014-02-03 19:37:23 -05:00
|
|
|
meta_xwayland_stop (&compositor->xwayland_manager);
|
2014-01-31 18:51:45 -05:00
|
|
|
|
|
|
|
if (compositor->launcher)
|
|
|
|
meta_launcher_free (compositor->launcher);
|
2013-08-19 08:57:16 -04:00
|
|
|
}
|
|
|
|
|
2013-07-30 05:36:18 -04:00
|
|
|
gboolean
|
2014-02-01 19:34:24 -05:00
|
|
|
meta_wayland_compositor_activate_vt (MetaWaylandCompositor *compositor,
|
|
|
|
int vt,
|
|
|
|
GError **error)
|
2013-07-30 05:36:18 -04:00
|
|
|
{
|
2014-02-01 19:34:24 -05:00
|
|
|
if (compositor->launcher)
|
|
|
|
{
|
|
|
|
return meta_launcher_activate_vt (compositor->launcher, vt, error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-11 17:25:02 -04:00
|
|
|
g_debug ("Ignoring VT switch keybinding, not running as display server");
|
2014-02-01 19:34:24 -05:00
|
|
|
return TRUE;
|
|
|
|
}
|
2013-07-30 05:36:18 -04:00
|
|
|
}
|
2014-03-11 17:04:22 -04:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_wayland_compositor_activate_session (MetaWaylandCompositor *compositor,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
if (compositor->launcher)
|
|
|
|
{
|
|
|
|
return meta_launcher_activate_vt (compositor->launcher, -1, error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_debug ("Ignoring activate_session, not running as display server");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|