Add wayland backend

This adds a clutter backend for running under the wayland window system.
Initial cogl framebuffer integration by Robert Bragg.
This commit is contained in:
Kristian Høgsberg 2010-09-28 10:17:46 -04:00 committed by Robert Bragg
parent a7cf98ebfc
commit cb5582c4ab
11 changed files with 1738 additions and 12 deletions

View File

@ -495,6 +495,25 @@ clutterfruity_includedir = $(clutter_includedir)/fruity
clutterfruity_include_HEADERS = $(srcdir)/fruity/clutter-fruity.h
endif # SUPPORT_FRUITY
# Wayland backend rules
if SUPPORT_WAYLAND
backend_source_h += \
$(srcdir)/wayland/clutter-wayland.h
backend_source_h_priv += \
$(srcdir)/wayland/clutter-backend-wayland.h \
$(srcdir)/wayland/clutter-stage-wayland.h
backend_source_c += \
$(srcdir)/wayland/clutter-backend-wayland.c \
$(srcdir)/wayland/clutter-stage-wayland.c \
$(srcdir)/wayland/clutter-event-wayland.c \
$(srcdir)/wayland/clutter-input-device-wayland.c
clutterwayland_includedir = $(clutter_includedir)/wayland
clutterwayland_include_HEADERS = $(wayland_source_h)
endif # SUPPORT_WAYLAND
# cally
cally_sources_h = \
$(srcdir)/cally/cally-actor.h \

View File

@ -294,6 +294,10 @@ if SUPPORT_EGL_PLATFORM_FRUITY
cogl_sources_c += \
$(srcdir)/winsys/cogl-fruity.c
endif
if SUPPORT_EGL_PLATFORM_DRM_SURFACELESS
cogl_sources_c += \
$(srcdir)/winsys/cogl-egl.c
endif
if SUPPORT_WIN32
cogl_sources_c += \
$(srcdir)/winsys/cogl-win32.c

View File

@ -27,11 +27,15 @@
#include "cogl.h"
#ifdef HAVE_COGL_GLES2
#ifdef HAVE_STANDALONE_EGL
#include <EGL/egl.h>
#else /* HAVE_COGL_GLES2 */
#include <EGL/eglext.h>
#define NativeDisplayType EGLNativeDisplayType
#define NativeWindowType EGLNativeWindowType
#else
#include <GLES/egl.h>
#endif /* HAVE_COGL_GLES2 */
#include <GLES/eglext.h>
#endif
CoglFuncPtr
_cogl_winsys_get_proc_address (const char *name)

View File

