Add a new GDK backend

This commit introduces a new flavour for Clutter, that uses GDK
for handling all window system specific interactions (except for
creating the cogl context, as cogl does not know about GDK), including
in particular events. This is not compatible with the X11 (glx)
flavour, and this is reflected by the different soname (libclutter-gdk-1.0.so),
as all X11 specific functions and classes are not available. If you
wish to be compatible, you should check for CLUTTER_WINDOWING_X11.
Other than that, this backend should be on feature parity with X11,
including XInput 2, XSettings and EMWH (with much, much less code)

https://bugzilla.gnome.org/show_bug.cgi?id=657434
This commit is contained in:
Giovanni Campagna 2011-08-26 03:09:18 +02:00 committed by Emmanuele Bassi
parent db53ca382c
commit 610a9c17ba
20 changed files with 2232 additions and 53 deletions

View File

@ -416,6 +416,34 @@ backend_source_c += $(cogl_source_c) $(glx_source_c)
backend_source_h_priv += $(cogl_source_h_priv)
endif # SUPPORT_GLX
# GDK backend rules
gdk_source_c = \
$(srcdir)/gdk/clutter-backend-gdk.c \
$(srcdir)/gdk/clutter-device-manager-gdk.c \
$(srcdir)/gdk/clutter-input-device-gdk.c \
$(srcdir)/gdk/clutter-event-gdk.c \
$(srcdir)/gdk/clutter-stage-gdk.c \
$(NULL)
gdk_source_h = \
$(srcdir)/gdk/clutter-gdk.h \
$(NULL)
gdk_source_h_priv = \
$(srcdir)/gdk/clutter-settings-gdk.h \
$(srcdir)/gdk/clutter-backend-gdk.h \
$(srcdir)/gdk/clutter-device-manager-gdk.h \
$(srcdir)/gdk/clutter-input-device-gdk.h \
$(srcdir)/gdk/clutter-event-gdk.h \
$(srcdir)/gdk/clutter-stage-gdk.h \
$(NULL)
if SUPPORT_GDK
backend_source_h += $(cogl_source_h) $(gdk_source_h)
backend_source_c += $(cogl_source_c) $(gdk_source_c)
backend_source_h_priv += $(cogl_source_h_priv) $(gdk_source_h_priv)
endif # SUPPORT_GDK
# Windows backend rules
win32_source_c = \
$(srcdir)/win32/clutter-backend-win32.c \

View File