@ -0,0 +1,552 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Robert Bragg
* Kristian Høgsberg
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <wayland-util.h>
#include <wayland-client.h>
#include <xf86drm.h>
#include "../clutter-private.h"
#include "../clutter-main.h"
#include "../clutter-debug.h"
#include "../clutter-version.h"
#include "clutter-backend-wayland.h"
#include "clutter-stage-wayland.h"
#include "clutter-wayland.h"
static ClutterBackendWayland *backend_singleton = NULL;
G_DEFINE_TYPE (ClutterBackendWayland, _clutter_backend_wayland, CLUTTER_TYPE_BACKEND);
static void
clutter_backend_at_exit (void)
{
if (backend_singleton)
g_object_run_dispose (G_OBJECT (backend_singleton));
}
static gboolean
clutter_backend_wayland_pre_parse (ClutterBackend *backend,
GError **error)
{
return TRUE;
}
static void
drm_handle_device (void *data, struct wl_drm *drm, const char *device)
{
ClutterBackendWayland *backend_wayland = data;
backend_wayland->device_name = g_strdup (device);
}
static void
drm_handle_authenticated (void *data, struct wl_drm *drm)
{
ClutterBackendWayland *backend_wayland = data;
backend_wayland->authenticated = 1;
}
static const struct wl_drm_listener drm_listener =
{
drm_handle_device,
drm_handle_authenticated
};
static void
display_handle_geometry (void *data,
struct wl_output *output,
int32_t width, int32_t height)
{
ClutterBackendWayland *backend_wayland = data;
backend_wayland->screen_allocation.x = 0;
backend_wayland->screen_allocation.y = 0;
backend_wayland->screen_allocation.width = width;
backend_wayland->screen_allocation.height = height;
}
static const struct wl_output_listener output_listener =
{
display_handle_geometry,
};
static void
handle_configure (void *data, struct wl_shell *shell,
uint32_t timestamp, uint32_t edges,
struct wl_surface *surface,
int32_t x, int32_t y, int32_t width, int32_t height)
{
ClutterStageWayland *stage_wayland;
stage_wayland = wl_surface_get_user_data (surface);
stage_wayland->pending_allocation.x = x;
stage_wayland->pending_allocation.y = y;
stage_wayland->allocation = stage_wayland->pending_allocation;
clutter_actor_set_size (CLUTTER_ACTOR (stage_wayland->wrapper),
width, height);
/* the resize process is complete, so we can ask the stage
* to set up the GL viewport with the new size
*/
clutter_stage_ensure_viewport (stage_wayland->wrapper);
}
static const struct wl_shell_listener shell_listener = {
handle_configure,
};
static void
display_handle_global (struct wl_display *display,
uint32_t id,
const char *interface,
uint32_t version,
void *data)
{
ClutterBackendWayland *backend_wayland = data;
if (strcmp (interface, "compositor") == 0)
{
backend_wayland->wayland_compositor = wl_compositor_create (display, id);
}
else if (strcmp (interface, "output") == 0)
{
backend_wayland->wayland_output = wl_output_create (display, id);
wl_output_add_listener (backend_wayland->wayland_output,
&output_listener, backend_wayland);
}
else if (strcmp (interface, "input_device") == 0)
{
_clutter_backend_add_input_device (backend_wayland, id);
}
else if (strcmp (interface, "shell") == 0)
{
backend_wayland->wayland_shell = wl_shell_create (display, id);
wl_shell_add_listener (backend_wayland->wayland_shell,
&shell_listener, backend_wayland);
}
else if (strcmp (interface, "drm") == 0)
{
backend_wayland->wayland_drm = wl_drm_create (display, id);
wl_drm_add_listener (backend_wayland->wayland_drm,
&drm_listener, backend_wayland);
}
}
static gboolean
clutter_backend_wayland_post_parse (ClutterBackend *backend,
GError **error)
{
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
EGLBoolean status;
drm_magic_t magic;
g_atexit (clutter_backend_at_exit);
/* TODO: expose environment variable/commandline option for this... */
backend_wayland->wayland_display =
wl_display_create ("\0wayland", sizeof ("\0wayland"));
if (!backend_wayland->wayland_display)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Failed to open Wayland display socket");
return FALSE;
}
backend_wayland->wayland_source =
_clutter_event_source_wayland_new (backend_wayland->wayland_display);
g_source_attach (backend_wayland->wayland_source, NULL);
/* Set up listener so we'll catch all events. */
wl_display_add_global_listener (backend_wayland->wayland_display,
display_handle_global,
backend_wayland);
/* Process connection events. */
wl_display_iterate (backend_wayland->wayland_display, WL_DISPLAY_READABLE);
backend_wayland->drm_fd = open (backend_wayland->device_name, O_RDWR);
if (backend_wayland->drm_fd < 0)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Failed to open drm device");
return FALSE;
}
if (drmGetMagic (backend_wayland->drm_fd, &magic))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Failed to get drm magic");
return FALSE;
}
wl_drm_authenticate (backend_wayland->wayland_drm, magic);
wl_display_iterate (backend_wayland->wayland_display, WL_DISPLAY_WRITABLE);
while (!backend_wayland->authenticated)
wl_display_iterate (backend_wayland->wayland_display, WL_DISPLAY_READABLE);
backend_wayland->get_drm_display =
(PFNEGLGETDRMDISPLAYMESA) eglGetProcAddress ("eglGetDRMDisplayMESA");
backend_wayland->create_drm_image =
(PFNEGLCREATEDRMIMAGEMESA) eglGetProcAddress ("eglCreateDRMImageMESA");
backend_wayland->destroy_image =
(PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress ("eglDestroyImageKHR");
backend_wayland->export_drm_image =
(PFNEGLEXPORTDRMIMAGEMESA) eglGetProcAddress ("eglExportDRMImageMESA");
backend_wayland->image_target_texture_2d =
(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress ("glEGLImageTargetTexture2DOES");
if (backend_wayland->get_drm_display == NULL ||
backend_wayland->create_drm_image == NULL ||
backend_wayland->destroy_image == NULL ||
backend_wayland->export_drm_image == NULL ||
backend_wayland->image_target_texture_2d == NULL)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Missing EGL extensions");
return FALSE;
}
backend_wayland->edpy =
backend_wayland->get_drm_display (backend_wayland->drm_fd);
status = eglInitialize (backend_wayland->edpy,
&backend_wayland->egl_version_major,
&backend_wayland->egl_version_minor);
if (status != EGL_TRUE)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to Initialize EGL");
return FALSE;
}
CLUTTER_NOTE (BACKEND, "EGL Reports version %i.%i",
backend_wayland->egl_version_major,
backend_wayland->egl_version_minor);
return TRUE;
}
static gboolean
try_create_context (ClutterBackend *backend,
int retry_cookie,
gboolean *try_fallback,
GError **error)
{
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
EGLDisplay edpy;
const char *error_message;
edpy = clutter_egl_display ();
eglBindAPI (EGL_OPENGL_API);
if (backend_wayland->egl_context == EGL_NO_CONTEXT)
{
#if defined (HAVE_COGL_GLES2)
static const EGLint attribs[] =
{ EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
#else
static const EGLint *attribs = NULL;
#endif
backend_wayland->egl_context = eglCreateContext (edpy,
NULL,
EGL_NO_CONTEXT,
attribs);
if (backend_wayland->egl_context == EGL_NO_CONTEXT)
{
error_message = "Unable to create a suitable EGL context";
goto fail;
}
CLUTTER_NOTE (GL, "Created EGL Context");
}
if (!eglMakeCurrent (edpy, NULL, NULL, backend_wayland->egl_context))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to MakeCurrent with NULL drawables");
return FALSE;
}
return TRUE;
fail:
{
*try_fallback = FALSE;
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"%s", error_message);
return FALSE;
}
}
static gboolean
clutter_backend_wayland_create_context (ClutterBackend *backend,
GError **error)
{
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
EGLDisplay edpy;
const gchar *egl_extensions = NULL;
gboolean status;
int retry_cookie;
gboolean try_fallback;
GError *try_error = NULL;
if (backend_wayland->egl_context != EGL_NO_CONTEXT)
return TRUE;
edpy = clutter_egl_display ();
egl_extensions = eglQueryString (edpy, EGL_EXTENSIONS);
if (!_cogl_check_extension ("EGL_KHR_surfaceless_opengl", egl_extensions))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Wayland clients require the "
"EGL_KHR_surfaceless_opengl extension");
return FALSE;
}
retry_cookie = 0;
while (!(status = try_create_context (backend,
retry_cookie,
&try_fallback,
&try_error)) &&
try_fallback)
{
g_warning ("Failed to create context: %s\nWill try fallback...",
try_error->message);
g_error_free (try_error);
try_error = NULL;
retry_cookie++;
}
if (!status)
g_propagate_error (error, try_error);
return status;
}
static void
clutter_backend_wayland_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
}
static void
clutter_backend_wayland_redraw (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterStageWindow *impl;
impl = _clutter_stage_get_window (stage);
if (!impl)
return;
g_assert (CLUTTER_IS_STAGE_WAYLAND (impl));
_clutter_stage_wayland_redraw (CLUTTER_STAGE_WAYLAND (impl), stage);
}
static void
clutter_backend_wayland_init_events (ClutterBackend *backend)
{
}
static void
clutter_backend_wayland_finalize (GObject *gobject)
{
if (backend_singleton)
backend_singleton = NULL;
G_OBJECT_CLASS (_clutter_backend_wayland_parent_class)->finalize (gobject);
}
static void
clutter_backend_wayland_dispose (GObject *gobject)
{
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (gobject);
/* We chain up before disposing our own resources so that
ClutterBackend will destroy all of the stages before we destroy
the egl context. Otherwise the actors may try to make GL calls
during destruction which causes a crash */
G_OBJECT_CLASS (_clutter_backend_wayland_parent_class)->dispose (gobject);
if (backend_wayland->egl_context)
{
eglDestroyContext (backend_wayland->edpy, backend_wayland->egl_context);
backend_wayland->egl_context = NULL;
}
if (backend_wayland->edpy)
{
eglTerminate (backend_wayland->edpy);
backend_wayland->edpy = 0;
}
if (backend_wayland->drm_fd != -1)
{
close (backend_wayland->drm_fd);
backend_wayland->drm_fd = -1;
}
}
static GObject *
clutter_backend_wayland_constructor (GType gtype,
guint n_params,
GObjectConstructParam *params)
{
GObjectClass *parent_class;
GObject *retval;
if (!backend_singleton)
{
parent_class = G_OBJECT_CLASS (_clutter_backend_wayland_parent_class);
retval = parent_class->constructor (gtype, n_params, params);
backend_singleton = CLUTTER_BACKEND_WAYLAND (retval);
return retval;
}
g_warning ("Attempting to create a new backend object. This should "
"never happen, so we return the singleton instance.");
return g_object_ref (backend_singleton);
}
static ClutterFeatureFlags
clutter_backend_wayland_get_features (ClutterBackend *backend)
{
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
ClutterFeatureFlags flags = 0;
g_assert (backend_wayland->egl_context != NULL);
flags |=
CLUTTER_FEATURE_STAGE_MULTIPLE |
CLUTTER_FEATURE_SWAP_EVENTS |
CLUTTER_FEATURE_SYNC_TO_VBLANK;
CLUTTER_NOTE (BACKEND, "Checking features\n"
"GL_VENDOR: %s\n"
"GL_RENDERER: %s\n"
"GL_VERSION: %s\n"
"EGL_VENDOR: %s\n"
"EGL_VERSION: %s\n"
"EGL_EXTENSIONS: %s\n",
glGetString (GL_VENDOR),
glGetString (GL_RENDERER),
glGetString (GL_VERSION),
eglQueryString (backend_wayland->edpy, EGL_VENDOR),
eglQueryString (backend_wayland->edpy, EGL_VERSION),
eglQueryString (backend_wayland->edpy, EGL_EXTENSIONS));
return flags;
}
static ClutterStageWindow *
clutter_backend_wayland_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
ClutterStageWindow *stage;
ClutterStageWayland *stage_wayland;
CLUTTER_NOTE (BACKEND, "Creating stage of type '%s'",
g_type_name (CLUTTER_STAGE_TYPE));
stage = g_object_new (CLUTTER_TYPE_STAGE_WAYLAND, NULL);
stage_wayland = CLUTTER_STAGE_WAYLAND (stage);
stage_wayland->backend = backend_wayland;
stage_wayland->wrapper = wrapper;
return stage;
}
static void
_clutter_backend_wayland_class_init (ClutterBackendWaylandClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
gobject_class->constructor = clutter_backend_wayland_constructor;
gobject_class->dispose = clutter_backend_wayland_dispose;
gobject_class->finalize = clutter_backend_wayland_finalize;
backend_class->pre_parse = clutter_backend_wayland_pre_parse;
backend_class->post_parse = clutter_backend_wayland_post_parse;
backend_class->get_features = clutter_backend_wayland_get_features;
backend_class->init_events = clutter_backend_wayland_init_events;
backend_class->create_stage = clutter_backend_wayland_create_stage;
backend_class->create_context = clutter_backend_wayland_create_context;
backend_class->ensure_context = clutter_backend_wayland_ensure_context;
backend_class->redraw = clutter_backend_wayland_redraw;
}
static void
_clutter_backend_wayland_init (ClutterBackendWayland *backend_wayland)
{
backend_wayland->egl_context = EGL_NO_CONTEXT;
backend_wayland->drm_fd = -1;
}
GType
_clutter_backend_impl_get_type (void)
{
return _clutter_backend_wayland_get_type ();
}
EGLDisplay
clutter_egl_display (void)
{
return backend_singleton->edpy;
}