@ -36,6 +36,17 @@
#include <errno.h>
#include "clutter-config.h"
#ifdef CLUTTER_WINDOWING_GDK
#include <gdk/gdk.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#endif
#include "clutter-backend-cogl.h"
#include "clutter-stage-cogl.h"
@ -67,8 +78,10 @@ static gdl_plane_id_t gdl_plane = GDL_PLANE_ID_UPP_C;
static guint gdl_n_buffers = CLUTTER_CEX100_TRIPLE_BUFFERING;
#endif
#ifdef COGL_HAS_X11_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
G_DEFINE_TYPE (ClutterBackendCogl, _clutter_backend_cogl, CLUTTER_TYPE_BACKEND_X11);
#elif defined(CLUTTER_WINDOWING_GDK)
G_DEFINE_TYPE (ClutterBackendCogl, _clutter_backend_cogl, CLUTTER_TYPE_BACKEND_GDK);
#else
G_DEFINE_TYPE (ClutterBackendCogl, _clutter_backend_cogl, CLUTTER_TYPE_BACKEND);
#endif
@ -87,7 +100,7 @@ clutter_backend_cogl_pre_parse (ClutterBackend *backend,
GError **error)
{
const gchar *env_string;
#ifdef COGL_HAS_X11_SUPPORT
#if defined(CLUTTER_WINDOWING_X11) || defined(CLUTTER_WINDOWING_GDK)
ClutterBackendClass *parent_class =
CLUTTER_BACKEND_CLASS (_clutter_backend_cogl_parent_class);
@ -109,7 +122,7 @@ static gboolean
clutter_backend_cogl_post_parse (ClutterBackend *backend,
GError **error)
{
#ifdef COGL_HAS_X11_SUPPORT
#if defined(CLUTTER_WINDOWING_X11) || defined(CLUTTER_WINDOWING_GDK)
ClutterBackendClass *parent_class =
CLUTTER_BACKEND_CLASS (_clutter_backend_cogl_parent_class);
@ -122,7 +135,7 @@ clutter_backend_cogl_post_parse (ClutterBackend *backend,
return TRUE;
}
#ifndef COGL_HAS_XLIB_SUPPORT
#if !(defined(CLUTTER_WINDOWING_X11) || defined(CLUTTER_WINDOWING_GDK))
static ClutterDeviceManager *
clutter_backend_cogl_get_device_manager (ClutterBackend *backend)
{
@ -140,7 +153,7 @@ clutter_backend_cogl_get_device_manager (ClutterBackend *backend)
return backend_cogl->device_manager;
}
#endif
#endif /* !(X11 || GDK) */
static void
clutter_backend_cogl_init_events (ClutterBackend *backend)
@ -152,8 +165,8 @@ clutter_backend_cogl_init_events (ClutterBackend *backend)
#ifdef HAVE_EVDEV
_clutter_events_evdev_init (CLUTTER_BACKEND (backend));
#endif
#ifdef COGL_HAS_X11_SUPPORT
/* Chain up to the X11 backend */
#if defined (CLUTTER_WINDOWING_X11) || defined (CLUTTER_WINDOWING_GDK)
/* Chain up to the X11 or GDK backend */
CLUTTER_BACKEND_CLASS (_clutter_backend_cogl_parent_class)->
init_events (backend);
#endif
@ -227,15 +240,15 @@ static ClutterFeatureFlags
clutter_backend_cogl_get_features (ClutterBackend *backend)
{
ClutterBackendCogl *backend_cogl = CLUTTER_BACKEND_COGL (backend);
#ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendClass *parent_class;
#endif
ClutterFeatureFlags flags = 0;
#ifdef COGL_HAS_XLIB_SUPPORT
parent_class = CLUTTER_BACKEND_CLASS (_clutter_backend_cogl_parent_class);
#if defined(CLUTTER_WINDOWING_X11) || defined(CLUTTER_WINDOWING_GDK)
{
ClutterBackendClass *parent_class;
parent_class = CLUTTER_BACKEND_CLASS (_clutter_backend_cogl_parent_class);
flags = parent_class->get_features (backend);
flags = parent_class->get_features (backend);
}
#endif
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN))
@ -272,7 +285,7 @@ clutter_backend_cogl_get_features (ClutterBackend *backend)
return flags;
}
#ifdef COGL_HAS_XLIB_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
static XVisualInfo *
clutter_backend_cogl_get_visual_info (ClutterBackendX11 *backend_x11)
{
@ -284,8 +297,10 @@ static gboolean
clutter_backend_cogl_create_context (ClutterBackend *backend,
GError **error)
{
#ifdef COGL_HAS_XLIB_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
#elif CLUTTER_WINDOWING_GDK
ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (backend);
#endif
CoglSwapChain *swap_chain = NULL;
CoglOnscreenTemplate *onscreen_template = NULL;
@ -295,17 +310,34 @@ clutter_backend_cogl_create_context (ClutterBackend *backend,
return TRUE;
backend->cogl_renderer = cogl_renderer_new ();
#ifdef COGL_HAS_XLIB_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
cogl_xlib_renderer_set_foreign_display (backend->cogl_renderer,
backend_x11->xdpy);
#elif defined(CLUTTER_WINDOWING_GDK)
#if defined(COGL_HAS_XLIB_SUPPORT) && defined(GDK_WINDOWING_X11)
if (GDK_IS_X11_DISPLAY (backend_gdk->display))
{
cogl_xlib_renderer_set_foreign_display (backend->cogl_renderer,
gdk_x11_display_get_xdisplay (backend_gdk->display));
}
else
#endif
{
g_warning ("Unsupported GdkDisplay type %s", G_OBJECT_TYPE_NAME (backend_gdk->display));
goto error;
}
#endif /* GDK */
if (!cogl_renderer_connect (backend->cogl_renderer, error))
goto error;
swap_chain = cogl_swap_chain_new ();
#ifdef COGL_HAS_XLIB_SUPPORT
#if defined(CLUTTER_WINDOWING_X11)
cogl_swap_chain_set_has_alpha (swap_chain,
clutter_x11_get_use_argb_visual ());
#elif defined(CLUTTER_WINDOWING_GDK)
cogl_swap_chain_set_has_alpha (swap_chain,
gdk_screen_get_rgba_visual (backend_gdk->screen) != NULL);
#endif
#ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT
@ -387,7 +419,7 @@ clutter_backend_cogl_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
#ifdef COGL_HAS_XLIB_SUPPORT
#if defined(CLUTTER_WINDOWING_X11)
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterEventTranslator *translator;
ClutterStageWindow *stage;
@ -408,7 +440,14 @@ clutter_backend_cogl_create_stage (ClutterBackend *backend,
backend_x11->xscreen_num,
(unsigned int) backend_x11->xwin_root);
#else /* COGL_HAS_XLIB_SUPPORT */
return stage;
#elif defined(CLUTTER_WINDOWING_GDK)
return g_object_new (CLUTTER_TYPE_STAGE_COGL,
"wrapper", wrapper,
"backend", backend,
NULL);
#else
ClutterBackendCogl *backend_cogl = CLUTTER_BACKEND_COGL (backend);
ClutterStageWindow *stage;
@ -431,9 +470,8 @@ clutter_backend_cogl_create_stage (ClutterBackend *backend,
backend_cogl->stage = stage;
#endif /* COGL_HAS_XLIB_SUPPORT */
return stage;
#endif /* CLUTTER_WINDOWING_X11 || CLUTTER_WINDOWING_GDK */
}
static void
@ -457,7 +495,7 @@ _clutter_backend_cogl_class_init (ClutterBackendCoglClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
#ifdef COGL_HAS_X11_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass);
#endif
@ -468,7 +506,7 @@ _clutter_backend_cogl_class_init (ClutterBackendCoglClass *klass)
backend_class->pre_parse = clutter_backend_cogl_pre_parse;
backend_class->post_parse = clutter_backend_cogl_post_parse;
backend_class->get_features = clutter_backend_cogl_get_features;
#ifndef COGL_HAS_XLIB_SUPPORT
#if !(defined(CLUTTER_WINDOWING_X11) || defined(CLUTTER_WINDOWING_GDK))
backend_class->get_device_manager = clutter_backend_cogl_get_device_manager;
#endif
backend_class->init_events = clutter_backend_cogl_init_events;
@ -476,7 +514,7 @@ _clutter_backend_cogl_class_init (ClutterBackendCoglClass *klass)
backend_class->create_context = clutter_backend_cogl_create_context;
backend_class->ensure_context = clutter_backend_cogl_ensure_context;
#ifdef COGL_HAS_XLIB_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
backendx11_class->get_visual_info = clutter_backend_cogl_get_visual_info;
#endif
}

View File

@ -37,9 +37,12 @@
#include "clutter-backend-private.h"
#ifdef COGL_HAS_X11_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
#include "../x11/clutter-backend-x11.h"
#endif
#ifdef CLUTTER_WINDOWING_GDK
#include "../gdk/clutter-backend-gdk.h"
#endif
G_BEGIN_DECLS
@ -55,10 +58,13 @@ typedef struct _ClutterBackendCoglClass ClutterBackendCoglClass;
struct _ClutterBackendCogl
{
#ifdef COGL_HAS_XLIB_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
ClutterBackendX11 parent_instance;
#else /* COGL_HAS_X11_SUPPORT */
#elif defined(CLUTTER_WINDOWING_GDK)
ClutterBackendGdk parent_instance;
#else
ClutterBackend parent_instance;
/* main stage singleton */
@ -73,7 +79,7 @@ struct _ClutterBackendCogl
/* event timer */
GTimer *event_timer;
#endif /* COGL_HAS_X11_SUPPORT */
#endif /* CLUTTER_WINDOWING_X11 || CLUTTER_WINDOWING_GDK */
CoglContext *cogl_context;
@ -82,8 +88,10 @@ struct _ClutterBackendCogl
struct _ClutterBackendCoglClass
{
#ifdef COGL_HAS_XLIB_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
ClutterBackendX11Class parent_class;
#elif defined(CLUTTER_WINDOWING_GDK)
ClutterBackendGdkClass parent_class;
#else
ClutterBackendClass parent_class;
#endif

View File

@ -30,6 +30,17 @@
#include "config.h"
#endif
#include "clutter-config.h"
#ifdef CLUTTER_WINDOWING_GDK
#include <gdk/gdk.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#endif
#include "clutter-stage-cogl.h"
#include "clutter-backend-cogl.h"
@ -43,7 +54,7 @@
#include "clutter-stage-private.h"
#include "clutter-util.h"
#ifdef COGL_HAS_X11_SUPPORT
#if defined(CLUTTER_WINDOWING_X11) || defined(CLUTTER_WINDOWING_GDK)
static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
#endif
@ -51,8 +62,10 @@ static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageCogl,
_clutter_stage_cogl,
#ifdef COGL_HAS_X11_SUPPORT
#if defined(CLUTTER_WINDOWING_X11)
CLUTTER_TYPE_STAGE_X11,
#elif defined(CLUTTER_WINDOWING_GDK)
CLUTTER_TYPE_STAGE_GDK,
#else
G_TYPE_OBJECT,
#endif
@ -66,7 +79,7 @@ clutter_stage_cogl_unrealize (ClutterStageWindow *stage_window)
CLUTTER_NOTE (BACKEND, "Unrealizing Cogl stage [%p]", stage_cogl);
#ifdef COGL_HAS_XLIB_SUPPORT
#if defined(CLUTTER_WINDOWING_X11) || defined(CLUTTER_WINDOWING_GDK)
/* chain up to the StageX11 implementation */
clutter_stage_window_parent_iface->unrealize (stage_window);
#endif
@ -101,8 +114,10 @@ static gboolean
clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
#ifdef COGL_HAS_XLIB_SUPPORT
#if defined(CLUTTER_WINDOWING_X11)
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
#elif defined(CLUTTER_WINDOWING_GDK)
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
#endif
ClutterBackend *backend;
CoglFramebuffer *framebuffer;
@ -115,16 +130,25 @@ clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
G_OBJECT_TYPE_NAME (stage_cogl),
stage_cogl);
#if defined(CLUTTER_WINDOWING_GDK)
/* we need to chain early to parent in the Gdk case, as the X window
must be created by GDK, not Cogl */
if (!clutter_stage_window_parent_iface->realize (stage_window))
return FALSE;
#endif
backend = clutter_get_default_backend ();
#ifdef COGL_HAS_XLIB_SUPPORT
#if defined(CLUTTER_WINDOWING_X11)
clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper), &width, &height);
#elif defined(CLUTTER_WINDOWING_GDK)
clutter_actor_get_size (CLUTTER_ACTOR (stage_gdk->wrapper), &width, &height);
#endif
stage_cogl->onscreen = cogl_onscreen_new (backend->cogl_context,
width, height);
#ifdef COGL_HAS_XLIB_SUPPORT
#if defined(CLUTTER_WINDOWING_X11)
if (stage_x11->xwin != None)
{
cogl_x11_onscreen_set_foreign_window_xid (stage_cogl->onscreen,
@ -133,6 +157,24 @@ clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
stage_x11);
}
#elif defined(CLUTTER_WINDOWING_GDK)
#if defined(COGL_HAS_XLIB_SUPPORT) && defined(GDK_WINDOWING_X11)
if (GDK_IS_X11_WINDOW (stage_gdk->window))
{
cogl_x11_onscreen_set_foreign_window_xid (stage_cogl->onscreen,
gdk_x11_window_get_xid (stage_gdk->window),
_clutter_stage_gdk_update_foreign_event_mask,
stage_gdk);
}
else
#endif
{
g_warning ("Unsupported GdkWindow type %s", G_OBJECT_TYPE_NAME (stage_gdk->window));
cogl_object_unref (stage_cogl->onscreen);
stage_cogl->onscreen = NULL;
return FALSE;
}
#endif
clutter_vblank = _clutter_backend_cogl_get_vblank ();
@ -161,7 +203,7 @@ clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
stage_cogl);
}
#ifdef COGL_HAS_XLIB_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
if (stage_x11->xwin == None)
stage_x11->xwin = cogl_x11_onscreen_get_window_xid (stage_cogl->onscreen);
@ -179,7 +221,7 @@ clutter_stage_cogl_get_pending_swaps (ClutterStageWindow *stage_window)
return stage_cogl->pending_swaps;
}
#ifndef COGL_HAS_XLIB_SUPPORT
#if !(defined(CLUTTER_WINDOWING_X11) || defined(CLUTTER_WINDOWING_GDK))
static ClutterActor *
clutter_stage_cogl_get_wrapper (ClutterStageWindow *stage_window)
@ -238,7 +280,7 @@ clutter_stage_cogl_resize (ClutterStageWindow *stage_window,
{
}
#endif /* COGL_HAS_XLIB_SUPPORT */
#endif /* X11 || GDK */
static gboolean
clutter_stage_cogl_has_redraw_clips (ClutterStageWindow *stage_window)
@ -368,10 +410,14 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
"The time spent in blit_sub_buffer",
0 /* no application private data */);
#ifdef COGL_HAS_X11_SUPPORT
#if defined(CLUTTER_WINDOWING_X11)
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_cogl);
wrapper = CLUTTER_ACTOR (stage_x11->wrapper);
#elif defined(CLUTTER_WINDOWING_GDK)
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_cogl);
wrapper = CLUTTER_ACTOR (stage_gdk->wrapper);
#else
wrapper = CLUTTER_ACTOR (stage_cogl->wrapper);
#endif
@ -390,7 +436,7 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
/* some drivers struggle to get going and produce some junk
* frames when starting up... */
G_LIKELY (stage_cogl->frame_count > 3)
#ifdef COGL_HAS_X11_SUPPORT
#if defined(CLUTTER_WINDOWING_X11)
/* While resizing a window clipped redraws are disabled to avoid
* artefacts. See clutter-event-x11.c:event_translate for a
* detailed explanation */
@ -564,7 +610,7 @@ clutter_stage_cogl_get_active_framebuffer (ClutterStageWindow *stage_window)
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{
#ifdef COGL_HAS_X11_SUPPORT
#if defined(CLUTTER_WINDOWING_X11) || defined(CLUTTER_WINDOWING_GDK)
clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface);
iface->realize = clutter_stage_cogl_realize;

View File

@ -13,8 +13,14 @@
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#endif
#ifdef CLUTTER_WINDOWING_X11
#include "../x11/clutter-stage-x11.h"
#endif
#ifdef CLUTTER_WINDOWING_GDK
#include "../gdk/clutter-stage-gdk.h"
#endif
#include "clutter-backend-cogl.h"
@ -32,12 +38,13 @@ typedef struct _ClutterStageCoglClass ClutterStageCoglClass;
struct _ClutterStageCogl
{
#ifdef COGL_HAS_X11_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
ClutterStageX11 parent_instance;
#else
#elif defined(CLUTTER_WINDOWING_GDK)
ClutterStageGdk parent_instance;
#else
GObject parent_instance;
/* the stage wrapper */
@ -69,9 +76,9 @@ struct _ClutterStageCogl
struct _ClutterStageCoglClass
{
#ifdef COGL_HAS_X11_SUPPORT
#ifdef CLUTTER_WINDOWING_X11
ClutterStageX11Class parent_class;
#else
#elif defined(CLUTTER_WINDOWING_GDK)
GObjectClass parent_class;
#endif
};

View File

@ -0,0 +1,32 @@
/* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* 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/>.
*
*
*/
#ifndef __CLUTTER_BACKEND_PRIVATE_X11_H__
#define __CLUTTER_BACKEND_PRIVATE_X11_H__
G_BEGIN_DECLS
void _clutter_backend_x11_events_init (ClutterBackend *backend);
void _clutter_backend_x11_events_uninit (ClutterBackend *backend);
G_END_DECLS
#endif

View File

@ -0,0 +1,368 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* 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/>.
*
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib/gi18n-lib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <gdk/gdk.h>
#include <cogl/cogl.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
/* other backends not yet supported */
#include "clutter-backend-gdk.h"
#include "clutter-device-manager-gdk.h"
#include "clutter-settings-gdk.h"
#include "clutter-stage-gdk.h"
#include "clutter-gdk.h"
#include "clutter-backend.h"
#include "clutter-debug.h"
#include "clutter-device-manager-private.h"
#include "clutter-event-private.h"
#include "clutter-main.h"
#include "clutter-private.h"
#define clutter_backend_gdk_get_type _clutter_backend_gdk_get_type
G_DEFINE_TYPE (ClutterBackendGdk, clutter_backend_gdk, CLUTTER_TYPE_BACKEND);
/* singleton object */
static ClutterBackendGdk *backend_singleton = NULL;
/* global for pre init setup calls */
static GdkDisplay *_foreign_dpy = NULL;
static void
clutter_backend_gdk_init_settings (ClutterBackendGdk *backend_gdk)
{
ClutterSettings *settings = clutter_settings_get_default ();
int i;
for (i = 0; i < G_N_ELEMENTS (_clutter_settings_map); i++)
{
GValue val = G_VALUE_INIT;
g_value_init (&val, CLUTTER_SETTING_TYPE(i));
gdk_screen_get_setting (backend_gdk->screen,
CLUTTER_SETTING_GDK_NAME(i),
&val);
g_object_set_property (G_OBJECT (settings),
CLUTTER_SETTING_PROPERTY(i),
&val);
g_value_unset (&val);
}
}
void
_clutter_backend_gdk_update_setting (ClutterBackendGdk *backend_gdk,
const gchar *setting_name)
{
ClutterSettings *settings = clutter_settings_get_default ();
int i;
for (i = 0; i < G_N_ELEMENTS (_clutter_settings_map); i++)
{
if (g_strcmp0 (CLUTTER_SETTING_GDK_NAME (i), setting_name) == 0)
{
GValue val = G_VALUE_INIT;
g_value_init (&val, CLUTTER_SETTING_TYPE (i));
gdk_screen_get_setting (backend_gdk->screen,
CLUTTER_SETTING_GDK_NAME (i),
&val);
g_object_set_property (G_OBJECT (settings),
CLUTTER_SETTING_PROPERTY (i),
&val);
g_value_unset (&val);
break;
}
}
}
static GdkFilterReturn
cogl_gdk_filter (GdkXEvent *xevent,
GdkEvent *event,
gpointer data)
{
#ifdef GDK_WINDOWING_X11
CoglFilterReturn ret;
ret = cogl_xlib_handle_event ((XEvent*)xevent);
switch (ret)
{
case COGL_FILTER_REMOVE:
return GDK_FILTER_REMOVE;
case COGL_FILTER_CONTINUE:
default:
return GDK_FILTER_CONTINUE;
}
#endif
}
static gboolean
_clutter_backend_gdk_pre_parse (ClutterBackend *backend,
GError **error)
{
/* nothing to do here */
return TRUE;
}
static gboolean
_clutter_backend_gdk_post_parse (ClutterBackend *backend,
GError **error)
{
ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (backend);
if (_foreign_dpy)
backend_gdk->display = _foreign_dpy;
/* Init Gdk, if outside code did not already */
if (!gdk_init_check (NULL, NULL))
return FALSE;
/*
* Only open connection if not already set by prior call to
* clutter_gdk_set_display()
*/
if (backend_gdk->display == NULL)
backend_gdk->display = g_object_ref (gdk_display_get_default ());
g_assert (backend_gdk->display != NULL);
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY (backend_gdk->display))
{
/* Cogl needs to know the Xlib display connection for
CoglTexturePixmapX11 */
cogl_xlib_set_display (gdk_x11_display_get_xdisplay (backend_gdk->display));
}
#endif
backend_gdk->screen = gdk_display_get_default_screen (backend_gdk->display);
/* add event filter for Cogl events */
gdk_window_add_filter (NULL, cogl_gdk_filter, NULL);
clutter_backend_gdk_init_settings (backend_gdk);
CLUTTER_NOTE (BACKEND,
"Gdk Display '%s' opened",
gdk_display_get_name (backend_gdk->display));
return TRUE;
}
static void
clutter_backend_gdk_init_events (ClutterBackend *backend)
{
CLUTTER_NOTE (EVENT, "initialising the event loop");
_clutter_backend_gdk_events_init (backend);
}
static void
clutter_backend_gdk_finalize (GObject *gobject)
{
ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (gobject);
gdk_window_remove_filter (NULL, cogl_gdk_filter, NULL);
g_object_unref (backend_gdk->display);
if (backend_singleton)
backend_singleton = NULL;
G_OBJECT_CLASS (clutter_backend_gdk_parent_class)->finalize (gobject);
}
static void
clutter_backend_gdk_dispose (GObject *gobject)
{
ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (gobject);
ClutterStageManager *stage_manager;
CLUTTER_NOTE (BACKEND, "Disposing the of stages");
stage_manager = clutter_stage_manager_get_default ();
g_object_unref (stage_manager);
CLUTTER_NOTE (BACKEND, "Removing the event source");
_clutter_backend_gdk_events_uninit (CLUTTER_BACKEND (backend_gdk));
G_OBJECT_CLASS (clutter_backend_gdk_parent_class)->dispose (gobject);
}
static GObject *
clutter_backend_gdk_constructor (GType gtype,
guint n_params,
GObjectConstructParam *params)
{
GObjectClass *parent_class;
GObject *retval;
if (backend_singleton == NULL)
{
parent_class = G_OBJECT_CLASS (clutter_backend_gdk_parent_class);
retval = parent_class->constructor (gtype, n_params, params);
backend_singleton = CLUTTER_BACKEND_GDK (retval);
return retval;
}
g_critical ("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_gdk_get_features (ClutterBackend *backend)
{
return CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR;
}
static void
clutter_backend_gdk_copy_event_data (ClutterBackend *backend,
const ClutterEvent *src,
ClutterEvent *dest)
{
GdkEvent *gdk_event;
gdk_event = _clutter_event_get_platform_data (src);
if (gdk_event != NULL)
_clutter_event_set_platform_data (dest, gdk_event_copy (gdk_event));
}
static void
clutter_backend_gdk_free_event_data (ClutterBackend *backend,
ClutterEvent *event)
{
GdkEvent *gdk_event;
gdk_event = _clutter_event_get_platform_data (event);
if (gdk_event != NULL)
gdk_event_free (gdk_event);
}
static ClutterDeviceManager *
clutter_backend_gdk_get_device_manager (ClutterBackend *backend)
{
ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (backend);
if (G_UNLIKELY (backend_gdk->device_manager == NULL))
{
backend_gdk->device_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_GDK,
"backend", backend_gdk,
"gdk-display", backend_gdk->display,
NULL);
}
return backend_gdk->device_manager;
}
static void
clutter_backend_gdk_class_init (ClutterBackendGdkClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
gobject_class->constructor = clutter_backend_gdk_constructor;
gobject_class->dispose = clutter_backend_gdk_dispose;
gobject_class->finalize = clutter_backend_gdk_finalize;
backend_class->pre_parse = _clutter_backend_gdk_pre_parse;
backend_class->post_parse = _clutter_backend_gdk_post_parse;
backend_class->init_events = clutter_backend_gdk_init_events;
backend_class->get_features = clutter_backend_gdk_get_features;
backend_class->get_device_manager = clutter_backend_gdk_get_device_manager;
backend_class->copy_event_data = clutter_backend_gdk_copy_event_data;
backend_class->free_event_data = clutter_backend_gdk_free_event_data;
}
static void
clutter_backend_gdk_init (ClutterBackendGdk *backend_gdk)
{
/* nothing to do here */
}
/**
* clutter_gdk_get_default_display:
*
* Retrieves the pointer to the default display.
*
* Return value: (transfer none): the default display
*
* Since: 0.6
*/
GdkDisplay *
clutter_gdk_get_default_display (void)
{
if (!backend_singleton)
{
g_critical ("GDK backend has not been initialised");
return NULL;
}
return backend_singleton->display;
}
/**
* clutter_gdk_set_display:
* @display: pointer to a GDK display connection.
*
* Sets the display connection Clutter should use; must be called
* before clutter_init(), clutter_init_with_args() or other functions
* pertaining Clutter's initialization process.
*
* If you are parsing the command line arguments by retrieving Clutter's
* #GOptionGroup with clutter_get_option_group() and calling
* g_option_context_parse() yourself, you should also call
* clutter_gdk_set_display() before g_option_context_parse().
*
* Since: 0.8
*/
void
clutter_gdk_set_display (GdkDisplay *display)
{
if (_clutter_context_is_initialized ())
{
g_warning ("%s() can only be used before calling clutter_init()",
G_STRFUNC);
return;
}
_foreign_dpy = g_object_ref (display);
}

View File

@ -0,0 +1,72 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
* 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
*
* 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/>.
*
*
*/
#ifndef __CLUTTER_BACKEND_GDK_H__
#define __CLUTTER_BACKEND_GDK_H__
#include <glib-object.h>
#include <clutter/clutter-event.h>
#include <gdk/gdk.h>
#include "clutter-gdk.h"
#include "clutter-backend-private.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_BACKEND_GDK (_clutter_backend_gdk_get_type ())
#define CLUTTER_BACKEND_GDK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_GDK, ClutterBackendGdk))
#define CLUTTER_IS_BACKEND_GDK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_GDK))
#define CLUTTER_BACKEND_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_GDK, ClutterBackendGdkClass))
#define CLUTTER_IS_BACKEND_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_GDK))
#define CLUTTER_BACKEND_GDK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_GDK, ClutterBackendGdkClass))
typedef struct _ClutterBackendGdk ClutterBackendGdk;
typedef struct _ClutterBackendGdkClass ClutterBackendGdkClass;
struct _ClutterBackendGdk
{
ClutterBackend parent_instance;
GdkDisplay *display;
GdkScreen *screen;
ClutterDeviceManager *device_manager;
};
struct _ClutterBackendGdkClass
{
ClutterBackendClass parent_class;
/* nothing here, for now */
};
GType _clutter_backend_gdk_get_type (void) G_GNUC_CONST;
void _clutter_backend_gdk_events_init (ClutterBackend *backend);
void _clutter_backend_gdk_events_uninit (ClutterBackend *backend);
void _clutter_backend_gdk_update_setting (ClutterBackendGdk *backend, const gchar *name);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_GDK_H__ */

View File

@ -0,0 +1,249 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright © 2011 Intel Corp.
* 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
*
* 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/>.
*
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
*/
#include "config.h"
#include <stdint.h>
#include "clutter-device-manager-gdk.h"
#include "clutter-backend-gdk.h"
#include "clutter-input-device-gdk.h"
#include "clutter-stage-gdk.h"
#include "clutter-backend.h"
#include "clutter-debug.h"
#include "clutter-device-manager-private.h"
#include "clutter-event-private.h"
#include "clutter-event-translator.h"
#include "clutter-stage-private.h"
#include "clutter-private.h"
#define clutter_device_manager_gdk_get_type _clutter_device_manager_gdk_get_type
G_DEFINE_TYPE (ClutterDeviceManagerGdk, clutter_device_manager_gdk, CLUTTER_TYPE_DEVICE_MANAGER)
enum {
PROP_0,
PROP_GDK_DISPLAY,
PROP_LAST
};
ClutterInputDevice *
_clutter_device_manager_gdk_lookup_device (ClutterDeviceManager *manager,
GdkDevice *device)
{
ClutterDeviceManagerGdk *manager_gdk = CLUTTER_DEVICE_MANAGER_GDK (manager);
ClutterInputDevice *clutter_device;
clutter_device = g_object_get_data (G_OBJECT (device), "clutter-device");
if (clutter_device != NULL)
return clutter_device;
clutter_device = _clutter_input_device_gdk_new (manager, device);
g_object_set_data_full (G_OBJECT (device), "clutter-device", clutter_device, g_object_unref);
manager_gdk->device_cache = g_slist_prepend (manager_gdk->device_cache, g_object_ref (clutter_device));
g_hash_table_replace (manager_gdk->device_by_id,
GINT_TO_POINTER (clutter_input_device_get_device_id (clutter_device)),
g_object_ref (clutter_device));
return clutter_device;
}
static void
clutter_device_manager_gdk_add_device (ClutterDeviceManager *manager,
ClutterInputDevice *device)
{
/* XXX implement */
}
static void
clutter_device_manager_gdk_remove_device (ClutterDeviceManager *manager,
ClutterInputDevice *device)
{
/* XXX implement */
}
static const GSList *
clutter_device_manager_gdk_get_devices (ClutterDeviceManager *manager)
{
ClutterDeviceManagerGdk *manager_gdk = CLUTTER_DEVICE_MANAGER_GDK (manager);
return manager_gdk->device_cache;
}
static ClutterInputDevice *
clutter_device_manager_gdk_get_device (ClutterDeviceManager *manager,
gint id)
{
ClutterDeviceManagerGdk *manager_gdk = CLUTTER_DEVICE_MANAGER_GDK (manager);
return g_hash_table_lookup (manager_gdk->device_by_id, GINT_TO_POINTER (id));
}
static ClutterInputDevice *
clutter_device_manager_gdk_get_core_device (ClutterDeviceManager *manager,
ClutterInputDeviceType device_type)
{
ClutterDeviceManagerGdk *manager_gdk = CLUTTER_DEVICE_MANAGER_GDK (manager);
GdkDevice *gdk_device;
gdk_device = gdk_device_manager_get_client_pointer (manager_gdk->device_manager);
g_assert (gdk_device != NULL);
if (device_type == CLUTTER_KEYBOARD_DEVICE)
gdk_device = gdk_device_get_associated_device (gdk_device);
else if (device_type != CLUTTER_POINTER_DEVICE)
return NULL;
return _clutter_device_manager_gdk_lookup_device (manager, gdk_device);
}
static void
gdk_device_added (GdkDeviceManager *gdk_manager,
GdkDevice *device,
ClutterDeviceManager *self)
{
/* this will do the right thing if the device is not there */
ClutterInputDevice *clutter_device = _clutter_device_manager_gdk_lookup_device (self, device);
_clutter_device_manager_add_device (self, clutter_device);
}
static void
gdk_device_removed (GdkDeviceManager *gdk_manager,
GdkDevice *device,
ClutterDeviceManagerGdk *self)
{
ClutterInputDevice *clutter_device = g_object_get_data (G_OBJECT (device), "clutter-device");
if (clutter_device == NULL)
return;
self->device_cache = g_slist_remove (self->device_cache, clutter_device);
g_object_unref (clutter_device);
g_hash_table_remove (self->device_by_id,
GINT_TO_POINTER (clutter_input_device_get_device_id (clutter_device)));
_clutter_device_manager_remove_device (CLUTTER_DEVICE_MANAGER (self), clutter_device);
}
static void
gdk_device_foreach_cb (gpointer data,
gpointer user_data)
{
_clutter_device_manager_gdk_lookup_device (user_data, data);
}
static void
clutter_device_manager_gdk_constructed (GObject *gobject)
{
ClutterDeviceManagerGdk *manager_gdk = CLUTTER_DEVICE_MANAGER_GDK (gobject);
GList *all_devices;
g_assert (manager_gdk->device_manager != NULL);
all_devices = gdk_device_manager_list_devices (manager_gdk->device_manager,
GDK_DEVICE_TYPE_MASTER);
g_list_foreach (all_devices, gdk_device_foreach_cb, manager_gdk);
g_list_free (all_devices);
all_devices = gdk_device_manager_list_devices (manager_gdk->device_manager,
GDK_DEVICE_TYPE_SLAVE);
g_list_foreach (all_devices, gdk_device_foreach_cb, manager_gdk);
g_list_free (all_devices);
all_devices = gdk_device_manager_list_devices (manager_gdk->device_manager,
GDK_DEVICE_TYPE_FLOATING);
g_list_foreach (all_devices, gdk_device_foreach_cb, manager_gdk);
g_list_free (all_devices);
g_object_connect (manager_gdk->device_manager,
"object-signal::device-added", gdk_device_added, gobject,
"object-signal::device-removed", gdk_device_removed, gobject,
NULL);
if (G_OBJECT_CLASS (clutter_device_manager_gdk_parent_class)->constructed)
G_OBJECT_CLASS (clutter_device_manager_gdk_parent_class)->constructed (gobject);
}
static void
clutter_device_manager_gdk_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterDeviceManagerGdk *manager_gdk = CLUTTER_DEVICE_MANAGER_GDK (gobject);
GdkDisplay *gdk_display;
switch (prop_id)
{
case PROP_GDK_DISPLAY:
gdk_display = GDK_DISPLAY (g_value_get_object (value));
manager_gdk->device_manager = gdk_display_get_device_manager (gdk_display);
g_object_ref (manager_gdk->device_manager);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_device_manager_gdk_class_init (ClutterDeviceManagerGdkClass *klass)
{
ClutterDeviceManagerClass *manager_class;
GObjectClass *gobject_class;
GParamSpec *pspec;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructed = clutter_device_manager_gdk_constructed;
gobject_class->set_property = clutter_device_manager_gdk_set_property;
manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass);
manager_class->add_device = clutter_device_manager_gdk_add_device;
manager_class->remove_device = clutter_device_manager_gdk_remove_device;
manager_class->get_devices = clutter_device_manager_gdk_get_devices;
manager_class->get_core_device = clutter_device_manager_gdk_get_core_device;
manager_class->get_device = clutter_device_manager_gdk_get_device;
pspec = g_param_spec_object ("gdk-display",
"GdkDisplay",
"The GDK display",
GDK_TYPE_DISPLAY,
CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (gobject_class, PROP_GDK_DISPLAY, pspec);
}
static void
clutter_device_manager_gdk_init (ClutterDeviceManagerGdk *self)
{
self->device_by_id = g_hash_table_new_full (NULL, NULL,
NULL, (GDestroyNotify) g_object_unref);
}

View File

@ -0,0 +1,63 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright © 2011 Intel Corp.
*
* 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/>.
*
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
*/
#ifndef __CLUTTER_DEVICE_MANAGER_GDK_H__
#define __CLUTTER_DEVICE_MANAGER_GDK_H__
#include <clutter/clutter-device-manager.h>
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_DEVICE_MANAGER_GDK (_clutter_device_manager_gdk_get_type ())
#define CLUTTER_DEVICE_MANAGER_GDK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER_GDK, ClutterDeviceManagerGdk))
#define CLUTTER_IS_DEVICE_MANAGER_GDK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER_GDK))
#define CLUTTER_DEVICE_MANAGER_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER_GDK, ClutterDeviceManagerGdkClass))
#define CLUTTER_IS_DEVICE_MANAGER_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER_GDK))
#define CLUTTER_DEVICE_MANAGER_GDK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER_GDK, ClutterDeviceManagerGdkClass))
typedef struct _ClutterDeviceManagerGdk ClutterDeviceManagerGdk;
typedef struct _ClutterDeviceManagerGdkClass ClutterDeviceManagerGdkClass;
struct _ClutterDeviceManagerGdk
{
ClutterDeviceManager parent_instance;
GdkDeviceManager *device_manager;
GSList *device_cache;
GHashTable *device_by_id;
};
struct _ClutterDeviceManagerGdkClass
{
ClutterDeviceManagerClass parent_class;
};
GType _clutter_device_manager_gdk_get_type (void) G_GNUC_CONST;
ClutterInputDevice * _clutter_device_manager_gdk_lookup_device (ClutterDeviceManager *manager,
GdkDevice *device);
G_END_DECLS
#endif /* __CLUTTER_DEVICE_MANAGER_GDK_H__ */

View File

@ -0,0 +1,264 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
* Copyright (C) 2009, 2010 Intel Corp.
* 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
*
* 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/>.
*
*
*
* Authored by:
* Matthew Allum <mallum@openedhand.com>
* Emmanuele Bassi <ebassi@linux.intel.com>
*/
#include "config.h"
#include "clutter-gdk.h"
#include "clutter-backend-gdk.h"
#include "clutter-device-manager-gdk.h"
#include "clutter-debug.h"
#include "clutter-main.h"
#include "clutter-backend-private.h"
#include "clutter-event-private.h"
#include "clutter-stage-private.h"
#include <string.h>
#include <glib.h>
static void
gdk_event_handler (GdkEvent *event,
gpointer user_data)
{
clutter_gdk_handle_event (event);
}
void
_clutter_backend_gdk_events_init (ClutterBackend *backend)
{
gdk_event_handler_set (gdk_event_handler, NULL, NULL);
CLUTTER_NOTE (EVENT, "GDK event handler set");
}
void
_clutter_backend_gdk_events_uninit (ClutterBackend *backend)
{
gdk_event_handler_set (NULL, NULL, NULL);
}
/**
* clutter_gdk_handle_event:
* @event: a #GdkEvent
*
* This function processes a single GDK event; it can be used to hook
* into external event processing
*
* Return value: #GdkFilterReturn. %GDK_FILTER_REMOVE indicates that
* Clutter has internally handled the event and the caller should do
* no further processing. %GDK_FILTER_CONTINUE indicates that Clutter
* is either not interested in the event, or has used the event to
* update internal state without taking any exclusive action.
* %GDK_FILTER_TRANSLATE will not occur.
*
*/
GdkFilterReturn
clutter_gdk_handle_event (GdkEvent *gdk_event)
{
ClutterDeviceManager *device_manager;
ClutterBackendGdk *backend_gdk;
ClutterStage *stage = NULL;
ClutterEvent *event = NULL;
gint spin = 0;
GdkFilterReturn result = GDK_FILTER_CONTINUE;
if (gdk_event->any.window == NULL)
return GDK_FILTER_CONTINUE;
clutter_threads_enter ();
backend_gdk = CLUTTER_BACKEND_GDK (clutter_get_default_backend ());
stage = clutter_gdk_get_stage_from_window (gdk_event->any.window);
device_manager = clutter_device_manager_get_default ();
if (stage == NULL)
goto out;
switch (gdk_event->type) {
case GDK_DELETE:
event = clutter_event_new (CLUTTER_DELETE);
break;
case GDK_DESTROY:
event = clutter_event_new (CLUTTER_DESTROY_NOTIFY);
break;
case GDK_EXPOSE:
clutter_redraw (stage);
break;
case GDK_DAMAGE:
/* This is handled by cogl */
goto out;
case GDK_MOTION_NOTIFY:
event = clutter_event_new (CLUTTER_MOTION);
event->motion.time = gdk_event->motion.time;
event->motion.x = gdk_event->motion.x;
event->motion.y = gdk_event->motion.y;
event->motion.axes = NULL;
/* It's all X in the end, right? */
event->motion.modifier_state = gdk_event->motion.state;
event->motion.device = _clutter_device_manager_gdk_lookup_device (device_manager,
gdk_event->motion.device);
break;
case GDK_BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
event = clutter_event_new (gdk_event->type == GDK_BUTTON_PRESS ?
CLUTTER_BUTTON_PRESS :
CLUTTER_BUTTON_RELEASE);
event->button.time = gdk_event->button.time;
event->button.x = gdk_event->button.x;
event->button.y = gdk_event->button.y;
event->button.axes = NULL;
event->button.modifier_state = gdk_event->button.state;
event->button.button = gdk_event->button.button;
event->button.click_count = 1;
event->button.device = _clutter_device_manager_gdk_lookup_device (device_manager,
gdk_event->button.device);
break;
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
/* these are handled by clutter-main.c updating click_count */
goto out;
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
event = clutter_event_new (gdk_event->type == GDK_KEY_PRESS ?
CLUTTER_KEY_PRESS :
CLUTTER_KEY_RELEASE);
event->key.time = gdk_event->key.time;
event->key.modifier_state = gdk_event->key.state;
event->key.keyval = gdk_event->key.keyval;
event->key.hardware_keycode = gdk_event->key.hardware_keycode;
event->key.unicode_value = g_utf8_get_char (gdk_event->key.string);
break;
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
event = clutter_event_new (gdk_event->type == GDK_ENTER_NOTIFY ?
CLUTTER_ENTER :
CLUTTER_LEAVE);
event->crossing.source = CLUTTER_ACTOR (stage);
event->crossing.time = gdk_event->crossing.time;
event->crossing.x = gdk_event->crossing.x;
event->crossing.y = gdk_event->crossing.y;
/* XXX: no better fallback here? */
event->crossing.device = clutter_device_manager_get_core_device (device_manager,
CLUTTER_POINTER_DEVICE);
if (gdk_event->type == GDK_ENTER_NOTIFY)
_clutter_stage_add_device (stage, event->crossing.device);
else
_clutter_stage_remove_device (stage, event->crossing.device);
break;
case GDK_FOCUS_CHANGE:
event = clutter_event_new (CLUTTER_STAGE_STATE);
event->stage_state.time = 0; /* XXX: there is no timestamp in this GdkEvent */
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
event->stage_state.new_state = gdk_event->focus_change.in ? CLUTTER_STAGE_STATE_ACTIVATED : 0;
break;
case GDK_CONFIGURE:
clutter_actor_set_size (CLUTTER_ACTOR (stage),
gdk_event->configure.width,
gdk_event->configure.height);
break;
case GDK_SCROLL:
event = clutter_event_new (CLUTTER_SCROLL);
event->scroll.time = gdk_event->scroll.time;
event->scroll.x = gdk_event->scroll.x;
event->scroll.y = gdk_event->scroll.y;
event->scroll.modifier_state = gdk_event->scroll.state;
event->scroll.axes = NULL;
event->scroll.direction = gdk_event->scroll.direction;
event->scroll.device = _clutter_device_manager_gdk_lookup_device (device_manager,
gdk_event->scroll.device);
case GDK_WINDOW_STATE:
event = clutter_event_new (CLUTTER_STAGE_STATE);
event->stage_state.changed_mask = 0;
event->stage_state.new_state = 0;
if (gdk_event->window_state.changed_mask & GDK_WINDOW_STATE_WITHDRAWN)
{
event->stage_state.changed_mask |= CLUTTER_STAGE_STATE_OFFSCREEN;
event->stage_state.new_state |= (gdk_event->window_state.new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ?
CLUTTER_STAGE_STATE_OFFSCREEN : 0;
}
if (gdk_event->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
{
event->stage_state.changed_mask |= CLUTTER_STAGE_STATE_FULLSCREEN;
event->stage_state.new_state |= (gdk_event->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ?
CLUTTER_STAGE_STATE_FULLSCREEN : 0;
}
break;
case GDK_SETTING:
_clutter_backend_gdk_update_setting (backend_gdk, gdk_event->setting.name);
break;
default:
break;
}
if (event != NULL)
{
event->any.stage = stage;
if (gdk_event->any.send_event)
event->any.flags = CLUTTER_EVENT_FLAG_SYNTHETIC;
_clutter_event_push (event, FALSE);
spin = 1;
CLUTTER_NOTE (EVENT, "Translated one event from Gdk");
/* handle also synthetic enter/leave events */
if (event->type == CLUTTER_MOTION)
spin += 2;
while (spin > 0 && (event = clutter_event_get ()))
{
/* forward the event into clutter for emission etc. */
clutter_do_event (event);
clutter_event_free (event);
--spin;
}
result = GDK_FILTER_REMOVE;
}
out:
clutter_threads_leave ();
return result;
}

55
clutter/gdk/clutter-gdk.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* 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/>.
*
*
*/
/**
* SECTION:clutter-gdk
* @short_description: GDK specific API
*
* The GDK backend for Clutter provides some specific API, allowing
* integration with the GDK API for manipulating the stage window and
* handling events outside of Clutter.
*/
#ifndef __CLUTTER_GDK_H__
#define __CLUTTER_GDK_H__
#include <glib.h>
#include <gdk/gdk.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
void clutter_gdk_set_display (GdkDisplay *display);
GdkWindow *clutter_gdk_get_stage_window (ClutterStage *stage);
gboolean clutter_gdk_set_stage_foreign (ClutterStage *stage,
GdkWindow *window);
GdkFilterReturn clutter_gdk_handle_event (GdkEvent *event);
ClutterStage *clutter_gdk_get_stage_from_window (GdkWindow *window);
G_END_DECLS
#endif /* __CLUTTER_GDK_H__ */

View File

@ -0,0 +1,160 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright © 2011 Intel Corp.
* 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
*
* 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/>.
*
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
*/
#include "config.h"
#include "clutter-input-device-gdk.h"
#include "clutter-debug.h"
#include "clutter-device-manager-private.h"
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "clutter-backend-gdk.h"
#include "clutter-stage-gdk.h"
typedef struct _ClutterInputDeviceClass ClutterInputDeviceGdkClass;
#define clutter_input_device_gdk_get_type _clutter_input_device_gdk_get_type
G_DEFINE_TYPE (ClutterInputDeviceGdk,
clutter_input_device_gdk,
CLUTTER_TYPE_INPUT_DEVICE);
static int device_int_counter;
enum {
PROP_0,
PROP_GDK_DEVICE,
PROP_LAST
};
static void
clutter_input_device_gdk_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterInputDeviceGdk *self = CLUTTER_INPUT_DEVICE_GDK (gobject);
switch (prop_id)
{
case PROP_GDK_DEVICE:
self->gdk_device = GDK_DEVICE (g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_input_device_gdk_class_init (ClutterInputDeviceGdkClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = clutter_input_device_gdk_set_property;
g_object_class_install_property (gobject_class, PROP_GDK_DEVICE,
g_param_spec_object ("gdk-device",
"GdkDevice",
"The GDK device",
GDK_TYPE_DEVICE,
CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
}
static void
clutter_input_device_gdk_init (ClutterInputDeviceGdk *self)
{
}
ClutterInputDevice*
_clutter_input_device_gdk_new (ClutterDeviceManager *manager,
GdkDevice *device)
{
ClutterBackend *backend;
ClutterInputDevice *clutter_device;
ClutterInputMode input_mode = CLUTTER_INPUT_MODE_FLOATING;
ClutterInputDeviceType device_type = CLUTTER_EXTENSION_DEVICE;
gboolean has_cursor = FALSE;
const gchar *name;
gboolean is_enabled = FALSE;
g_object_get (manager, "backend", &backend, NULL);
/* yay for name consistency */
switch (gdk_device_get_device_type (device))
{
case GDK_DEVICE_TYPE_MASTER:
input_mode = CLUTTER_INPUT_MODE_MASTER;
is_enabled = TRUE;
break;
case GDK_DEVICE_TYPE_SLAVE:
input_mode = CLUTTER_INPUT_MODE_SLAVE;
is_enabled = FALSE;
break;
case GDK_DEVICE_TYPE_FLOATING:
input_mode = CLUTTER_INPUT_MODE_FLOATING;
is_enabled = FALSE;
break;
}
switch (gdk_device_get_source (device))
{
case GDK_SOURCE_MOUSE:
device_type = CLUTTER_POINTER_DEVICE;
break;
case GDK_SOURCE_PEN:
device_type = CLUTTER_PEN_DEVICE;
break;
case GDK_SOURCE_ERASER:
device_type = CLUTTER_ERASER_DEVICE;
break;
case GDK_SOURCE_CURSOR:
device_type = CLUTTER_CURSOR_DEVICE;
break;
case GDK_SOURCE_KEYBOARD:
device_type = CLUTTER_KEYBOARD_DEVICE;
break;
}
if (device_type != CLUTTER_KEYBOARD_DEVICE)
/* why Gdk asserts if passed a GDK_SOURCE_KEYBOARD device? */
has_cursor = gdk_device_get_has_cursor (device);
name = gdk_device_get_name (device);
clutter_device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_GDK,
"backend", backend,
"device-manager", manager,
"device-mode", input_mode,
"device-type", device_type,
"has-cursor", has_cursor,
"gdk-device", device,
"id", device_int_counter++,
"name", name,
"enabled", is_enabled,
NULL);
return clutter_device;
}

View File

@ -0,0 +1,55 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright © 2011 Intel Corp.
*
* 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/>.
*
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
*/
#ifndef __CLUTTER_INPUT_DEVICE_GDK_H__
#define __CLUTTER_INPUT_DEVICE_GDK_H__
#include <clutter/clutter-input-device.h>
#include <gdk/gdk.h>
#include "clutter-backend.h"
#include "clutter-device-manager-private.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_INPUT_DEVICE_GDK (_clutter_input_device_gdk_get_type ())
#define CLUTTER_INPUT_DEVICE_GDK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_GDK, ClutterInputDeviceGdk))
#define CLUTTER_IS_INPUT_DEVICE_GDK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_GDK))
typedef struct _ClutterInputDeviceGdk ClutterInputDeviceGdk;
struct _ClutterInputDeviceGdk
{
ClutterInputDevice parent;
GdkDevice *gdk_device;
};
GType _clutter_input_device_gdk_get_type (void) G_GNUC_CONST;
ClutterInputDevice * _clutter_input_device_gdk_new (ClutterDeviceManager *manager,
GdkDevice *device);
G_END_DECLS
#endif /* __CLUTTER_INPUT_DEVICE_GDK_H__ */

View File

@ -0,0 +1,28 @@
#ifndef __CLUTTER_SETTINGS_GDK_H__
#define __CLUTTER_SETTINGS_GDK_H__
/* XSETTINGS key names to ClutterSettings properties */
static const struct {
const char *gdk_setting_name;
const char *settings_property;
GType type;
} _clutter_settings_map[] = {
{ "gtk-double-click-time", "double-click-time", G_TYPE_INT },
{ "gtk-double-click-distance", "double-click-distance", G_TYPE_INT },
{ "gtk-dnd-drag-threshold", "dnd-drag-threshold", G_TYPE_INT },
{ "gtk-font-name", "font-name", G_TYPE_STRING },
{ "gtk-xft-antialias", "font-antialias", G_TYPE_INT },
{ "gtk-xft-dpi", "font-dpi", G_TYPE_INT },
{ "gtk-xft-hinting", "font-hinting", G_TYPE_INT },
{ "gtk-xft-hintstyle", "font-hint-style", G_TYPE_STRING },
{ "gtk-xft-rgba", "font-subpixel-order", G_TYPE_STRING },
{ "gtk-fontconfig-timestamp", "fontconfig-timestamp", G_TYPE_UINT },
};
static const gint _n_clutter_settings_map = G_N_ELEMENTS (_clutter_settings_map);
#define CLUTTER_SETTING_TYPE(id) (_clutter_settings_map[(id)].type)
#define CLUTTER_SETTING_GDK_NAME(id) (_clutter_settings_map[(id)].gdk_setting_name)
#define CLUTTER_SETTING_PROPERTY(id) (_clutter_settings_map[(id)].settings_property)
#endif /* __CLUTTER_SETTINGS_GDK_H__ */

View File

@ -0,0 +1,601 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* 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/>.
*
*
*/
#include "config.h"
#include <math.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "clutter-backend-gdk.h"
#include "clutter-stage-gdk.h"
#include "clutter-gdk.h"
#include "clutter-actor-private.h"
#include "clutter-debug.h"
#include "clutter-device-manager-private.h"
#include "clutter-enum-types.h"
#include "clutter-event-translator.h"
#include "clutter-event-private.h"
#include "clutter-feature.h"
#include "clutter-main.h"
#include "clutter-paint-volume-private.h"
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "cogl/cogl.h"
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
#define clutter_stage_gdk_get_type _clutter_stage_gdk_get_type
G_DEFINE_TYPE_WITH_CODE (ClutterStageGdk,
clutter_stage_gdk,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init));
enum {
PROP_0,
PROP_WRAPPER,
PROP_BACKEND,
PROP_LAST
};
void
_clutter_stage_gdk_update_foreign_event_mask (CoglOnscreen *onscreen,
guint32 event_mask,
void *user_data)
{
ClutterStageGdk *stage_gdk = user_data;
/* we assume that a GDK event mask is bitwise compatible with X11
event masks */
gdk_window_set_events (stage_gdk->window, event_mask | CLUTTER_STAGE_GDK_EVENT_MASK);
}
static void
clutter_stage_gdk_set_gdk_geometry (ClutterStageGdk *stage)
{
GdkGeometry geometry;
gboolean resize = clutter_stage_get_user_resizable (stage->wrapper);
if (!resize)
{
geometry.min_width = geometry.max_width = gdk_window_get_width (stage->window);
geometry.min_height = geometry.max_height = gdk_window_get_height (stage->window);
gdk_window_set_geometry_hints (stage->window,
&geometry,
GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
}
else
{
clutter_stage_get_minimum_size (stage->wrapper,
(guint *)&geometry.min_width,
(guint *)&geometry.min_height);
gdk_window_set_geometry_hints (stage->window,
&geometry,
GDK_HINT_MIN_SIZE);
}
}
static void
clutter_stage_gdk_get_geometry (ClutterStageWindow *stage_window,
ClutterGeometry *geometry)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
if (stage_gdk->window)
{
geometry->width = gdk_window_get_width (stage_gdk->window);
geometry->height = gdk_window_get_height (stage_gdk->window);
}
else
{
geometry->width = 640;
geometry->height = 480;
}
}
static void
clutter_stage_gdk_resize (ClutterStageWindow *stage_window,
gint width,
gint height)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
if (width == 0 || height == 0)
{
/* Should not happen, if this turns up we need to debug it and
* determine the cleanest way to fix.
*/
g_warning ("GDK stage not allowed to have 0 width or height");
width = 1;
height = 1;
}
CLUTTER_NOTE (BACKEND, "New size received: (%d, %d)", width, height);
CLUTTER_SET_PRIVATE_FLAGS (stage_gdk->wrapper,
CLUTTER_IN_RESIZE);
gdk_window_resize (stage_gdk->window, width, height);
}
static void
clutter_stage_gdk_unrealize (ClutterStageWindow *stage_window)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
if (stage_gdk->window)
{
g_object_set_data (G_OBJECT (stage_gdk->window),
"clutter-stage-window", NULL);
if (stage_gdk->foreign_window)
g_object_unref (stage_gdk->window);
else
gdk_window_destroy (stage_gdk->window);
stage_gdk->window = NULL;
}
}
static gboolean
clutter_stage_gdk_realize (ClutterStageWindow *stage_window)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
ClutterBackendGdk *backend_gdk = stage_gdk->backend;
GdkWindowAttr attributes;
gboolean cursor_visible;
gboolean use_alpha;
gfloat width, height;
if (stage_gdk->foreign_window &&
stage_gdk->window)
{
/* complete realizing the stage */
ClutterGeometry geometry;
clutter_stage_gdk_get_geometry (stage_window, &geometry);
clutter_actor_set_geometry (CLUTTER_ACTOR (stage_gdk->wrapper), &geometry);
gdk_window_ensure_native (stage_gdk->window);
gdk_window_set_events (stage_gdk->window,
CLUTTER_STAGE_GDK_EVENT_MASK);
return TRUE;
}
attributes.title = NULL;
g_object_get (stage_gdk->wrapper,
"cursor-visible", &cursor_visible,
"title", &attributes.title,
"width", &width,
"height", &height,
"use-alpha", &use_alpha,
NULL);
attributes.width = width;
attributes.height = height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.window_type = GDK_WINDOW_TOPLEVEL;
attributes.event_mask = CLUTTER_STAGE_GDK_EVENT_MASK;
attributes.cursor = NULL;
if (!cursor_visible)
{
if (stage_gdk->blank_cursor == NULL)
stage_gdk->blank_cursor = gdk_cursor_new (GDK_BLANK_CURSOR);
attributes.cursor = stage_gdk->blank_cursor;
}
if (use_alpha)
{
attributes.visual = gdk_screen_get_rgba_visual (backend_gdk->screen);
if (attributes.visual == NULL)
clutter_stage_set_use_alpha (stage_gdk->wrapper, FALSE);
}
else
{
/* This could still be an RGBA visual, although normally it's not */
attributes.visual = gdk_screen_get_system_visual (backend_gdk->screen);
}
if (stage_gdk->window != NULL)
{
g_critical ("Stage realized more than once");
g_object_set_data (G_OBJECT (stage_gdk->window),
"clutter-stage-window", NULL);
if (stage_gdk->foreign_window)
g_object_unref (stage_gdk->window);
else
gdk_window_destroy (stage_gdk->window);
}
stage_gdk->foreign_window = FALSE;
stage_gdk->window = gdk_window_new (NULL, &attributes,
GDK_WA_TITLE | GDK_WA_CURSOR | GDK_WA_VISUAL);
gdk_window_ensure_native (stage_gdk->window);
clutter_stage_gdk_set_gdk_geometry (stage_gdk);
g_object_set_data (G_OBJECT (stage_gdk->window),
"clutter-stage-window", stage_gdk);
g_free (attributes.title);
CLUTTER_NOTE (BACKEND, "Successfully realized stage");
return TRUE;
}
static void
clutter_stage_gdk_set_fullscreen (ClutterStageWindow *stage_window,
gboolean is_fullscreen)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
ClutterStage *stage = stage_gdk->wrapper;
if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage))
return;
if (stage_gdk->window == NULL)
return;
CLUTTER_NOTE (BACKEND, "%ssetting fullscreen", is_fullscreen ? "" : "un");
if (is_fullscreen)
gdk_window_fullscreen (stage_gdk->window);
else
gdk_window_unfullscreen (stage_gdk->window);
}
static void
clutter_stage_gdk_set_cursor_visible (ClutterStageWindow *stage_window,
gboolean cursor_visible)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
if (stage_gdk->window == NULL)
return;
if (cursor_visible)
{
gdk_window_set_cursor (stage_gdk->window, NULL);
}
else
{
if (stage_gdk->blank_cursor == NULL)
stage_gdk->blank_cursor = gdk_cursor_new (GDK_BLANK_CURSOR);
gdk_window_set_cursor (stage_gdk->window, stage_gdk->blank_cursor);
}
}
static void
clutter_stage_gdk_set_title (ClutterStageWindow *stage_window,
const gchar *title)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
if (stage_gdk->window == NULL)
return;
gdk_window_set_title (stage_gdk->window, title);
}
static void
clutter_stage_gdk_set_user_resizable (ClutterStageWindow *stage_window,
gboolean is_resizable)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
GdkWMFunction function;
if (stage_gdk->window == NULL)
return;
function = GDK_FUNC_MOVE | GDK_FUNC_MINIMIZE | GDK_FUNC_CLOSE;
if (is_resizable)
function |= GDK_FUNC_RESIZE | GDK_FUNC_MAXIMIZE;
gdk_window_set_functions (stage_gdk->window, function);
clutter_stage_gdk_set_gdk_geometry (stage_gdk);
}
static void
clutter_stage_gdk_set_accept_focus (ClutterStageWindow *stage_window,
gboolean accept_focus)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
if (stage_gdk->window == NULL)
return;
gdk_window_set_accept_focus (stage_gdk->window, accept_focus);
}
static void
clutter_stage_gdk_show (ClutterStageWindow *stage_window,
gboolean do_raise)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
g_return_if_fail (stage_gdk->window != NULL);
clutter_actor_map (CLUTTER_ACTOR (stage_gdk->wrapper));
if (do_raise)
gdk_window_show (stage_gdk->window);
else
gdk_window_show_unraised (stage_gdk->window);
}
static void
clutter_stage_gdk_hide (ClutterStageWindow *stage_window)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
g_return_if_fail (stage_gdk->window != NULL);
clutter_actor_unmap (CLUTTER_ACTOR (stage_gdk->wrapper));
gdk_window_hide (stage_gdk->window);
}
static ClutterActor *
clutter_stage_gdk_get_wrapper (ClutterStageWindow *stage_window)
{
return CLUTTER_ACTOR (CLUTTER_STAGE_GDK (stage_window)->wrapper);
}
static void
clutter_stage_gdk_dispose (GObject *gobject)
{
ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (gobject);
if (stage_gdk->window)
{
g_object_set_data (G_OBJECT (stage_gdk->window),
"clutter-stage-window", NULL);
if (stage_gdk->foreign_window)
g_object_unref (stage_gdk->window);
else
gdk_window_destroy (stage_gdk->window);
stage_gdk->window = NULL;
}
if (stage_gdk->blank_cursor)
{
g_object_unref (stage_gdk->blank_cursor);
stage_gdk->blank_cursor = NULL;
}
G_OBJECT_CLASS (clutter_stage_gdk_parent_class)->dispose (gobject);
}
static void
clutter_stage_gdk_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterStageGdk *self = CLUTTER_STAGE_GDK (gobject);
switch (prop_id)
{
case PROP_WRAPPER:
self->wrapper = CLUTTER_STAGE (g_value_get_object (value));
break;
case PROP_BACKEND:
self->backend = CLUTTER_BACKEND_GDK (g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_stage_gdk_class_init (ClutterStageGdkClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = clutter_stage_gdk_dispose;
gobject_class->set_property = clutter_stage_gdk_set_property;
g_object_class_install_property (gobject_class, PROP_WRAPPER,
g_param_spec_object ("wrapper",
"Wrapper",
"ClutterStage wrapping this native stage",
CLUTTER_TYPE_STAGE,
CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class, PROP_BACKEND,
g_param_spec_object ("backend",
"ClutterBackend",
"The Clutter backend singleton",
CLUTTER_TYPE_BACKEND_GDK,
CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
}
static void
clutter_stage_gdk_init (ClutterStageGdk *stage)
{
/* nothing to do here */
}
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{
iface->get_wrapper = clutter_stage_gdk_get_wrapper;
iface->set_title = clutter_stage_gdk_set_title;
iface->set_fullscreen = clutter_stage_gdk_set_fullscreen;
iface->set_cursor_visible = clutter_stage_gdk_set_cursor_visible;
iface->set_user_resizable = clutter_stage_gdk_set_user_resizable;
iface->set_accept_focus = clutter_stage_gdk_set_accept_focus;
iface->show = clutter_stage_gdk_show;
iface->hide = clutter_stage_gdk_hide;
iface->resize = clutter_stage_gdk_resize;
iface->get_geometry = clutter_stage_gdk_get_geometry;
iface->realize = clutter_stage_gdk_realize;
iface->unrealize = clutter_stage_gdk_unrealize;
}
/**
* clutter_gdk_get_stage_window:
* @stage: a #ClutterStage
*
* Gets the stages GdkWindow.
*
* Return value: (transfer none): A GdkWindow* for the stage window.
*
* Since: 0.4
*/
GdkWindow*
clutter_gdk_get_stage_window (ClutterStage *stage)
{
ClutterStageWindow *impl;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), None);
impl = _clutter_stage_get_window (stage);
g_assert (CLUTTER_IS_STAGE_GDK (impl));
return CLUTTER_STAGE_GDK (impl)->window;
}
/**
* clutter_gdk_get_stage_from_window:
* @window: a #GtkWindow
*
* Gets the stage for a particular X window.
*
* Return value: (transfer none): A #ClutterStage, or% NULL if a stage
* does not exist for the window
*
* Since: 0.8
*/
ClutterStage *
clutter_gdk_get_stage_from_window (GdkWindow *window)
{
ClutterStageGdk *stage_gdk = g_object_get_data (G_OBJECT (window), "clutter-stage-window");
if (stage_gdk != NULL && CLUTTER_IS_STAGE_GDK (stage_gdk))
return stage_gdk->wrapper;
return NULL;
}
typedef struct
{
ClutterStageGdk *stage_gdk;
GdkWindow *window;
} ForeignWindowClosure;
static void
set_foreign_window_callback (ClutterActor *actor,
void *data)
{
ForeignWindowClosure *closure = data;
ClutterStageGdk *stage_gdk = closure->stage_gdk;
stage_gdk->window = closure->window;
stage_gdk->foreign_window = TRUE;
/* calling this with the stage unrealized will unset the stage
* from the GL context; once the stage is realized the GL context
* will be set again
*/
clutter_stage_ensure_current (CLUTTER_STAGE (actor));
}
/**
* clutter_gdk_set_stage_foreign:
* @stage: a #ClutterStage
* @window: an existing #GdkWindow
*
* Target the #ClutterStage to use an existing external #GdkWindow
*
* Return value: %TRUE if foreign window is valid
*
* Since: 0.4
*/
gboolean
clutter_gdk_set_stage_foreign (ClutterStage *stage,
GdkWindow *window)
{
ForeignWindowClosure closure;
ClutterStageGdk *stage_gdk;
ClutterStageWindow *impl;
ClutterActor *actor;
gpointer gtk_data = NULL;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
g_return_val_if_fail (!CLUTTER_ACTOR_IN_DESTRUCTION (stage), FALSE);
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
impl = _clutter_stage_get_window (stage);
stage_gdk = CLUTTER_STAGE_GDK (impl);
if (g_object_get_data (G_OBJECT (window), "clutter-stage-window") != NULL)
{
g_critical ("The provided GdkWindow is already in use by another ClutterStage");
return FALSE;
}
gdk_window_get_user_data (window, &gtk_data);
if (gtk_data != NULL)
{
g_critical ("The provided GdkWindow is already in use by a GtkWidget. "
"Use a child GdkWindow for embedding instead");
return FALSE;
}
closure.stage_gdk = stage_gdk;
closure.window = g_object_ref (window);
actor = CLUTTER_ACTOR (stage);
_clutter_actor_rerealize (actor,
set_foreign_window_callback,
&closure);
/* Queue a relayout - so the stage will be allocated the new
* window size.
*
* Note also that when the stage gets allocated the new
* window size that will result in the stage's
* priv->viewport being changed, which will in turn result
* in the Cogl viewport changing when _clutter_do_redraw
* calls _clutter_stage_maybe_setup_viewport().
*/
clutter_actor_queue_relayout (actor);
return TRUE;
}

View File

@ -0,0 +1,84 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
* 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
*
* 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/>.
*
*
*/
#ifndef __CLUTTER_STAGE_GDK_H__
#define __CLUTTER_STAGE_GDK_H__
#include <clutter/clutter-group.h>
#include <clutter/clutter-stage.h>
#include <gdk/gdk.h>
#include "clutter-backend-gdk.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_STAGE_GDK (_clutter_stage_gdk_get_type ())
#define CLUTTER_STAGE_GDK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_GDK, ClutterStageGdk))
#define CLUTTER_IS_STAGE_GDK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_GDK))
#define CLUTTER_STAGE_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_GDK, ClutterStageGdkClass))
#define CLUTTER_IS_STAGE_GDK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_GDK))
#define CLUTTER_STAGE_GDK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_GDK, ClutterStageGdkClass))
typedef struct _ClutterStageGdk ClutterStageGdk;
typedef struct _ClutterStageGdkClass ClutterStageGdkClass;
struct _ClutterStageGdk
{
GObject parent_instance;
GdkWindow *window;
GdkCursor *blank_cursor;
/* backpointers */
ClutterStage *wrapper;
ClutterBackendGdk *backend;
gboolean foreign_window;
};
struct _ClutterStageGdkClass
{
GObjectClass parent_class;
};
#define CLUTTER_STAGE_GDK_EVENT_MASK \
(GDK_STRUCTURE_MASK | \
GDK_FOCUS_CHANGE_MASK | \
GDK_EXPOSURE_MASK | \
GDK_PROPERTY_CHANGE_MASK | \
GDK_ENTER_NOTIFY_MASK | \
GDK_LEAVE_NOTIFY_MASK | \
GDK_KEY_PRESS_MASK | \
GDK_KEY_RELEASE_MASK | \
GDK_BUTTON_PRESS_MASK | \
GDK_BUTTON_RELEASE_MASK | \
GDK_POINTER_MOTION_MASK)
GType _clutter_stage_gdk_get_type (void) G_GNUC_CONST;
void _clutter_stage_gdk_update_foreign_event_mask (CoglOnscreen *onscreen,
guint32 event_mask,
void *user_data);
G_END_DECLS
#endif /* __CLUTTER_STAGE_H__ */

View File

@ -226,6 +226,23 @@ AS_CASE([$CLUTTER_FLAVOUR],
[])
],
[gdk],
[
CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_COGL"
# We don't claim to support X11 (even though that's the preferred
# GDK backend), to avoid building all the ClutterX11 stuff
SUPPORT_GDK=1
CLUTTER_WINSYS=cogl
CLUTTER_WINSYS_BASE=gdk
CLUTTER_WINSYS_BASE_LIB="gdk/libclutter-gdk.la"
CLUTTER_SONAME_INFIX=gdk
BACKEND_PC_FILES="$BACKEND_PC_FILES gdk-3.0"
PKG_CHECK_EXISTS([gl], [BACKEND_PC_FILES="$BACKEND_PC_FILES gl"], [])
],
[opengl-egl-xlib],
[
CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_EGL"
@ -419,6 +436,7 @@ AS_IF([test "x$CLUTTER_EGL_BACKEND" = "xcex100"],
AM_CONDITIONAL(SUPPORT_GLX, [test "x$SUPPORT_GLX" = "x1"])
AM_CONDITIONAL(SUPPORT_X11, [test "x$SUPPORT_X11" = "x1"])
AM_CONDITIONAL(SUPPORT_XLIB, [test "x$SUPPORT_XLIB" = "x1"])
AM_CONDITIONAL(SUPPORT_GDK, [test "x$SUPPORT_GDK" = "x1"])
AM_CONDITIONAL(SUPPORT_EGL, [test "x$SUPPORT_EGL" = "x1"])
AM_CONDITIONAL(SUPPORT_OSX, [test "x$CLUTTER_WINSYS" = "xosx"])
AM_CONDITIONAL(SUPPORT_WIN32, [test "x$CLUTTER_WINSYS" = "xwin32"])
@ -446,6 +464,9 @@ CLUTTER_CONFIG_DEFINES=
AS_IF([test "x$SUPPORT_XLIB" = "x1"],
[CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
#define CLUTTER_WINDOWING_X11 1"])
AS_IF([test "x$SUPPORT_GDK" = "x1"],
[CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
#define CLUTTER_WINDOWING_GDK 1"])
AS_IF([test "x$SUPPORT_GLX" = "x1"],
[CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
#define CLUTTER_WINDOWING_GLX 1"])

View File

@ -4,7 +4,7 @@
static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
#ifdef COGL_HAS_XLIB
#ifdef CLUTTER_WINDOWING_X11
#include <clutter/x11/clutter-x11.h>
#include <cogl/cogl-texture-pixmap-x11.h>
@ -195,13 +195,13 @@ queue_redraw (gpointer stage)
return TRUE;
}
#endif /* COGL_HAS_XLIB */
#endif /* CLUTTER_WINDOWING_X11 */
void
test_cogl_texture_pixmap_x11 (TestConformSimpleFixture *fixture,
gconstpointer data)
{
#ifdef COGL_HAS_XLIB
#ifdef CLUTTER_WINDOWING_X11
TestState state;
guint idle_handler;
@ -235,11 +235,11 @@ test_cogl_texture_pixmap_x11 (TestConformSimpleFixture *fixture,
if (g_test_verbose ())
g_print ("OK\n");
#else /* COGL_HAS_XLIB */
#else /* CLUTTER_WINDOWING_X11 */
if (g_test_verbose ())
g_print ("Skipping\n");
#endif /* COGL_HAS_XLIB */
#endif /* CLUTTER_WINDOWING_X11 */
}

View File

@ -3,7 +3,7 @@
#include <clutter/clutter.h>
#include <stdlib.h>
#ifdef COGL_HAS_XLIB
#ifdef CLUTTER_WINDOWING_X11
#include <X11/Xlib.h>
#include <clutter/x11/clutter-x11.h>
#endif
@ -48,7 +48,7 @@ test_conform_simple_fixture_setup (TestConformSimpleFixture *fixture,
g_assert (clutter_init (shared_state->argc_addr, shared_state->argv_addr)
== CLUTTER_INIT_SUCCESS);
#ifdef COGL_HAS_XLIB
#ifdef CLUTTER_WINDOWING_X11
/* A lot of the tests depend on a specific stage / framebuffer size
* when they read pixels back to verify the results of the test.
*