View File

@ -0,0 +1,94 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Robert Bragg
* Kristian Høgsberg
*/
#ifndef __CLUTTER_BACKEND_WAYLAND_H__
#define __CLUTTER_BACKEND_WAYLAND_H__
#include <glib-object.h>
#include <clutter/clutter-event.h>
#include <clutter/clutter-backend.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "clutter-wayland.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_BACKEND_WAYLAND (_clutter_backend_wayland_get_type ())
#define CLUTTER_BACKEND_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_WAYLAND, ClutterBackendWayland))
#define CLUTTER_IS_BACKEND_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_WAYLAND))
#define CLUTTER_BACKEND_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_WAYLAND, ClutterBackendWaylandClass))
#define CLUTTER_IS_BACKEND_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_WAYLAND))
#define CLUTTER_BACKEND_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_WAYLAND, ClutterBackendWaylandClass))
typedef struct _ClutterBackendWayland ClutterBackendWayland;
typedef struct _ClutterBackendWaylandClass ClutterBackendWaylandClass;
struct _ClutterBackendWayland
{
ClutterBackend parent_instance;
/* EGL Specific */
EGLDisplay edpy;
EGLContext egl_context;
EGLConfig egl_config;
gint egl_version_major;
gint egl_version_minor;
struct wl_display *wayland_display;
GSource *wayland_source;
struct wl_compositor *wayland_compositor;
struct wl_shell *wayland_shell;
struct wl_drm *wayland_drm;
char *device_name;
int authenticated;
struct wl_output *wayland_output;
ClutterGeometry screen_allocation;
int drm_fd;
PFNEGLGETDRMDISPLAYMESA get_drm_display;
PFNEGLCREATEDRMIMAGEMESA create_drm_image;
PFNEGLDESTROYIMAGEKHRPROC destroy_image;
PFNEGLEXPORTDRMIMAGEMESA export_drm_image;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
};
struct _ClutterBackendWaylandClass
{
ClutterBackendClass parent_class;
};
GType _clutter_backend_wayland_get_type (void) G_GNUC_CONST;
GSource *_clutter_event_source_wayland_new(struct wl_display *display);
void _clutter_backend_add_input_device (ClutterBackendWayland *backend_wayland,
uint32_t id);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_WAYLAND_H__ */

View File

@ -0,0 +1,148 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Robert Bragg
* Kristian Høgsberg
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdint.h>
#include <stdlib.h>
#include <wayland-client.h>
#include "../clutter-event.h"
#include "../clutter-main.h"
typedef struct _ClutterEventSourceWayland
{
GSource source;
GPollFD pfd;
uint32_t mask;
struct wl_display *display;
} ClutterEventSourceWayland;
static gboolean
clutter_event_source_wayland_prepare (GSource *base, gint *timeout)
{
ClutterEventSourceWayland *source = (ClutterEventSourceWayland *) base;
gboolean retval;
clutter_threads_enter ();
*timeout = -1;
/* We have to add/remove the GPollFD if we want to update our
* poll event mask dynamically. Instead, let's just flush all
* write on idle instead, which is what this amounts to. */
while (source->mask & WL_DISPLAY_WRITABLE)
wl_display_iterate (source->display, WL_DISPLAY_WRITABLE);
retval = clutter_events_pending ();
clutter_threads_leave ();
return retval;
}
static gboolean
clutter_event_source_wayland_check (GSource *base)
{
ClutterEventSourceWayland *source = (ClutterEventSourceWayland *) base;
gboolean retval;
clutter_threads_enter ();
retval = clutter_events_pending () || source->pfd.revents;
clutter_threads_leave ();
return retval;
}
static gboolean
clutter_event_source_wayland_dispatch (GSource *base,
GSourceFunc callback,
gpointer data)
{
ClutterEventSourceWayland *source = (ClutterEventSourceWayland *) base;
ClutterEvent *event;
clutter_threads_enter ();
if (source->pfd.revents)
{
wl_display_iterate (source->display, WL_DISPLAY_READABLE);
source->pfd.revents = 0;
}
event = clutter_event_get ();
if (event)
{
/* forward the event into clutter for emission etc. */
clutter_do_event (event);
clutter_event_free (event);
}
clutter_threads_leave ();
return TRUE;
}
static GSourceFuncs clutter_event_source_wayland_funcs = {
clutter_event_source_wayland_prepare,
clutter_event_source_wayland_check,
clutter_event_source_wayland_dispatch,
NULL
};
static int
clutter_event_source_wayland_update (uint32_t mask, void *data)
{
ClutterEventSourceWayland *source = data;
source->mask = mask;
return 0;
}
GSource *
_clutter_event_source_wayland_new (struct wl_display *display)
{
ClutterEventSourceWayland *source;
source = (ClutterEventSourceWayland *)
g_source_new (&clutter_event_source_wayland_funcs,
sizeof (ClutterEventSourceWayland));
source->display = display;
source->pfd.fd =
wl_display_get_fd (display,
clutter_event_source_wayland_update, source);
source->pfd.events = G_IO_IN | G_IO_ERR;
g_source_add_poll (&source->source, &source->pfd);
return &source->source;
}

View File

@ -0,0 +1,340 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Robert Bragg
* Kristian Høgsberg
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <wayland-util.h>
#include <wayland-client.h>
#include <X11/extensions/XKBcommon.h>
#include "../clutter-debug.h"
#include "../clutter-private.h"
#include "../clutter-keysyms.h"
#include "clutter-stage-wayland.h"
#define CLUTTER_TYPE_INPUT_DEVICE_WAYLAND (clutter_input_device_wayland_get_type ())
#define CLUTTER_INPUT_DEVICE_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_WAYLAND, ClutterInputDeviceWayland))
#define CLUTTER_IS_INPUT_DEVICE_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_WAYLAND))
typedef struct _ClutterInputDeviceWayland ClutterInputDeviceWayland;
GType clutter_input_device_wayland_get_type (void) G_GNUC_CONST;
typedef struct _ClutterInputDeviceClass ClutterInputDeviceWaylandClass;
struct _ClutterInputDeviceWayland
{
ClutterInputDevice device;
struct wl_input_device *input_device;
ClutterStageWayland *pointer_focus;
ClutterStageWayland *keyboard_focus;
uint32_t modifier_state;
int32_t x, y, surface_x, surface_y;
struct xkb_desc *xkb;
};
G_DEFINE_TYPE (ClutterInputDeviceWayland,
clutter_input_device_wayland,
CLUTTER_TYPE_INPUT_DEVICE);
static void
clutter_backend_wayland_handle_motion (void *data,
struct wl_input_device *input_device,
uint32_t _time,
int32_t x, int32_t y,
int32_t sx, int32_t sy)
{
ClutterInputDeviceWayland *device = data;
ClutterStageWayland *stage_wayland = device->pointer_focus;
ClutterMainContext *clutter_context;
ClutterEvent *event;
event = clutter_event_new (CLUTTER_MOTION);
event->motion.stage = stage_wayland->wrapper;
event->motion.device = CLUTTER_INPUT_DEVICE (device);
event->motion.time = _time;
event->motion.modifier_state = 0;
event->motion.x = sx;
event->motion.y = sy;
device->surface_x = sx;
device->surface_y = sy;
device->x = x;
device->y = y;
clutter_context = _clutter_context_get_default ();
g_queue_push_head (clutter_context->events_queue, event);
}
static void
clutter_backend_wayland_handle_button (void *data,
struct wl_input_device *input_device,
uint32_t _time,
uint32_t button, uint32_t state)
{
ClutterInputDeviceWayland *device = data;
ClutterStageWayland *stage_wayland = device->pointer_focus;
ClutterMainContext *clutter_context;
ClutterEvent *event;
ClutterEventType type;
if (state)
type = CLUTTER_BUTTON_PRESS;
else
type = CLUTTER_BUTTON_RELEASE;
event = clutter_event_new (type);
event->button.stage = stage_wayland->wrapper;
event->button.device = CLUTTER_INPUT_DEVICE (device);
event->button.time = _time;
event->button.x = device->surface_x;
event->button.y = device->surface_y;
event->button.modifier_state = device->modifier_state;
/* evdev button codes */
switch (button) {
case 272:
event->button.button = 1;
break;
case 273:
event->button.button = 3;
break;
case 274:
event->button.button = 2;
break;
}
clutter_context = _clutter_context_get_default ();
g_queue_push_head (clutter_context->events_queue, event);
}
static void
clutter_backend_wayland_handle_key (void *data,
struct wl_input_device *input_device,
uint32_t _time,
uint32_t key, uint32_t state)
{
ClutterInputDeviceWayland *device = data;
ClutterStageWayland *stage_wayland = device->keyboard_focus;
ClutterMainContext *clutter_context;
ClutterEvent *event;
uint32_t code, sym, level;
if (state)
event = clutter_event_new (CLUTTER_KEY_PRESS);
else
event = clutter_event_new (CLUTTER_KEY_RELEASE);
code = key + device->xkb->min_key_code;
level = 0;
if (device->modifier_state & CLUTTER_SHIFT_MASK &&
XkbKeyGroupWidth (device->xkb, code, 0) > 1)
level = 1;
sym = XkbKeySymEntry (device->xkb, code, level, 0);
if (state)
device->modifier_state |= device->xkb->map->modmap[code];
else
device->modifier_state &= ~device->xkb->map->modmap[code];
event->key.device = CLUTTER_INPUT_DEVICE (device);
event->key.stage = stage_wayland->wrapper;
event->key.time = _time;
event->key.modifier_state = device->modifier_state;
event->key.hardware_keycode = key;
event->key.keyval = sym;
event->key.unicode_value = sym;
clutter_context = _clutter_context_get_default ();
g_queue_push_head (clutter_context->events_queue, event);
}
static void
clutter_backend_wayland_handle_pointer_focus (void *data,
struct wl_input_device *input_device,
uint32_t _time,
struct wl_surface *surface,
int32_t x, int32_t y, int32_t sx, int32_t sy)
{
ClutterInputDeviceWayland *device = data;
ClutterStageWayland *stage_wayland;
ClutterMainContext *clutter_context;
ClutterEvent *event;
if (device->pointer_focus)
{
stage_wayland = device->pointer_focus;
event = clutter_event_new (CLUTTER_LEAVE);
event->crossing.stage = stage_wayland->wrapper;
event->crossing.time = _time;
event->crossing.x = sx;
event->crossing.y = sy;
event->crossing.source = CLUTTER_ACTOR (stage_wayland->wrapper);
event->crossing.device = CLUTTER_INPUT_DEVICE (device);
clutter_context = _clutter_context_get_default ();
g_queue_push_head (clutter_context->events_queue, event);
device->pointer_focus = NULL;
_clutter_input_device_set_stage (CLUTTER_INPUT_DEVICE (device), NULL);
}
if (surface)
{
stage_wayland = wl_surface_get_user_data (surface);
device->pointer_focus = stage_wayland;
_clutter_input_device_set_stage (CLUTTER_INPUT_DEVICE (device),
stage_wayland->wrapper);
event = clutter_event_new (CLUTTER_MOTION);
event->motion.time = _time;
event->motion.x = sx;
event->motion.y = sy;
event->motion.modifier_state = device->modifier_state;
event->motion.source = CLUTTER_ACTOR (stage_wayland->wrapper);
event->motion.device = CLUTTER_INPUT_DEVICE (device);
clutter_context = _clutter_context_get_default ();
g_queue_push_head (clutter_context->events_queue, event);
device->surface_x = sx;
device->surface_y = sy;
device->x = x;
device->y = y;
/* Revert back to default pointer for now. */
wl_input_device_attach (input_device, _time, NULL, 0, 0);
}
}
static void
clutter_backend_wayland_handle_keyboard_focus (void *data,
struct wl_input_device *input_device,
uint32_t _time,
struct wl_surface *surface,
struct wl_array *keys)
{
ClutterInputDeviceWayland *device = data;
ClutterStageWayland *stage_wayland;
ClutterMainContext *clutter_context;
ClutterEvent *event;
uint32_t *k, *end;
if (device->keyboard_focus)
{
stage_wayland = device->keyboard_focus;
device->keyboard_focus = NULL;
event = clutter_event_new (CLUTTER_STAGE_STATE);
event->stage_state.time = _time;
event->stage_state.stage = stage_wayland->wrapper;
event->stage_state.stage = stage_wayland->wrapper;
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
event->stage_state.new_state = 0;
clutter_context = _clutter_context_get_default ();
g_queue_push_head (clutter_context->events_queue, event);
}
if (surface)
{
stage_wayland = wl_surface_get_user_data (surface);
device->keyboard_focus = stage_wayland;
event = clutter_event_new (CLUTTER_STAGE_STATE);
event->stage_state.stage = stage_wayland->wrapper;
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
event->stage_state.new_state = CLUTTER_STAGE_STATE_ACTIVATED;
end = keys->data + keys->size;
device->modifier_state = 0;
for (k = keys->data; k < end; k++)
device->modifier_state |= device->xkb->map->modmap[*k];
clutter_context = _clutter_context_get_default ();
g_queue_push_head (clutter_context->events_queue, event);
}
}
static const struct wl_input_device_listener input_device_listener = {
clutter_backend_wayland_handle_motion,
clutter_backend_wayland_handle_button,
clutter_backend_wayland_handle_key,
clutter_backend_wayland_handle_pointer_focus,
clutter_backend_wayland_handle_keyboard_focus,
};
static void
clutter_input_device_wayland_class_init (ClutterInputDeviceWaylandClass *klass)
{
}
static void
clutter_input_device_wayland_init (ClutterInputDeviceWayland *self)
{
}
const char *option_xkb_layout = "us";
const char *option_xkb_variant = "";
const char *option_xkb_options = "";
void
_clutter_backend_add_input_device (ClutterBackendWayland *backend_wayland,
uint32_t id)
{
ClutterInputDeviceWayland *device;
struct xkb_rule_names names;
device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_WAYLAND,
"id", id,
"device-type", CLUTTER_POINTER_DEVICE,
"name", "wayland device",
NULL);
device->input_device =
wl_input_device_create (backend_wayland->wayland_display, id);
wl_input_device_add_listener (device->input_device,
&input_device_listener, device);
wl_input_device_set_user_data (device->input_device, device);
names.rules = "evdev";
names.model = "pc105";
names.layout = option_xkb_layout;
names.variant = option_xkb_variant;
names.options = option_xkb_options;
device->xkb = xkb_compile_keymap_from_rules (&names);
if (!device->xkb)
CLUTTER_NOTE (BACKEND, "Failed to compile keymap");
}

View File

@ -0,0 +1,368 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Robert Bragg
* Kristian Høgsberg
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <wayland-util.h>
#include <wayland-client.h>
#include <xf86drm.h>
#include "../clutter-main.h"
#include "../clutter-feature.h"
#include "../clutter-color.h"
#include "../clutter-util.h"
#include "../clutter-event.h"
#include "../clutter-enum-types.h"
#include "../clutter-private.h"
#include "../clutter-debug.h"
#include "../clutter-units.h"
#include "../clutter-stage.h"
#include "../clutter-stage-window.h"
#include "clutter-stage-wayland.h"
#include "clutter-wayland.h"
#include "clutter-backend-wayland.h"
#include "cogl/cogl-framebuffer-private.h"
static void
wayland_swap_buffers (ClutterStageWayland *stage_wayland);
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageWayland,
_clutter_stage_wayland,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init));
static ClutterStageWaylandWaylandBuffer *
wayland_create_buffer (ClutterStageWayland *stage_wayland,
ClutterGeometry *geom)
{
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
EGLDisplay edpy = clutter_egl_display ();
ClutterStageWaylandWaylandBuffer *buffer;
EGLint image_attribs[] = {
EGL_WIDTH, 0,
EGL_HEIGHT, 0,
EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA,
EGL_NONE
};
CoglHandle tex;
buffer = g_slice_new (ClutterStageWaylandWaylandBuffer);
image_attribs[1] = geom->width;
image_attribs[3] = geom->height;
buffer->drm_image = backend_wayland->create_drm_image (edpy, image_attribs);
glGenTextures (1, &buffer->texture);
glBindTexture (GL_TEXTURE_2D, buffer->texture);
backend_wayland->image_target_texture_2d (GL_TEXTURE_2D, buffer->drm_image);
tex = cogl_texture_new_from_foreign (buffer->texture,
GL_TEXTURE_2D,
geom->width,
geom->height,
0,
0,
COGL_PIXEL_FORMAT_ARGB_8888);
buffer->offscreen = cogl_offscreen_new_to_texture (tex);
cogl_handle_unref (tex);
buffer->wayland_buffer = NULL;
return buffer;
}
static void
wayland_free_buffer (ClutterStageWaylandWaylandBuffer *buffer)
{
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
EGLDisplay edpy = clutter_egl_display ();
if (buffer->wayland_buffer)
wl_buffer_destroy (buffer->wayland_buffer);
cogl_handle_unref (buffer->offscreen);
glDeleteTextures (1, &buffer->texture);
backend_wayland->destroy_image (edpy, buffer->drm_image);
g_slice_free (ClutterStageWaylandWaylandBuffer, buffer);
}
static void
clutter_stage_wayland_unrealize (ClutterStageWindow *stage_window)
{
ClutterStageWayland *stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);
if (stage_wayland->front_buffer)
{
wayland_free_buffer (stage_wayland->front_buffer);
stage_wayland->front_buffer = NULL;
}
if (stage_wayland->back_buffer)
{
wayland_free_buffer (stage_wayland->back_buffer);
stage_wayland->back_buffer = NULL;
}
wayland_free_buffer (stage_wayland->pick_buffer);
}
static gboolean
clutter_stage_wayland_realize (ClutterStageWindow *stage_window)
{
ClutterStageWayland *stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
gfloat width, height;
clutter_actor_get_size (CLUTTER_ACTOR (stage_wayland->wrapper),
&width, &height);
stage_wayland->pending_allocation.width = (gint)width;
stage_wayland->pending_allocation.height = (gint)height;
stage_wayland->allocation = stage_wayland->pending_allocation;
stage_wayland->wayland_surface =
wl_compositor_create_surface (backend_wayland->wayland_compositor);
wl_surface_set_user_data (stage_wayland->wayland_surface, stage_wayland);
stage_wayland->pick_buffer =
wayland_create_buffer (stage_wayland, &stage_wayland->allocation);
return TRUE;
}
static int
clutter_stage_wayland_get_pending_swaps (ClutterStageWindow *stage_window)
{
ClutterStageWayland *stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);
return stage_wayland->pending_swaps;
}
static void
clutter_stage_wayland_set_fullscreen (ClutterStageWindow *stage_window,
gboolean fullscreen)
{
g_warning ("Stage of type '%s' do not support ClutterStage::set_fullscreen",
G_OBJECT_TYPE_NAME (stage_window));
}
static void
clutter_stage_wayland_set_title (ClutterStageWindow *stage_window,
const gchar *title)
{
g_warning ("Stage of type '%s' do not support ClutterStage::set_title",
G_OBJECT_TYPE_NAME (stage_window));
}
static void
clutter_stage_wayland_set_cursor_visible (ClutterStageWindow *stage_window,
gboolean cursor_visible)
{
g_warning ("Stage of type '%s' do not support ClutterStage::set_cursor_visible",
G_OBJECT_TYPE_NAME (stage_window));
}
static ClutterActor *
clutter_stage_wayland_get_wrapper (ClutterStageWindow *stage_window)
{
return CLUTTER_ACTOR (CLUTTER_STAGE_WAYLAND (stage_window)->wrapper);
}
static void
clutter_stage_wayland_show (ClutterStageWindow *stage_window,
gboolean do_raise)
{
ClutterStageWayland *stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);
clutter_actor_map (CLUTTER_ACTOR (stage_wayland->wrapper));
}
static void
clutter_stage_wayland_hide (ClutterStageWindow *stage_window)
{
ClutterStageWayland *stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);
clutter_actor_unmap (CLUTTER_ACTOR (stage_wayland->wrapper));
}
static void
clutter_stage_wayland_get_geometry (ClutterStageWindow *stage_window,
ClutterGeometry *geometry)
{
ClutterStageWayland *stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);
if (geometry)
{
*geometry = stage_wayland->allocation;
}
}
static void
clutter_stage_wayland_resize (ClutterStageWindow *stage_window,
gint width,
gint height)
{
ClutterStageWayland *stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);
stage_wayland->pending_allocation.width = width;
stage_wayland->pending_allocation.height = height;
}
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{
iface->realize = clutter_stage_wayland_realize;
iface->unrealize = clutter_stage_wayland_unrealize;
iface->get_pending_swaps = clutter_stage_wayland_get_pending_swaps;
iface->set_fullscreen = clutter_stage_wayland_set_fullscreen;
iface->set_title = clutter_stage_wayland_set_title;
iface->set_cursor_visible = clutter_stage_wayland_set_cursor_visible;
iface->get_wrapper = clutter_stage_wayland_get_wrapper;
iface->get_geometry = clutter_stage_wayland_get_geometry;
iface->resize = clutter_stage_wayland_resize;
iface->show = clutter_stage_wayland_show;
iface->hide = clutter_stage_wayland_hide;
}
static void
_clutter_stage_wayland_class_init (ClutterStageWaylandClass *klass)
{
}
static void
_clutter_stage_wayland_init (ClutterStageWayland *stage_wayland)
{
stage_wayland->allocation.x = 0;
stage_wayland->allocation.y = 0;
stage_wayland->allocation.width = 640;
stage_wayland->allocation.height = 480;
stage_wayland->save_allocation = stage_wayland->allocation;
}
static void
wayland_free_front_buffer (void *data)
{
ClutterStageWayland *stage_wayland = data;
if (stage_wayland->front_buffer)
wayland_free_buffer (stage_wayland->front_buffer);
stage_wayland->front_buffer = stage_wayland->pending_buffer;
stage_wayland->pending_buffer = NULL;
if (stage_wayland->back_buffer)
wayland_swap_buffers (stage_wayland);
}
static void
wayland_frame_callback (void *data, uint32_t _time)
{
ClutterStageWayland *stage_wayland = data;
stage_wayland->pending_swaps--;
}
static void
wayland_swap_buffers (ClutterStageWayland *stage_wayland)
{
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
EGLDisplay edpy = clutter_egl_display ();
EGLint name;
EGLint stride;
struct wl_visual *visual;
if (stage_wayland->pending_buffer)
return;
stage_wayland->pending_buffer = stage_wayland->back_buffer;
stage_wayland->back_buffer = NULL;
backend_wayland->export_drm_image (edpy,
stage_wayland->pending_buffer->drm_image,
&name, NULL, &stride);
visual =
wl_display_get_premultiplied_argb_visual (backend_wayland->wayland_display);
stage_wayland->pending_buffer->wayland_buffer =
wl_drm_create_buffer (backend_wayland->wayland_drm,
name,
stage_wayland->allocation.width,
stage_wayland->allocation.height,
stride, visual);
wl_surface_attach (stage_wayland->wayland_surface,
stage_wayland->pending_buffer->wayland_buffer);
wl_surface_map (stage_wayland->wayland_surface,
stage_wayland->allocation.x,
stage_wayland->allocation.y,
stage_wayland->allocation.width,
stage_wayland->allocation.height);
wl_display_sync_callback (backend_wayland->wayland_display,
wayland_free_front_buffer,
stage_wayland);
stage_wayland->pending_swaps++;
wl_display_frame_callback (backend_wayland->wayland_display,
wayland_frame_callback,
stage_wayland);
}
void
_clutter_stage_wayland_redraw (ClutterStageWayland *stage_wayland,
ClutterStage *stage)
{
ClutterActor *wrapper = CLUTTER_ACTOR (stage_wayland->wrapper);
stage_wayland->allocation = stage_wayland->pending_allocation;
if (stage_wayland->back_buffer)
{
wayland_free_buffer (stage_wayland->back_buffer);
stage_wayland->back_buffer = NULL;
}
stage_wayland->back_buffer = wayland_create_buffer (stage_wayland,
&stage_wayland->allocation);
cogl_set_framebuffer (stage_wayland->back_buffer->offscreen);
_clutter_stage_maybe_setup_viewport (stage_wayland->wrapper);
clutter_actor_paint (wrapper);
cogl_flush ();
glFlush ();
cogl_set_framebuffer (stage_wayland->pick_buffer->offscreen);
_clutter_stage_maybe_setup_viewport (stage_wayland->wrapper);
wayland_swap_buffers (stage_wayland);
}

View File

@ -0,0 +1,94 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Robert Bragg
* Kristian Høgsberg
*/
#ifndef __CLUTTER_STAGE_WAYLAND_H__
#define __CLUTTER_STAGE_WAYLAND_H__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib-object.h>
#include <clutter/clutter-stage.h>
#define MESA_EGL_NO_X11_HEADERS
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "clutter-backend-wayland.h"
#define CLUTTER_TYPE_STAGE_WAYLAND (_clutter_stage_wayland_get_type ())
#define CLUTTER_STAGE_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_WAYLAND, ClutterStageWayland))
#define CLUTTER_IS_STAGE_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_WAYLAND))
#define CLUTTER_STAGE_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_WAYLAND, ClutterStageWaylandClass))
#define CLUTTER_IS_STAGE_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_WAYLAND))
#define CLUTTER_STAGE_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_WAYLAND, ClutterStageWaylandClass))
typedef struct _ClutterStageWayland ClutterStageWayland;
typedef struct _ClutterStageWaylandClass ClutterStageWaylandClass;
typedef struct _ClutterStageWaylandWaylandBuffer
{
EGLImageKHR drm_image;
GLuint texture;
CoglHandle offscreen;
struct wl_buffer *wayland_buffer;
} ClutterStageWaylandWaylandBuffer;
struct _ClutterStageWayland
{
GObject parent_instance;
/* the stage wrapper */
ClutterStage *wrapper;
/* back pointer to the backend */
ClutterBackendWayland *backend;
ClutterGeometry allocation;
ClutterGeometry save_allocation;
ClutterGeometry pending_allocation;
struct wl_surface *wayland_surface;
int pending_swaps;
ClutterStageWaylandWaylandBuffer *front_buffer;
ClutterStageWaylandWaylandBuffer *back_buffer;
ClutterStageWaylandWaylandBuffer *pending_buffer;
ClutterStageWaylandWaylandBuffer *pick_buffer;
};
struct _ClutterStageWaylandClass
{
GObjectClass parent_class;
};
GType _clutter_stage_wayland_get_type (void) G_GNUC_CONST;
void _clutter_stage_wayland_redraw (ClutterStageWayland *stage_wayland,
ClutterStage *stage);
#endif /* __CLUTTER_STAGE_WAYLAND_H__ */

View File

@ -0,0 +1,60 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Robert Bragg
* Kristian Høgsberg
*/
/**
* SECTION:clutter-wayland
* @short_description: Wayland specific API
*
* The Wayland backend for Clutter provides some Wayland specific API
*
* You need to include
* <filename class="headerfile">&lt;clutter/egl/clutter-wayland.h&gt;</filename>
* to have access to the functions documented here.
*/
#ifndef __CLUTTER_WAYLAND_H__
#define __CLUTTER_WAYLAND_H__
#include <glib.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
G_BEGIN_DECLS
/**
* clutter_egl_display:
*
* Retrieves the <structname>EGLDisplay</structname> used by Clutter
*
* Return value: the EGL display
*/
EGLDisplay
clutter_egl_display (void);
G_END_DECLS
#endif /* __CLUTTER_WAYLAND_H__ */

View File

@ -152,7 +152,7 @@ experimental_backend=no
experimental_image=no
AC_ARG_WITH([flavour],
[AC_HELP_STRING([--with-flavour=@<:@glx/opengl-egl-xlib/eglx/eglnative/osx/win32/fruity/cex100@:>@],
[AC_HELP_STRING([--with-flavour=@<:@glx/opengl-egl-xlib/wayland/eglx/eglnative/osx/win32/fruity/cex100@:>@],
[Select the Clutter window system backend])],
[CLUTTER_FLAVOUR=$with_flavour])
@ -228,6 +228,26 @@ AS_CASE([$CLUTTER_FLAVOUR],
PKG_CHECK_EXISTS([egl], [BACKEND_PC_FILES="$BACKEND_PC_FILES egl"], [])
],
[wayland],
[
experimental_backend="yes"
cogl_gl_headers="GL/gl.h"
CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_WAYLAND"
SUPPORT_WAYLAND=1
SUPPORT_EGL_PLATFORM_DRM_SURFACELESS=1
COGL_DRIVER="gl"
CLUTTER_WINSYS=wayland
CLUTTER_SONAME_INFIX=wayland
PKG_CHECK_EXISTS([gl], [BACKEND_PC_FILES="$BACKEND_PC_FILES gl"], [])
PKG_CHECK_EXISTS([egl], [BACKEND_PC_FILES="$BACKEND_PC_FILES egl"], [])
PKG_CHECK_EXISTS([wayland-client xkbcommon],
[BACKEND_PC_FILES="$BACKEND_PC_FILES wayland-client xkbcommon"], [])
],
[eglx],
[
# the GL header is defined in the COGL checks above
@ -383,6 +403,11 @@ AS_IF([test "x$SUPPORT_GLX" = "x1"],
[AC_MSG_ERROR([Required GLX library not found])])
])
AS_IF([test "x$SUPPORT_WAYLAND" = "x1"],
[
AC_DEFINE([HAVE_CLUTTER_WAYLAND], [1], [Have the Wayland backend])
])
AS_IF([test "x$SUPPORT_EGL" = "x1"],
[
AC_DEFINE([HAVE_CLUTTER_EGL], [1], [Have the EGL backend])
@ -395,24 +420,29 @@ AS_IF([test "x$CLUTTER_EGL_BACKEND" = "xgeneric"],
AS_IF([test "x$CLUTTER_EGL_BACKEND" = "xcex100"],
AC_DEFINE([CLUTTER_EGL_BACKEND_CEX100], [1], [Use CEX100 EGL backend]))
AS_IF([test "x$SUPPORT_EGL_POWERVR_X11" = "x1"],
AS_IF([test "x$SUPPORT_EGL_PLATFORM_POWERVR_X11" = "x1"],
[
AC_DEFINE([COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT], [1],
[Cogl supports OpenGLES using the EGL API with PowerVR X11 platform typedefs])
[Cogl supports OpenGL[ES] using the EGL API with PowerVR X11 platform typedefs])
])
AS_IF([test "x$SUPPORT_EGL_POWERVR_NULL" = "x1"],
AS_IF([test "x$SUPPORT_EGL_PLATFORM_POWERVR_NULL" = "x1"],
[
AC_DEFINE([COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT], [1],
[Cogl supports OpenGLES using the EGL API with PowerVR NULL platform typedefs])
[Cogl supports OpenGL[ES] using the EGL API with PowerVR NULL platform typedefs])
])
AS_IF([test "x$SUPPORT_EGL_POWERVR_GDL" = "x1"],
AS_IF([test "x$SUPPORT_EGL_PLATFORM_POWERVR_GDL" = "x1"],
[
AC_DEFINE([COGL_HAS_EGL_PLATFORM_POWERVR_GDL_SUPPORT], [1],
[Cogl supports OpenGLES using the EGL API with PowerVR GDL platform typedefs])
[Cogl supports OpenGL[ES] using the EGL API with the GDL API])
])
AS_IF([test "x$SUPPORT_EGL_PLATFORM_DRM_SURFACELESS" = "x1"],
[
AC_DEFINE([COGL_HAS_EGL_PLATFORM_DRM_SURFACELESS_SUPPORT], [1],
[Cogl supports OpenGL[ES] using the EGL API with EGL_MESA_drm_display])
])
# winsys conditionals for use in automake files...
AM_CONDITIONAL(SUPPORT_GLX, [test "x$SUPPORT_GLX" = "x1"])
@ -423,15 +453,20 @@ AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_POWERVR_X11, [test "x$SUPPORT_EGL_PLATFORM_P
AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_POWERVR_NULL, [test "x$SUPPORT_EGL_PLATFORM_POWERVR_NULL" = "x1"])
AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_POWERVR_GDL, [test "x$SUPPORT_EGL_PLATFORM_POWERVR_GDL" = "x1"])
AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_FRUITY, [test "x$CLUTTER_WINSYS" = "xfruity"])
AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_DRM_SURFACELESS, [test "x$SUPPORT_EGL_PLATFORM_DRM_SURFACELESS" = "x1"])
AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_FRUITY, [test "x$CLUTTER_WINSYS" = "xfruity"])
AM_CONDITIONAL(SUPPORT_OSX, [test "x$CLUTTER_WINSYS" = "xosx"])
AM_CONDITIONAL(SUPPORT_FRUITY, [test "x$CLUTTER_WINSYS" = "xfruity"])
AM_CONDITIONAL(SUPPORT_WIN32, [test "x$CLUTTER_WINSYS" = "xwin32"])
AM_CONDITIONAL(SUPPORT_CEX100, [test "x$SUPPORT_EGL_PLATFORM_POWERVR_GDL" = "x1"])
AM_CONDITIONAL(SUPPORT_WAYLAND, [test "x$CLUTTER_WINSYS" = "xwayland"])
dnl === COGL driver backend =====================================================
AS_IF([test "x$COGL_DRIVER" = "xgl"],
[ AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering]) ])
[ AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering])
NEED_SEPARATE_EGL=yes
])
cogl_gles_version_define=""
@ -478,7 +513,9 @@ AS_IF([test "x$COGL_DRIVER" = "xgles"],
AS_IF([test "x$NEED_SEPARATE_EGL" = "xyes"],
[
PKG_CHECK_EXISTS([egl],
[BACKEND_PC_FILES="$BACKEND_PC_FILES egl"],
[BACKEND_PC_FILES="$BACKEND_PC_FILES egl"
NEED_SEPARATE_EGL=yes
],
[
AC_CHECK_HEADERS([GLES/egl.h],
[],
@ -524,6 +561,8 @@ AS_IF([test "x$COGL_DRIVER" = "xgles"],
FLAVOUR_LIBS="$FLAVOUR_LIBS -lEGL"
]
)
NEED_SEPARATE_EGL=yes
],
[fruity],
@ -561,6 +600,10 @@ if test "x$SUPPORT_XLIB" = "x1"; then
COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_XLIB"
fi;
if test "x$NEED_SEPARATE_EGL" = "xyes"; then
AC_DEFINE([HAVE_STANDALONE_EGL], 1, [Have standalone EGL library])
fi
AS_CASE([$COGL_DRIVER],
[gl],
[COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GL"