2007-11-15 Matthew Allum <mallum@openedhand.com>
* clutter/Makefile.am: * clutter/eglx/Makefile.am: * clutter/eglx/clutter-backend-egl.c: * clutter/eglx/clutter-backend-egl.h: * clutter/eglx/clutter-eglx.h: * clutter/eglx/clutter-event-egl.c: * clutter/eglx/clutter-stage-egl.c: * clutter/eglx/clutter-stage-egl.h: * clutter/glx/Makefile.am: * clutter/glx/clutter-backend-glx.c: * clutter/glx/clutter-backend-glx.h: * clutter/glx/clutter-event-glx.c: * clutter/glx/clutter-glx.h: * clutter/glx/clutter-stage-glx.c: * clutter/glx/clutter-stage-glx.h: * clutter/x11/Makefile.am: * clutter/x11/clutter-backend-x11-private.h: * clutter/x11/clutter-backend-x11.c: * clutter/x11/clutter-backend-x11.h: * clutter/x11/clutter-event-x11.c: * clutter/x11/clutter-stage-x11.c: * clutter/x11/clutter-stage-x11.h: * clutter/x11/clutter-x11.h: Create a new X11 backend class of which EGL and GLX 'real' backends then subclass. Effectively shares all X11 code between both backends avoids code duplication and brings many missing features to EGL X backend. Requires some cleanup and testing. (#518) * clutter/cogl/gles/cogl.c: (cogl_color): Add define to use color4ub only if configure finds it. If not fall back to old code. * configure.ac: Drop support for vincent checks. Drop sdles backend. Specifically check for color4ub call.
This commit is contained in:
parent
a9efed235e
commit
3607a470aa
31
ChangeLog
31
ChangeLog
@ -1,3 +1,34 @@
|
||||
2007-11-15 Matthew Allum <mallum@openedhand.com>
|
||||
|
||||
reviewed by: <delete if not using a buddy>
|
||||
|
||||
* clutter/Makefile.am:
|
||||
* clutter/cogl/gles/cogl.c: (cogl_color):
|
||||
* clutter/eglx/Makefile.am:
|
||||
* clutter/eglx/clutter-backend-egl.c:
|
||||
* clutter/eglx/clutter-backend-egl.h:
|
||||
* clutter/eglx/clutter-eglx.h:
|
||||
* clutter/eglx/clutter-event-egl.c:
|
||||
* clutter/eglx/clutter-stage-egl.c: (clutter_stage_egl_realize):
|
||||
* clutter/eglx/clutter-stage-egl.h:
|
||||
* clutter/glx/Makefile.am:
|
||||
* clutter/glx/clutter-backend-glx.c:
|
||||
(clutter_backend_glx_pre_parse):
|
||||
* clutter/glx/clutter-backend-glx.h:
|
||||
* clutter/glx/clutter-event-glx.c:
|
||||
* clutter/glx/clutter-glx.h:
|
||||
* clutter/glx/clutter-stage-glx.c: (clutter_stage_glx_realize):
|
||||
* clutter/glx/clutter-stage-glx.h:
|
||||
* clutter/x11/Makefile.am:
|
||||
* clutter/x11/clutter-backend-x11-private.h:
|
||||
* clutter/x11/clutter-backend-x11.c:
|
||||
* clutter/x11/clutter-backend-x11.h:
|
||||
* clutter/x11/clutter-event-x11.c:
|
||||
* clutter/x11/clutter-stage-x11.c:
|
||||
* clutter/x11/clutter-stage-x11.h:
|
||||
* clutter/x11/clutter-x11.h:
|
||||
* configure.ac:
|
||||
|
||||
2007-11-15 Neil J. Patel <njp@o-hand.com>
|
||||
|
||||
* clutter/Makefile.am:
|
||||
|
6
README
6
README
@ -129,6 +129,12 @@ RELEASE NOTES
|
||||
Relevant information for developers with existing Clutter applications
|
||||
wanting to port to newer releases (See NEWS for general new feature info).
|
||||
|
||||
Release Notes for Clutter 0.6.0
|
||||
-------------------------------
|
||||
|
||||
* X11 related called for glx and eglx backends are now shared and moved into
|
||||
a clutter_x11 prefix.
|
||||
|
||||
Release Notes for Clutter 0.4.0
|
||||
-------------------------------
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
NULL =
|
||||
|
||||
SUBDIRS = cogl pango json $(clutterbackend)
|
||||
SUBDIRS = cogl pango json $(clutterbackend) $(backendextra)
|
||||
|
||||
DIST_SUBDIRS = pango glx eglx eglnative cogl sdl json osx
|
||||
DIST_SUBDIRS = pango glx eglx eglnative cogl sdl json osx x11
|
||||
|
||||
target = $(clutterbackend)
|
||||
|
||||
@ -181,7 +181,8 @@ libclutter_@CLUTTER_FLAVOUR@_@CLUTTER_API_VERSION@_la_LIBADD = \
|
||||
pango/libpangoclutter.la \
|
||||
@CLUTTER_FLAVOUR@/libclutter-@CLUTTER_FLAVOUR@.la \
|
||||
cogl/@CLUTTER_COGL@/libclutter-cogl.la \
|
||||
json/libclutter-json.la
|
||||
json/libclutter-json.la \
|
||||
$(backendextralib)
|
||||
|
||||
libclutter_@CLUTTER_FLAVOUR@_@CLUTTER_API_VERSION@_la_SOURCES = \
|
||||
$(source_c) $(source_h) $(source_h_priv)
|
||||
|
@ -239,9 +239,10 @@ cogl_enable (gulong flags)
|
||||
void
|
||||
cogl_color (const ClutterColor *color)
|
||||
{
|
||||
#if HAVE_GLES_COLOR4UB
|
||||
/*
|
||||
* GLES 1.1 does actually have this function, it's in the header file but
|
||||
* missing in the reference manual:
|
||||
* missing in the reference manual (and SDK):
|
||||
*
|
||||
* http://www.khronos.org/egl/headers/1_1/gl.h
|
||||
*/
|
||||
@ -249,6 +250,13 @@ cogl_color (const ClutterColor *color)
|
||||
color->green,
|
||||
color->blue,
|
||||
color->alpha) );
|
||||
#else
|
||||
/* conversion can cause issues with picking on some gles implementations */
|
||||
GE( glColor4x ((color->red << 16) / 0xff,
|
||||
(color->green << 16) / 0xff,
|
||||
(color->blue << 16) / 0xff,
|
||||
(color->alpha << 16) / 0xff));
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -8,14 +8,14 @@ INCLUDES = \
|
||||
$(CLUTTER_DEBUG_CFLAGS) \
|
||||
$(GCC_FLAGS)
|
||||
|
||||
LDADD = $(CLUTTER_LIBS)
|
||||
LDADD = $(CLUTTER_LIBS) \
|
||||
$(top_srcdir)/clutter/x11/libclutter-x11.la
|
||||
|
||||
noinst_LTLIBRARIES = libclutter-eglx.la
|
||||
|
||||
libclutter_eglx_la_SOURCES = \
|
||||
clutter-backend-egl.h \
|
||||
clutter-backend-egl.c \
|
||||
clutter-event-egl.c \
|
||||
clutter-stage-egl.h \
|
||||
clutter-stage-egl.c \
|
||||
clutter-eglx.h
|
||||
|
@ -10,79 +10,20 @@
|
||||
|
||||
static ClutterBackendEGL *backend_singleton = NULL;
|
||||
|
||||
/* options */
|
||||
static gchar *clutter_display_name = NULL;
|
||||
static gint clutter_screen = 0;
|
||||
|
||||
/* X error trap */
|
||||
static int TrappedErrorCode = 0;
|
||||
static int (*old_error_handler) (Display *, XErrorEvent *);
|
||||
|
||||
G_DEFINE_TYPE (ClutterBackendEGL, clutter_backend_egl, CLUTTER_TYPE_BACKEND);
|
||||
|
||||
static gboolean
|
||||
clutter_backend_egl_pre_parse (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *env_string;
|
||||
|
||||
/* we don't fail here if DISPLAY is not set, as the user
|
||||
* might pass the --display command line switch
|
||||
*/
|
||||
env_string = g_getenv ("DISPLAY");
|
||||
if (env_string)
|
||||
{
|
||||
clutter_display_name = g_strdup (env_string);
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
G_DEFINE_TYPE (ClutterBackendEGL, clutter_backend_egl, CLUTTER_TYPE_BACKEND_X11);
|
||||
|
||||
static gboolean
|
||||
clutter_backend_egl_post_parse (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
if (clutter_display_name)
|
||||
{
|
||||
backend_egl->xdpy = XOpenDisplay (clutter_display_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_BACKEND,
|
||||
"Unable to open display. You have to set the DISPLAY "
|
||||
"environment variable, or use the --display command "
|
||||
"line argument");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (backend_egl->xdpy)
|
||||
if (clutter_backend_x11_post_parse (backend, error))
|
||||
{
|
||||
EGLBoolean status;
|
||||
double dpi;
|
||||
|
||||
CLUTTER_NOTE (MISC, "Getting the X screen");
|
||||
|
||||
if (clutter_screen == 0)
|
||||
backend_egl->xscreen = DefaultScreenOfDisplay (backend_egl->xdpy);
|
||||
else
|
||||
backend_egl->xscreen = ScreenOfDisplay (backend_egl->xdpy,
|
||||
clutter_screen);
|
||||
|
||||
backend_egl->xscreen_num = XScreenNumberOfScreen (backend_egl->xscreen);
|
||||
backend_egl->xwin_root = RootWindow (backend_egl->xdpy,
|
||||
backend_egl->xscreen_num);
|
||||
|
||||
backend_egl->display_name = g_strdup (clutter_display_name);
|
||||
|
||||
backend_egl->edpy = eglGetDisplay((NativeDisplayType)backend_egl->xdpy);
|
||||
|
||||
dpi = (((double) DisplayHeight (backend_egl->xdpy, backend_egl->xscreen_num) * 25.4)
|
||||
/ (double) DisplayHeightMM (backend_egl->xdpy, backend_egl->xscreen_num));
|
||||
clutter_backend_set_resolution (backend, dpi);
|
||||
backend_egl->edpy = eglGetDisplay((NativeDisplayType)backend_x11->xdpy);
|
||||
|
||||
status = eglInitialize(backend_egl->edpy,
|
||||
&backend_egl->egl_version_major,
|
||||
@ -98,14 +39,6 @@ clutter_backend_egl_post_parse (ClutterBackend *backend,
|
||||
|
||||
}
|
||||
|
||||
g_free (clutter_display_name);
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "X Display `%s' [%p] opened (screen:%d, root:%u)",
|
||||
backend_egl->display_name,
|
||||
backend_egl->xdpy,
|
||||
backend_egl->xscreen_num,
|
||||
(unsigned int) backend_egl->xwin_root);
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "EGL Reports version %i.%i",
|
||||
backend_egl->egl_version_major,
|
||||
backend_egl->egl_version_minor);
|
||||
@ -113,80 +46,23 @@ clutter_backend_egl_post_parse (ClutterBackend *backend,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_backend_egl_init_stage (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
|
||||
|
||||
if (!backend_egl->stage)
|
||||
{
|
||||
ClutterStageEGL *stage_egl;
|
||||
ClutterActor *stage;
|
||||
|
||||
stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL);
|
||||
|
||||
/* copy backend data into the stage */
|
||||
stage_egl = CLUTTER_STAGE_EGL (stage);
|
||||
stage_egl->xdpy = backend_egl->xdpy;
|
||||
stage_egl->xwin_root = backend_egl->xwin_root;
|
||||
stage_egl->xscreen = backend_egl->xscreen_num;
|
||||
|
||||
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
|
||||
|
||||
backend_egl->stage = g_object_ref_sink (stage);
|
||||
}
|
||||
|
||||
clutter_actor_realize (backend_egl->stage);
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (backend_egl->stage))
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_INTERNAL,
|
||||
"Unable to realize the main stage");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_egl_init_events (ClutterBackend *backend)
|
||||
{
|
||||
_clutter_events_init (backend);
|
||||
|
||||
}
|
||||
|
||||
static const GOptionEntry entries[] =
|
||||
{
|
||||
{
|
||||
"display", 0,
|
||||
G_OPTION_FLAG_IN_MAIN,
|
||||
G_OPTION_ARG_STRING, &clutter_display_name,
|
||||
"X display to use", "DISPLAY"
|
||||
},
|
||||
{
|
||||
"screen", 0,
|
||||
G_OPTION_FLAG_IN_MAIN,
|
||||
G_OPTION_ARG_INT, &clutter_screen,
|
||||
"X screen to use", "SCREEN"
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
clutter_backend_egl_redraw (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
ClutterStageEGL *stage_egl;
|
||||
ClutterStageX11 *stage_x11;
|
||||
|
||||
stage_egl = CLUTTER_STAGE_EGL(backend_egl->stage);
|
||||
stage_x11 = CLUTTER_STAGE_X11(backend_x11->stage);
|
||||
stage_egl = CLUTTER_STAGE_EGL(backend_x11->stage);
|
||||
|
||||
clutter_actor_paint (CLUTTER_ACTOR(stage_egl));
|
||||
|
||||
/* Why this paint is done in backend as likely GL windowing system
|
||||
* specific calls, like swapping buffers.
|
||||
*/
|
||||
if (stage_egl->xwin)
|
||||
if (stage_x11->xwin)
|
||||
{
|
||||
/* clutter_feature_wait_for_vblank (); */
|
||||
eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface);
|
||||
@ -198,30 +74,9 @@ clutter_backend_egl_redraw (ClutterBackend *backend)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_egl_add_options (ClutterBackend *backend,
|
||||
GOptionGroup *group)
|
||||
{
|
||||
g_option_group_add_entries (group, entries);
|
||||
}
|
||||
|
||||
static ClutterActor *
|
||||
clutter_backend_egl_get_stage (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
|
||||
|
||||
return backend_egl->stage;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_egl_finalize (GObject *gobject)
|
||||
{
|
||||
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (gobject);
|
||||
|
||||
g_free (backend_egl->display_name);
|
||||
|
||||
XCloseDisplay (backend_egl->xdpy);
|
||||
|
||||
if (backend_singleton)
|
||||
backend_singleton = NULL;
|
||||
|
||||
@ -231,16 +86,6 @@ clutter_backend_egl_finalize (GObject *gobject)
|
||||
static void
|
||||
clutter_backend_egl_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (gobject);
|
||||
|
||||
_clutter_events_uninit (CLUTTER_BACKEND (backend_egl));
|
||||
|
||||
if (backend_egl->stage)
|
||||
{
|
||||
clutter_actor_destroy (backend_egl->stage);
|
||||
backend_egl->stage = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (clutter_backend_egl_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
@ -275,6 +120,49 @@ clutter_backend_egl_get_features (ClutterBackend *backend)
|
||||
return CLUTTER_FEATURE_STAGE_CURSOR;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_backend_egl_init_stage (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
if (!backend_x11->stage)
|
||||
{
|
||||
ClutterStageX11 *stage_x11;
|
||||
ClutterActor *stage;
|
||||
|
||||
stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL);
|
||||
|
||||
/* copy backend data into the stage */
|
||||
stage_x11 = CLUTTER_STAGE_X11 (stage);
|
||||
stage_x11->xdpy = backend_x11->xdpy;
|
||||
stage_x11->xwin_root = backend_x11->xwin_root;
|
||||
stage_x11->xscreen = backend_x11->xscreen_num;
|
||||
stage_x11->backend = backend_x11;
|
||||
|
||||
CLUTTER_NOTE (MISC, "X11 stage created (display:%p, screen:%d, root:%u)",
|
||||
stage_x11->xdpy,
|
||||
stage_x11->xscreen,
|
||||
(unsigned int) stage_x11->xwin_root);
|
||||
|
||||
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
|
||||
|
||||
backend_x11->stage = g_object_ref_sink (stage);
|
||||
}
|
||||
|
||||
clutter_actor_realize (backend_x11->stage);
|
||||
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (backend_x11->stage))
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_INTERNAL,
|
||||
"Unable to realize the main stage");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_egl_class_init (ClutterBackendEGLClass *klass)
|
||||
{
|
||||
@ -285,25 +173,16 @@ clutter_backend_egl_class_init (ClutterBackendEGLClass *klass)
|
||||
gobject_class->dispose = clutter_backend_egl_dispose;
|
||||
gobject_class->finalize = clutter_backend_egl_finalize;
|
||||
|
||||
backend_class->pre_parse = clutter_backend_egl_pre_parse;
|
||||
backend_class->post_parse = clutter_backend_egl_post_parse;
|
||||
backend_class->init_stage = clutter_backend_egl_init_stage;
|
||||
backend_class->init_events = clutter_backend_egl_init_events;
|
||||
backend_class->get_stage = clutter_backend_egl_get_stage;
|
||||
backend_class->add_options = clutter_backend_egl_add_options;
|
||||
backend_class->redraw = clutter_backend_egl_redraw;
|
||||
backend_class->get_features = clutter_backend_egl_get_features;
|
||||
backend_class->init_stage = clutter_backend_egl_init_stage;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_egl_init (ClutterBackendEGL *backend_egl)
|
||||
{
|
||||
ClutterBackend *backend = CLUTTER_BACKEND (backend_egl);
|
||||
|
||||
/* FIXME: get from xsettings */
|
||||
clutter_backend_set_resolution (backend, 96.0);
|
||||
clutter_backend_set_double_click_time (backend, 250);
|
||||
clutter_backend_set_double_click_distance (backend, 5);
|
||||
;
|
||||
}
|
||||
|
||||
GType
|
||||
@ -312,108 +191,6 @@ _clutter_backend_impl_get_type (void)
|
||||
return clutter_backend_egl_get_type ();
|
||||
}
|
||||
|
||||
static int
|
||||
error_handler(Display *xdpy,
|
||||
XErrorEvent *error)
|
||||
{
|
||||
TrappedErrorCode = error->error_code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_eglx_trap_x_errors:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
void
|
||||
clutter_eglx_trap_x_errors (void)
|
||||
{
|
||||
TrappedErrorCode = 0;
|
||||
old_error_handler = XSetErrorHandler (error_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_eglx_untrap_x_errors:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
gint
|
||||
clutter_eglx_untrap_x_errors (void)
|
||||
{
|
||||
XSetErrorHandler (old_error_handler);
|
||||
|
||||
return TrappedErrorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_eglx_get_default_xdisplay:
|
||||
*
|
||||
* Returns the default X Display
|
||||
*
|
||||
* Return value: A Display pointer
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
Display *
|
||||
clutter_eglx_get_default_xdisplay (void)
|
||||
{
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("EGL backend has not been initialised");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return backend_singleton->xdpy;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_eglx_get_default_screen:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
gint
|
||||
clutter_eglx_get_default_screen (void)
|
||||
{
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("EGL backend has not been initialised");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return backend_singleton->xscreen_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_eglx_get_default_root_window:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
Window
|
||||
clutter_eglx_get_default_root_window (void)
|
||||
{
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("EGL backend has not been initialised");
|
||||
return None;
|
||||
}
|
||||
|
||||
return backend_singleton->xwin_root;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_egl_display
|
||||
*
|
||||
|
@ -23,6 +23,7 @@
|
||||
#define __CLUTTER_BACKEND_EGL_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter-event.h>
|
||||
#include <clutter/clutter-backend.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
@ -30,6 +31,9 @@
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/egl.h>
|
||||
|
||||
#include "../x11/clutter-backend-x11.h"
|
||||
#include "clutter-eglx.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_BACKEND_EGL (clutter_backend_egl_get_type ())
|
||||
@ -44,37 +48,21 @@ typedef struct _ClutterBackendEGLClass ClutterBackendEGLClass;
|
||||
|
||||
struct _ClutterBackendEGL
|
||||
{
|
||||
ClutterBackend parent_instance;
|
||||
|
||||
Display *xdpy;
|
||||
gchar *display_name;
|
||||
Window xwin_root;
|
||||
int xscreen_num;
|
||||
Screen *xscreen;
|
||||
ClutterBackendX11 parent_instance;
|
||||
|
||||
/* EGL Specific */
|
||||
EGLDisplay edpy;
|
||||
gint egl_version_major, egl_version_minor;
|
||||
|
||||
/* main stage singleton */
|
||||
ClutterActor *stage;
|
||||
|
||||
/* event source */
|
||||
GSource *event_source;
|
||||
|
||||
/*< private >*/
|
||||
};
|
||||
|
||||
struct _ClutterBackendEGLClass
|
||||
{
|
||||
ClutterBackendClass parent_class;
|
||||
ClutterBackendX11Class parent_class;
|
||||
};
|
||||
|
||||
GType clutter_backend_egl_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void _clutter_events_init (ClutterBackend *backend);
|
||||
void _clutter_events_uninit (ClutterBackend *backend);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_BACKEND_EGL_H__ */
|
||||
|
@ -39,19 +39,6 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void clutter_eglx_trap_x_errors (void);
|
||||
gint clutter_eglx_untrap_x_errors (void);
|
||||
|
||||
Display *clutter_eglx_get_default_xdisplay (void);
|
||||
gint clutter_eglx_get_default_screen (void);
|
||||
Window clutter_eglx_get_default_root_window (void);
|
||||
|
||||
Window clutter_eglx_get_stage_window (ClutterStage *stage);
|
||||
XVisualInfo *clutter_eglx_get_stage_visual (ClutterStage *stage);
|
||||
|
||||
void clutter_eglx_set_stage_foreign (ClutterStage *stage,
|
||||
Window window);
|
||||
|
||||
EGLDisplay
|
||||
clutter_eglx_display (void);
|
||||
|
||||
|
@ -1,382 +0,0 @@
|
||||
/* 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-stage-egl.h"
|
||||
#include "clutter-backend-egl.h"
|
||||
#include "clutter-eglx.h"
|
||||
|
||||
#include "../clutter-backend.h"
|
||||
#include "../clutter-event.h"
|
||||
#include "../clutter-private.h"
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-main.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef HAVE_XFIXES
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#endif
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
typedef struct _ClutterEventSource ClutterEventSource;
|
||||
|
||||
struct _ClutterEventSource
|
||||
{
|
||||
GSource source;
|
||||
|
||||
ClutterBackend *backend;
|
||||
GPollFD event_poll_fd;
|
||||
};
|
||||
|
||||
static gboolean clutter_event_prepare (GSource *source,
|
||||
gint *timeout);
|
||||
static gboolean clutter_event_check (GSource *source);
|
||||
static gboolean clutter_event_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data);
|
||||
|
||||
static GList *event_sources = NULL;
|
||||
|
||||
static GSourceFuncs event_funcs = {
|
||||
clutter_event_prepare,
|
||||
clutter_event_check,
|
||||
clutter_event_dispatch,
|
||||
NULL
|
||||
};
|
||||
|
||||
static GSource *
|
||||
clutter_event_source_new (ClutterBackend *backend)
|
||||
{
|
||||
GSource *source = g_source_new (&event_funcs, sizeof (ClutterEventSource));
|
||||
ClutterEventSource *event_source = (ClutterEventSource *) source;
|
||||
|
||||
event_source->backend = backend;
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_check_xpending (ClutterBackend *backend)
|
||||
{
|
||||
return XPending (CLUTTER_BACKEND_EGL (backend)->xdpy);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_clutter_events_init (ClutterBackend *backend)
|
||||
{
|
||||
GSource *source;
|
||||
ClutterEventSource *event_source;
|
||||
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
|
||||
int connection_number;
|
||||
|
||||
connection_number = ConnectionNumber (backend_egl->xdpy);
|
||||
CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number);
|
||||
|
||||
source = backend_egl->event_source = clutter_event_source_new (backend);
|
||||
event_source = (ClutterEventSource *) source;
|
||||
g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
|
||||
|
||||
event_source->event_poll_fd.fd = connection_number;
|
||||
event_source->event_poll_fd.events = G_IO_IN;
|
||||
|
||||
event_sources = g_list_prepend (event_sources, event_source);
|
||||
|
||||
g_source_add_poll (source, &event_source->event_poll_fd);
|
||||
g_source_set_can_recurse (source, TRUE);
|
||||
g_source_attach (source, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_events_uninit (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
|
||||
|
||||
if (backend_egl->event_source)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "Destroying the event source");
|
||||
|
||||
event_sources = g_list_remove (event_sources,
|
||||
backend_egl->event_source);
|
||||
|
||||
g_source_destroy (backend_egl->event_source);
|
||||
g_source_unref (backend_egl->event_source);
|
||||
backend_egl->event_source = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_user_time (Display *display,
|
||||
Window *xwindow,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
if (clutter_event_get_time (event) != CLUTTER_CURRENT_TIME)
|
||||
{
|
||||
Atom atom_WM_USER_TIME;
|
||||
long timestamp = clutter_event_get_time (event);
|
||||
|
||||
atom_WM_USER_TIME = XInternAtom (display, "_NET_WM_USER_TIME", False);
|
||||
|
||||
XChangeProperty (display, *xwindow,
|
||||
atom_WM_USER_TIME,
|
||||
XA_CARDINAL, 32, PropModeReplace,
|
||||
(unsigned char *) ×tamp, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
translate_key_event (ClutterBackend *backend,
|
||||
ClutterEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "Translating key %s event",
|
||||
xevent->xany.type == KeyPress ? "press" : "release");
|
||||
|
||||
event->key.type = (xevent->xany.type == KeyPress) ? CLUTTER_KEY_PRESS
|
||||
: CLUTTER_KEY_RELEASE;
|
||||
event->key.time = xevent->xkey.time;
|
||||
event->key.modifier_state = xevent->xkey.state; /* FIXME: handle modifiers */
|
||||
event->key.hardware_keycode = xevent->xkey.keycode;
|
||||
event->key.keyval = XKeycodeToKeysym (xevent->xkey.display,
|
||||
xevent->xkey.keycode,
|
||||
0); /* FIXME: index with modifiers */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_event_translate (ClutterBackend *backend,
|
||||
ClutterEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
ClutterBackendEGL *backend_egl;
|
||||
ClutterStage *stage;
|
||||
gboolean res;
|
||||
Window xwindow, stage_xwindow;
|
||||
|
||||
backend_egl = CLUTTER_BACKEND_EGL (backend);
|
||||
stage = CLUTTER_STAGE (_clutter_backend_get_stage (backend));
|
||||
stage_xwindow = clutter_eglx_get_stage_window (stage);
|
||||
|
||||
xwindow = xevent->xany.window;
|
||||
if (xwindow == None)
|
||||
xwindow = stage_xwindow;
|
||||
|
||||
res = TRUE;
|
||||
|
||||
switch (xevent->type)
|
||||
{
|
||||
case Expose:
|
||||
{
|
||||
XEvent foo_xev;
|
||||
|
||||
/* Cheap compress */
|
||||
while (XCheckTypedWindowEvent (backend_egl->xdpy,
|
||||
xevent->xexpose.window,
|
||||
Expose,
|
||||
&foo_xev));
|
||||
|
||||
/* FIXME: need to make stage an 'actor' so can que
|
||||
* a paint direct from there rather than hack here...
|
||||
*/
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
||||
res = FALSE;
|
||||
}
|
||||
break;
|
||||
case KeyPress:
|
||||
event->type = CLUTTER_KEY_PRESS;
|
||||
translate_key_event (backend, event, xevent);
|
||||
set_user_time (backend_egl->xdpy, &xwindow, event);
|
||||
break;
|
||||
case KeyRelease:
|
||||
event->type = CLUTTER_KEY_RELEASE;
|
||||
translate_key_event (backend, event, xevent);
|
||||
break;
|
||||
case ButtonPress:
|
||||
switch (xevent->xbutton.button)
|
||||
{
|
||||
case 4: /* up */
|
||||
case 5: /* down */
|
||||
case 6: /* left */
|
||||
case 7: /* right */
|
||||
event->scroll.type = event->type = CLUTTER_SCROLL;
|
||||
|
||||
if (xevent->xbutton.button == 4)
|
||||
event->scroll.direction = CLUTTER_SCROLL_UP;
|
||||
else if (xevent->xbutton.button == 5)
|
||||
event->scroll.direction = CLUTTER_SCROLL_DOWN;
|
||||
else if (xevent->xbutton.button == 6)
|
||||
event->scroll.direction = CLUTTER_SCROLL_LEFT;
|
||||
else
|
||||
event->scroll.direction = CLUTTER_SCROLL_RIGHT;
|
||||
|
||||
event->scroll.time = xevent->xbutton.time;
|
||||
event->scroll.x = xevent->xbutton.x;
|
||||
event->scroll.y = xevent->xbutton.y;
|
||||
event->scroll.modifier_state = xevent->xbutton.state;
|
||||
|
||||
break;
|
||||
default:
|
||||
event->button.type = event->type = CLUTTER_BUTTON_PRESS;
|
||||
event->button.time = xevent->xbutton.time;
|
||||
event->button.x = xevent->xbutton.x;
|
||||
event->button.y = xevent->xbutton.y;
|
||||
event->button.modifier_state = xevent->xbutton.state;
|
||||
event->button.button = xevent->xbutton.button;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
set_user_time (backend_egl->xdpy, &xwindow, event);
|
||||
break;
|
||||
case ButtonRelease:
|
||||
/* scroll events don't have a corresponding release */
|
||||
if (xevent->xbutton.button == 4 ||
|
||||
xevent->xbutton.button == 5 ||
|
||||
xevent->xbutton.button == 6 ||
|
||||
xevent->xbutton.button == 7)
|
||||
{
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
|
||||
event->button.time = xevent->xbutton.time;
|
||||
event->button.x = xevent->xbutton.x;
|
||||
event->button.y = xevent->xbutton.y;
|
||||
event->button.modifier_state = xevent->xbutton.state;
|
||||
event->button.button = xevent->xbutton.button;
|
||||
break;
|
||||
case MotionNotify:
|
||||
event->motion.type = event->type = CLUTTER_MOTION;
|
||||
event->motion.time = xevent->xmotion.time;
|
||||
event->motion.x = xevent->xmotion.x;
|
||||
event->motion.y = xevent->xmotion.y;
|
||||
event->motion.modifier_state = xevent->xmotion.state;
|
||||
break;
|
||||
case DestroyNotify:
|
||||
CLUTTER_NOTE (EVENT, "destroy notify:\twindow: %ld",
|
||||
xevent->xdestroywindow.window);
|
||||
event->type = event->any.type = CLUTTER_DESTROY_NOTIFY;
|
||||
break;
|
||||
default:
|
||||
/* ignore every other event */
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
events_queue (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
|
||||
ClutterEvent *event;
|
||||
XEvent xevent;
|
||||
ClutterMainContext *clutter_context;
|
||||
|
||||
clutter_context = clutter_context_get_default ();
|
||||
|
||||
Display *xdisplay = backend_egl->xdpy;
|
||||
|
||||
while (!clutter_events_pending () && XPending (xdisplay))
|
||||
{
|
||||
XNextEvent (xdisplay, &xevent);
|
||||
|
||||
event = clutter_event_new (CLUTTER_NOTHING);
|
||||
if (clutter_event_translate (backend, event, &xevent))
|
||||
{
|
||||
g_queue_push_head (clutter_context->events_queue, event);
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_event_free (event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_event_prepare (GSource *source,
|
||||
gint *timeout)
|
||||
{
|
||||
ClutterBackend *backend = ((ClutterEventSource *) source)->backend;
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
*timeout = -1;
|
||||
retval = (clutter_events_pending () || clutter_check_xpending (backend));
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_event_check (GSource *source)
|
||||
{
|
||||
ClutterEventSource *event_source = (ClutterEventSource *) source;
|
||||
ClutterBackend *backend = event_source->backend;
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
if (event_source->event_poll_fd.revents & G_IO_IN)
|
||||
retval = (clutter_events_pending () || clutter_check_xpending (backend));
|
||||
else
|
||||
retval = FALSE;
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_event_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
ClutterBackend *backend = ((ClutterEventSource *) source)->backend;
|
||||
ClutterEvent *event;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
events_queue (backend);
|
||||
|
||||
event = clutter_event_get ();
|
||||
|
||||
if (event)
|
||||
{
|
||||
clutter_do_event (event);
|
||||
clutter_event_free (event);
|
||||
}
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return TRUE;
|
||||
}
|
@ -15,39 +15,13 @@
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-units.h"
|
||||
|
||||
#ifdef HAVE_XFIXES
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (ClutterStageEGL, clutter_stage_egl, CLUTTER_TYPE_STAGE);
|
||||
|
||||
/* This is currently an EGL on X implementation (eg for use with vincent)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
clutter_stage_egl_show (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
|
||||
|
||||
if (stage_egl->xwin)
|
||||
XMapWindow (stage_egl->xdpy, stage_egl->xwin);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_egl_hide (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
|
||||
|
||||
if (stage_egl->xwin)
|
||||
XUnmapWindow (stage_egl->xdpy, stage_egl->xwin);
|
||||
}
|
||||
G_DEFINE_TYPE (ClutterStageEGL, clutter_stage_egl, CLUTTER_TYPE_STAGE_X11);
|
||||
|
||||
static void
|
||||
clutter_stage_egl_unrealize (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
|
||||
gboolean was_offscreen;
|
||||
|
||||
CLUTTER_MARK();
|
||||
@ -60,13 +34,13 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stage_egl->xwin != None)
|
||||
if (stage_x11->xwin != None)
|
||||
{
|
||||
XDestroyWindow (stage_egl->xdpy, stage_egl->xwin);
|
||||
stage_egl->xwin = None;
|
||||
XDestroyWindow (stage_x11->xdpy, stage_x11->xwin);
|
||||
stage_x11->xwin = None;
|
||||
}
|
||||
else
|
||||
stage_egl->xwin = None;
|
||||
stage_x11->xwin = None;
|
||||
}
|
||||
|
||||
if (stage_egl->egl_surface)
|
||||
@ -87,6 +61,7 @@ static void
|
||||
clutter_stage_egl_realize (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
|
||||
|
||||
EGLConfig configs[2];
|
||||
EGLint config_count;
|
||||
@ -123,19 +98,19 @@ clutter_stage_egl_realize (ClutterActor *actor)
|
||||
if (status != EGL_TRUE)
|
||||
g_warning ("eglChooseConfig");
|
||||
|
||||
if (stage_egl->xwin == None)
|
||||
stage_egl->xwin
|
||||
= XCreateSimpleWindow(clutter_eglx_get_default_xdisplay(),
|
||||
clutter_eglx_get_default_root_window(),
|
||||
if (stage_x11->xwin == None)
|
||||
stage_x11->xwin
|
||||
= XCreateSimpleWindow(stage_x11->xdpy,
|
||||
stage_x11->xwin_root,
|
||||
0, 0,
|
||||
stage_egl->xwin_width,
|
||||
stage_egl->xwin_height,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height,
|
||||
0, 0,
|
||||
WhitePixel(clutter_eglx_get_default_xdisplay(),
|
||||
clutter_eglx_get_default_screen()));
|
||||
WhitePixel (stage_x11->xdpy,
|
||||
stage_x11->xscreen));
|
||||
|
||||
XSelectInput(clutter_eglx_get_default_xdisplay(),
|
||||
stage_egl->xwin,
|
||||
XSelectInput(stage_x11->xdpy,
|
||||
stage_x11->xwin,
|
||||
StructureNotifyMask
|
||||
|ExposureMask
|
||||
/* FIXME: we may want to eplicity enable MotionMask */
|
||||
@ -155,7 +130,7 @@ clutter_stage_egl_realize (ClutterActor *actor)
|
||||
stage_egl->egl_surface
|
||||
= eglCreateWindowSurface (clutter_eglx_display(),
|
||||
configs[0],
|
||||
(NativeWindowType)stage_egl->xwin,
|
||||
(NativeWindowType)stage_x11->xwin,
|
||||
NULL);
|
||||
|
||||
if (stage_egl->egl_surface == EGL_NO_SURFACE)
|
||||
@ -176,8 +151,6 @@ clutter_stage_egl_realize (ClutterActor *actor)
|
||||
|
||||
if (status != EGL_TRUE)
|
||||
g_warning ("eglMakeCurrent");
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -187,137 +160,6 @@ clutter_stage_egl_realize (ClutterActor *actor)
|
||||
CLUTTER_SET_PRIVATE_FLAGS(actor, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_egl_query_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (self);
|
||||
|
||||
box->x1 = box->y1 = 0;
|
||||
box->x2 = box->x1 + CLUTTER_UNITS_FROM_INT (stage_egl->xwin_width);
|
||||
box->y2 = box->y1 + CLUTTER_UNITS_FROM_INT (stage_egl->xwin_height);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_egl_request_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (self);
|
||||
gint new_width, new_height;
|
||||
|
||||
/* FIXME: some how have X configure_notfiys call this ? */
|
||||
new_width = ABS (CLUTTER_UNITS_TO_INT (box->x2 - box->x1));
|
||||
new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1));
|
||||
|
||||
if (new_width != stage_egl->xwin_width ||
|
||||
new_height != stage_egl->xwin_height)
|
||||
{
|
||||
stage_egl->xwin_width = new_width;
|
||||
stage_egl->xwin_height = new_height;
|
||||
|
||||
if (stage_egl->xwin != None)
|
||||
XResizeWindow (stage_egl->xdpy,
|
||||
stage_egl->xwin,
|
||||
stage_egl->xwin_width,
|
||||
stage_egl->xwin_height);
|
||||
|
||||
CLUTTER_SET_PRIVATE_FLAGS(self, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
if (stage_egl->xwin != None) /* Do we want to bother ? */
|
||||
XMoveWindow (stage_egl->xdpy,
|
||||
stage_egl->xwin,
|
||||
CLUTTER_UNITS_TO_INT (box->x1),
|
||||
CLUTTER_UNITS_TO_INT (box->y1));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_egl_set_fullscreen (ClutterStage *stage,
|
||||
gboolean fullscreen)
|
||||
{
|
||||
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage);
|
||||
Atom atom_WM_STATE, atom_WM_STATE_FULLSCREEN;
|
||||
|
||||
atom_WM_STATE = XInternAtom (stage_egl->xdpy, "_NET_WM_STATE", False);
|
||||
atom_WM_STATE_FULLSCREEN = XInternAtom (stage_egl->xdpy,
|
||||
"_NET_WM_STATE_FULLSCREEN",
|
||||
False);
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
gint width, height;
|
||||
|
||||
width = DisplayWidth (stage_egl->xdpy, stage_egl->xscreen);
|
||||
height = DisplayHeight (stage_egl->xdpy, stage_egl->xscreen);
|
||||
|
||||
clutter_actor_set_size (CLUTTER_ACTOR (stage_egl), width, height);
|
||||
|
||||
if (stage_egl->xwin != None)
|
||||
XChangeProperty (stage_egl->xdpy,
|
||||
stage_egl->xwin,
|
||||
atom_WM_STATE, XA_ATOM, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char *) &atom_WM_STATE_FULLSCREEN, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stage_egl->xwin != None)
|
||||
XDeleteProperty (stage_egl->xdpy, stage_egl->xwin, atom_WM_STATE);
|
||||
}
|
||||
|
||||
CLUTTER_SET_PRIVATE_FLAGS(stage, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_egl_set_cursor_visible (ClutterStage *stage,
|
||||
gboolean show_cursor)
|
||||
{
|
||||
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage);
|
||||
|
||||
if (stage_egl->xwin == None)
|
||||
return;
|
||||
|
||||
CLUTTER_NOTE (MISC, "setting cursor state (%s) over stage window (%u)",
|
||||
show_cursor ? "visible" : "invisible",
|
||||
(unsigned int) stage_egl->xwin);
|
||||
|
||||
if (show_cursor)
|
||||
{
|
||||
#ifdef HAVE_XFIXES
|
||||
XFixesShowCursor (stage_egl->xdpy, stage_egl->xwin);
|
||||
#else
|
||||
XUndefineCursor (stage_egl->xdpy, stage_egl->xwin);
|
||||
#endif /* HAVE_XFIXES */
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_XFIXES
|
||||
XFixesHideCursor (stage_egl->xdpy, stage_egl->xwin);
|
||||
#else
|
||||
XColor col;
|
||||
Pixmap pix;
|
||||
Cursor curs;
|
||||
|
||||
pix = XCreatePixmap (stage_egl->xdpy, stage_egl->xwin, 1, 1, 1);
|
||||
memset (&col, 0, sizeof (col));
|
||||
curs = XCreatePixmapCursor (stage_egl->xdpy,
|
||||
pix, pix,
|
||||
&col, &col,
|
||||
1, 1);
|
||||
XFreePixmap (stage_egl->xdpy, pix);
|
||||
XDefineCursor (stage_egl->xdpy, stage_egl->xwin, curs);
|
||||
#endif /* HAVE_XFIXES */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_egl_set_offscreen (ClutterStage *stage,
|
||||
gboolean offscreen)
|
||||
{
|
||||
g_warning ("Stage of type `%s' do not support ClutterStage::set_offscreen",
|
||||
G_OBJECT_TYPE_NAME (stage));
|
||||
}
|
||||
|
||||
static GdkPixbuf*
|
||||
clutter_stage_egl_draw_to_pixbuf (ClutterStage *stage,
|
||||
gint x,
|
||||
@ -334,8 +176,9 @@ static void
|
||||
clutter_stage_egl_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (gobject);
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject);
|
||||
|
||||
if (stage_egl->xwin)
|
||||
if (stage_x11->xwin)
|
||||
clutter_actor_unrealize (CLUTTER_ACTOR (stage_egl));
|
||||
|
||||
G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject);
|
||||
@ -350,83 +193,15 @@ clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
|
||||
|
||||
gobject_class->dispose = clutter_stage_egl_dispose;
|
||||
|
||||
actor_class->show = clutter_stage_egl_show;
|
||||
actor_class->hide = clutter_stage_egl_hide;
|
||||
actor_class->realize = clutter_stage_egl_realize;
|
||||
actor_class->unrealize = clutter_stage_egl_unrealize;
|
||||
actor_class->request_coords = clutter_stage_egl_request_coords;
|
||||
actor_class->query_coords = clutter_stage_egl_query_coords;
|
||||
|
||||
stage_class->set_fullscreen = clutter_stage_egl_set_fullscreen;
|
||||
stage_class->set_cursor_visible = clutter_stage_egl_set_cursor_visible;
|
||||
stage_class->set_offscreen = clutter_stage_egl_set_offscreen;
|
||||
stage_class->draw_to_pixbuf = clutter_stage_egl_draw_to_pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_egl_init (ClutterStageEGL *stage)
|
||||
{
|
||||
stage->xdpy = NULL;
|
||||
stage->xwin_root = None;
|
||||
stage->xscreen = 0;
|
||||
|
||||
stage->xwin = None;
|
||||
stage->xwin_width = 640;
|
||||
stage->xwin_height = 480;
|
||||
stage->xvisinfo = None;
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_eglx_get_stage_window:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
Window
|
||||
clutter_eglx_get_stage_window (ClutterStage *stage)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_EGL (stage), None);
|
||||
|
||||
return CLUTTER_STAGE_EGL (stage)->xwin;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_eglx_get_stage_visual:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
XVisualInfo *
|
||||
clutter_eglx_get_stage_visual (ClutterStage *stage)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_EGL (stage), NULL);
|
||||
|
||||
return CLUTTER_STAGE_EGL (stage)->xvisinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_eglx_set_stage_foreign:
|
||||
* @stage: a #ClutterStage
|
||||
* @window: FIXME
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
void
|
||||
clutter_eglx_set_stage_foreign (ClutterStage *stage,
|
||||
Window window)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_STAGE_EGL (stage));
|
||||
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/egl.h>
|
||||
|
||||
#include "../x11/clutter-stage-x11.h"
|
||||
|
||||
#define CLUTTER_TYPE_STAGE_EGL (clutter_stage_egl_get_type ())
|
||||
#define CLUTTER_STAGE_EGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_EGL, ClutterStageEGL))
|
||||
@ -24,16 +25,7 @@ typedef struct _ClutterStageEGLClass ClutterStageEGLClass;
|
||||
|
||||
struct _ClutterStageEGL
|
||||
{
|
||||
ClutterStage parent_instance;
|
||||
|
||||
/* from the backend */
|
||||
Display *xdpy;
|
||||
Window xwin_root;
|
||||
int xscreen;
|
||||
XVisualInfo *xvisinfo;
|
||||
Window xwin;
|
||||
gint xwin_width;
|
||||
gint xwin_height;
|
||||
ClutterStageX11 parent_instance;
|
||||
|
||||
EGLSurface egl_surface;
|
||||
EGLContext egl_context;
|
||||
@ -41,7 +33,7 @@ struct _ClutterStageEGL
|
||||
|
||||
struct _ClutterStageEGLClass
|
||||
{
|
||||
ClutterStageClass parent_class;
|
||||
ClutterStageX11Class parent_class;
|
||||
};
|
||||
|
||||
GType clutter_stage_egl_get_type (void) G_GNUC_CONST;
|
||||
|
@ -17,7 +17,6 @@ noinst_LTLIBRARIES = libclutter-glx.la
|
||||
libclutter_glx_la_SOURCES = \
|
||||
clutter-backend-glx.h \
|
||||
clutter-backend-glx.c \
|
||||
clutter-event-glx.c \
|
||||
clutter-stage-glx.h \
|
||||
clutter-stage-glx.c \
|
||||
clutter-glx.h
|
||||
|
@ -37,8 +37,6 @@
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
|
||||
|
||||
#include "clutter-backend-glx.h"
|
||||
#include "clutter-stage-glx.h"
|
||||
#include "clutter-glx.h"
|
||||
@ -50,20 +48,11 @@
|
||||
|
||||
#include "cogl.h"
|
||||
|
||||
G_DEFINE_TYPE (ClutterBackendGLX, clutter_backend_glx, CLUTTER_TYPE_BACKEND);
|
||||
G_DEFINE_TYPE (ClutterBackendGLX, clutter_backend_glx, CLUTTER_TYPE_BACKEND_X11);
|
||||
|
||||
/* singleton object */
|
||||
static ClutterBackendGLX *backend_singleton = NULL;
|
||||
|
||||
/* options */
|
||||
static gchar *clutter_display_name = NULL;
|
||||
static gint clutter_screen = 0;
|
||||
static gboolean clutter_synchronise = FALSE;
|
||||
|
||||
/* X error trap */
|
||||
static int TrappedErrorCode = 0;
|
||||
static int (* old_error_handler) (Display *, XErrorEvent *);
|
||||
|
||||
static gchar *clutter_vblank_name = NULL;
|
||||
|
||||
#ifdef __linux__
|
||||
@ -120,16 +109,6 @@ clutter_backend_glx_pre_parse (ClutterBackend *backend,
|
||||
{
|
||||
const gchar *env_string;
|
||||
|
||||
/* we don't fail here if DISPLAY is not set, as the user
|
||||
* might pass the --display command line switch
|
||||
*/
|
||||
env_string = g_getenv ("DISPLAY");
|
||||
if (env_string)
|
||||
{
|
||||
clutter_display_name = g_strdup (env_string);
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
env_string = g_getenv ("CLUTTER_VBLANK");
|
||||
if (env_string)
|
||||
{
|
||||
@ -137,53 +116,19 @@ clutter_backend_glx_pre_parse (ClutterBackend *backend,
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return clutter_backend_x11_pre_parse (backend, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_backend_glx_post_parse (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
|
||||
|
||||
if (clutter_display_name)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "XOpenDisplay on `%s'", clutter_display_name);
|
||||
backend_glx->xdpy = XOpenDisplay (clutter_display_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_BACKEND,
|
||||
"Unable to open display. You have to set the DISPLAY "
|
||||
"environment variable, or use the --display command "
|
||||
"line argument");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (backend_glx->xdpy)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
int glx_major, glx_minor;
|
||||
double dpi;
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Getting the X screen");
|
||||
|
||||
if (clutter_screen == 0)
|
||||
backend_glx->xscreen = DefaultScreenOfDisplay (backend_glx->xdpy);
|
||||
else
|
||||
backend_glx->xscreen = ScreenOfDisplay (backend_glx->xdpy,
|
||||
clutter_screen);
|
||||
|
||||
backend_glx->xscreen_num = XScreenNumberOfScreen (backend_glx->xscreen);
|
||||
|
||||
backend_glx->xwin_root = RootWindow (backend_glx->xdpy,
|
||||
backend_glx->xscreen_num);
|
||||
|
||||
backend_glx->display_name = g_strdup (clutter_display_name);
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Checking GLX info");
|
||||
|
||||
if (!glXQueryVersion (backend_glx->xdpy, &glx_major, &glx_minor)
|
||||
if (clutter_backend_x11_post_parse (backend, error))
|
||||
{
|
||||
if (!glXQueryVersion (backend_x11->xdpy, &glx_major, &glx_minor)
|
||||
|| !(glx_major > 1 || glx_minor > 1))
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
@ -191,128 +136,19 @@ clutter_backend_glx_post_parse (ClutterBackend *backend,
|
||||
"XServer appears to lack required GLX support");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Prefer current GLX specs over current violations */
|
||||
if (!(glx_major > 1 || glx_minor > 2))
|
||||
{
|
||||
|
||||
const char* exts = glXQueryExtensionsString (display, screen);
|
||||
if (!exts || !strstr (exts, "GLX_SGIX_fbconfig"))
|
||||
have_fbconfig = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
dpi = (((double) DisplayHeight (backend_glx->xdpy, backend_glx->xscreen_num) * 25.4)
|
||||
/ (double) DisplayHeightMM (backend_glx->xdpy, backend_glx->xscreen_num));
|
||||
|
||||
clutter_backend_set_resolution (backend, dpi);
|
||||
|
||||
if (clutter_synchronise)
|
||||
XSynchronize (backend_glx->xdpy, True);
|
||||
|
||||
backend_glx->atom_WM_STATE
|
||||
= XInternAtom (backend_glx->xdpy, "_NET_WM_STATE", False);
|
||||
backend_glx->atom_WM_STATE_FULLSCREEN
|
||||
= XInternAtom (backend_glx->xdpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
}
|
||||
|
||||
g_free (clutter_display_name);
|
||||
|
||||
CLUTTER_NOTE (BACKEND,
|
||||
"X Display `%s'[%p] opened (screen:%d, root:%u, dpi:%f)",
|
||||
backend_glx->display_name,
|
||||
backend_glx->xdpy,
|
||||
backend_glx->xscreen_num,
|
||||
(unsigned int) backend_glx->xwin_root,
|
||||
clutter_backend_get_resolution (backend));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
clutter_backend_glx_init_stage (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
|
||||
|
||||
if (!backend_glx->stage)
|
||||
{
|
||||
ClutterStageGLX *stage_glx;
|
||||
ClutterActor *stage;
|
||||
|
||||
stage = g_object_new (CLUTTER_TYPE_STAGE_GLX, NULL);
|
||||
|
||||
/* copy backend data into the stage */
|
||||
stage_glx = CLUTTER_STAGE_GLX (stage);
|
||||
stage_glx->xdpy = backend_glx->xdpy;
|
||||
stage_glx->xwin_root = backend_glx->xwin_root;
|
||||
stage_glx->xscreen = backend_glx->xscreen_num;
|
||||
stage_glx->backend = backend_glx;
|
||||
|
||||
CLUTTER_NOTE (MISC, "GLX stage created (display:%p, screen:%d, root:%u)",
|
||||
stage_glx->xdpy,
|
||||
stage_glx->xscreen,
|
||||
(unsigned int) stage_glx->xwin_root);
|
||||
|
||||
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
|
||||
|
||||
backend_glx->stage = g_object_ref_sink (stage);
|
||||
}
|
||||
|
||||
clutter_actor_realize (backend_glx->stage);
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (backend_glx->stage))
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_INTERNAL,
|
||||
"Unable to realize the main stage");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_glx_init_events (ClutterBackend *backend)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "initialising the event loop");
|
||||
|
||||
_clutter_backend_glx_events_init (backend);
|
||||
}
|
||||
|
||||
static ClutterActor *
|
||||
clutter_backend_glx_get_stage (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
|
||||
|
||||
return backend_glx->stage;
|
||||
}
|
||||
|
||||
static const GOptionEntry entries[] =
|
||||
{
|
||||
{
|
||||
"display", 0,
|
||||
G_OPTION_FLAG_IN_MAIN,
|
||||
G_OPTION_ARG_STRING, &clutter_display_name,
|
||||
"X display to use", "DISPLAY"
|
||||
},
|
||||
{
|
||||
"screen", 0,
|
||||
G_OPTION_FLAG_IN_MAIN,
|
||||
G_OPTION_ARG_INT, &clutter_screen,
|
||||
"X screen to use", "SCREEN"
|
||||
},
|
||||
{ "vblank", 0,
|
||||
0,
|
||||
G_OPTION_ARG_STRING, &clutter_vblank_name,
|
||||
"VBlank method to be used (none, dri or glx)", "METHOD"
|
||||
},
|
||||
{ "synch", 0,
|
||||
0,
|
||||
G_OPTION_ARG_NONE, &clutter_synchronise,
|
||||
"Make X calls synchronous", NULL,
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -321,17 +157,12 @@ clutter_backend_glx_add_options (ClutterBackend *backend,
|
||||
GOptionGroup *group)
|
||||
{
|
||||
g_option_group_add_entries (group, entries);
|
||||
clutter_backend_x11_add_options (backend, group);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_glx_finalize (GObject *gobject)
|
||||
{
|
||||
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (gobject);
|
||||
|
||||
g_free (backend_glx->display_name);
|
||||
|
||||
XCloseDisplay (backend_glx->xdpy);
|
||||
|
||||
if (backend_singleton)
|
||||
backend_singleton = NULL;
|
||||
|
||||
@ -341,19 +172,6 @@ clutter_backend_glx_finalize (GObject *gobject)
|
||||
static void
|
||||
clutter_backend_glx_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (gobject);
|
||||
|
||||
if (backend_glx->stage)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "Disposing the main stage");
|
||||
|
||||
clutter_actor_destroy (backend_glx->stage);
|
||||
backend_glx->stage = NULL;
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Removing the event source");
|
||||
_clutter_backend_glx_events_uninit (CLUTTER_BACKEND (backend_glx));
|
||||
|
||||
G_OBJECT_CLASS (clutter_backend_glx_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
@ -390,7 +208,6 @@ check_vblank_env (const char *name)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static ClutterFeatureFlags
|
||||
clutter_backend_glx_get_features (ClutterBackend *backend)
|
||||
{
|
||||
@ -400,8 +217,6 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
|
||||
|
||||
/* FIXME: we really need to check if gl context is set */
|
||||
|
||||
flags = CLUTTER_FEATURE_STAGE_USER_RESIZE|CLUTTER_FEATURE_STAGE_CURSOR;
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Checking features\n"
|
||||
"GL_VENDOR: %s\n"
|
||||
"GL_RENDERER: %s\n"
|
||||
@ -413,8 +228,8 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
|
||||
glGetString (GL_EXTENSIONS));
|
||||
|
||||
glx_extensions =
|
||||
glXQueryExtensionsString (clutter_glx_get_default_display (),
|
||||
clutter_glx_get_default_screen ());
|
||||
glXQueryExtensionsString (clutter_x11_get_default_display (),
|
||||
clutter_x11_get_default_screen ());
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "GLX Extensions: %s", glx_extensions);
|
||||
|
||||
@ -512,26 +327,28 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
|
||||
|
||||
CLUTTER_NOTE (MISC, "backend features checked");
|
||||
|
||||
return flags;
|
||||
return flags|clutter_backend_x11_get_features (backend);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_glx_redraw (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
ClutterStageGLX *stage_glx;
|
||||
ClutterStageX11 *stage_x11;
|
||||
|
||||
stage_glx = CLUTTER_STAGE_GLX(backend_glx->stage);
|
||||
stage_x11 = CLUTTER_STAGE_X11(backend_x11->stage);
|
||||
stage_glx = CLUTTER_STAGE_GLX(backend_x11->stage);
|
||||
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage_glx));
|
||||
|
||||
/* Why this paint is done in backend as likely GL windowing system
|
||||
* specific calls, like swapping buffers.
|
||||
*/
|
||||
if (stage_glx->xwin)
|
||||
if (stage_x11->xwin)
|
||||
{
|
||||
clutter_backend_glx_wait_for_vblank (stage_glx->backend);
|
||||
glXSwapBuffers (stage_glx->xdpy, stage_glx->xwin);
|
||||
clutter_backend_glx_wait_for_vblank (CLUTTER_BACKEND_GLX(backend));
|
||||
glXSwapBuffers (stage_x11->xdpy, stage_x11->xwin);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -539,9 +356,52 @@ clutter_backend_glx_redraw (ClutterBackend *backend)
|
||||
glXWaitGL ();
|
||||
CLUTTER_GLERR ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_backend_glx_init_stage (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
if (!backend_x11->stage)
|
||||
{
|
||||
ClutterStageX11 *stage_x11;
|
||||
ClutterActor *stage;
|
||||
|
||||
stage = g_object_new (CLUTTER_TYPE_STAGE_GLX, NULL);
|
||||
|
||||
/* copy backend data into the stage */
|
||||
stage_x11 = CLUTTER_STAGE_X11 (stage);
|
||||
stage_x11->xdpy = backend_x11->xdpy;
|
||||
stage_x11->xwin_root = backend_x11->xwin_root;
|
||||
stage_x11->xscreen = backend_x11->xscreen_num;
|
||||
stage_x11->backend = backend_x11;
|
||||
|
||||
CLUTTER_NOTE (MISC, "X11 stage created (display:%p, screen:%d, root:%u)",
|
||||
stage_x11->xdpy,
|
||||
stage_x11->xscreen,
|
||||
(unsigned int) stage_x11->xwin_root);
|
||||
|
||||
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
|
||||
|
||||
backend_x11->stage = g_object_ref_sink (stage);
|
||||
}
|
||||
|
||||
clutter_actor_realize (backend_x11->stage);
|
||||
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (backend_x11->stage))
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_INTERNAL,
|
||||
"Unable to realize the main stage");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
|
||||
{
|
||||
@ -555,8 +415,6 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
|
||||
backend_class->pre_parse = clutter_backend_glx_pre_parse;
|
||||
backend_class->post_parse = clutter_backend_glx_post_parse;
|
||||
backend_class->init_stage = clutter_backend_glx_init_stage;
|
||||
backend_class->init_events = clutter_backend_glx_init_events;
|
||||
backend_class->get_stage = clutter_backend_glx_get_stage;
|
||||
backend_class->add_options = clutter_backend_glx_add_options;
|
||||
backend_class->get_features = clutter_backend_glx_get_features;
|
||||
backend_class->redraw = clutter_backend_glx_redraw;
|
||||
@ -565,12 +423,7 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
|
||||
static void
|
||||
clutter_backend_glx_init (ClutterBackendGLX *backend_glx)
|
||||
{
|
||||
ClutterBackend *backend = CLUTTER_BACKEND (backend_glx);
|
||||
|
||||
/* FIXME: get from xsettings */
|
||||
clutter_backend_set_double_click_time (backend, 250);
|
||||
clutter_backend_set_double_click_distance (backend, 5);
|
||||
clutter_backend_set_resolution (backend, 96.0);
|
||||
;
|
||||
}
|
||||
|
||||
/* every backend must implement this function */
|
||||
@ -580,14 +433,6 @@ _clutter_backend_impl_get_type (void)
|
||||
return clutter_backend_glx_get_type ();
|
||||
}
|
||||
|
||||
static int
|
||||
error_handler(Display *xdpy,
|
||||
XErrorEvent *error)
|
||||
{
|
||||
TrappedErrorCode = error->error_code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
clutter_backend_glx_wait_for_vblank (ClutterBackendGLX *backend_glx)
|
||||
{
|
||||
@ -623,175 +468,3 @@ clutter_backend_glx_wait_for_vblank (ClutterBackendGLX *backend_glx)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* clutter_glx_trap_x_errors:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
void
|
||||
clutter_glx_trap_x_errors (void)
|
||||
{
|
||||
TrappedErrorCode = 0;
|
||||
old_error_handler = XSetErrorHandler (error_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_untrap_x_errors:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
gint
|
||||
clutter_glx_untrap_x_errors (void)
|
||||
{
|
||||
XSetErrorHandler (old_error_handler);
|
||||
|
||||
return TrappedErrorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_get_default_display:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
Display *
|
||||
clutter_glx_get_default_display (void)
|
||||
{
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("GLX backend has not been initialised");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return backend_singleton->xdpy;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_get_default_screen:
|
||||
*
|
||||
* Gets the number of the default X Screen object.
|
||||
*
|
||||
* Return value: the number of the default Screen object.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
int
|
||||
clutter_glx_get_default_screen (void)
|
||||
{
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("GLX backend has not been initialised");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return backend_singleton->xscreen_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_get_root_window:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
Window
|
||||
clutter_glx_get_root_window (void)
|
||||
{
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("GLX backend has not been initialised");
|
||||
return None;
|
||||
}
|
||||
|
||||
return backend_singleton->xwin_root;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_add_filter:
|
||||
* @func: an event filter function
|
||||
* @data: user data to pass to the function, or %NULL
|
||||
*
|
||||
* Adds @func to the list of event filters. Filter functions
|
||||
* receive the raw events and must return %CLUTTER_GLX_FILTER_CONTINUE
|
||||
* if the event should be processed by Clutter, %CLUTTER_GLX_FILTER_TRANSLATE
|
||||
* if the event has been translated by the function and it's ready
|
||||
* to be sent to the stage, or %CLUTTER_GLX_FILTER_REMOVE if the event should
|
||||
* not be sent to the stage.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
void
|
||||
clutter_glx_add_filter (ClutterGLXFilterFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
ClutterGLXEventFilter *filter;
|
||||
|
||||
g_return_if_fail (func != NULL);
|
||||
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("GLX backend has not been initialised");
|
||||
return;
|
||||
}
|
||||
|
||||
filter = g_new0(ClutterGLXEventFilter, 1);
|
||||
filter->func = func;
|
||||
filter->data = data;
|
||||
|
||||
backend_singleton->event_filters =
|
||||
g_slist_append (backend_singleton->event_filters, filter);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_remove_filter:
|
||||
* @func: the filter function to remove
|
||||
* @data: user data of the filter function, or %NULL
|
||||
*
|
||||
* Removes @func from the list of filter functions installed
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
void
|
||||
clutter_glx_remove_filter (ClutterGLXFilterFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
GSList *tmp_list, *this;
|
||||
ClutterGLXEventFilter *filter;
|
||||
|
||||
g_return_if_fail (func == NULL);
|
||||
|
||||
tmp_list = backend_singleton->event_filters;
|
||||
|
||||
while (tmp_list)
|
||||
{
|
||||
filter = (ClutterGLXEventFilter *)tmp_list->data;
|
||||
this = tmp_list;
|
||||
tmp_list = tmp_list->next;
|
||||
|
||||
if (filter->func == func && filter->data == data)
|
||||
{
|
||||
backend_singleton->event_filters =
|
||||
g_slist_remove_link (backend_singleton->event_filters, this);
|
||||
|
||||
g_slist_free_1 (this);
|
||||
g_free (filter);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include "../x11/clutter-backend-x11.h"
|
||||
#include "clutter-glx.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@ -59,29 +60,9 @@ typedef int (*WaitVideoSyncProc) (int divisor,
|
||||
unsigned int *count);
|
||||
typedef int (*SwapIntervalProc) (int interval);
|
||||
|
||||
typedef struct _ClutterGLXEventFilter
|
||||
{
|
||||
ClutterGLXFilterFunc func;
|
||||
gpointer data;
|
||||
|
||||
} ClutterGLXEventFilter;
|
||||
|
||||
struct _ClutterBackendGLX
|
||||
{
|
||||
ClutterBackend parent_instance;
|
||||
|
||||
Display *xdpy;
|
||||
Window xwin_root;
|
||||
Screen *xscreen;
|
||||
int xscreen_num;
|
||||
gchar *display_name;
|
||||
|
||||
/* main stage singleton */
|
||||
ClutterActor *stage;
|
||||
|
||||
/* event source */
|
||||
GSource *event_source;
|
||||
GSList *event_filters;
|
||||
ClutterBackendX11 parent_instance;
|
||||
|
||||
/* Vblank stuff */
|
||||
GetVideoSyncProc get_video_sync;
|
||||
@ -89,20 +70,13 @@ struct _ClutterBackendGLX
|
||||
SwapIntervalProc swap_interval;
|
||||
gint dri_fd;
|
||||
ClutterGLXVBlankType vblank_type;
|
||||
|
||||
/* props */
|
||||
Atom atom_WM_STATE;
|
||||
Atom atom_WM_STATE_FULLSCREEN;
|
||||
};
|
||||
|
||||
struct _ClutterBackendGLXClass
|
||||
{
|
||||
ClutterBackendClass parent_class;
|
||||
ClutterBackendX11Class parent_class;
|
||||
};
|
||||
|
||||
void _clutter_backend_glx_events_init (ClutterBackend *backend);
|
||||
void _clutter_backend_glx_events_uninit (ClutterBackend *backend);
|
||||
|
||||
void clutter_backend_glx_wait_for_vblank (ClutterBackendGLX *backend_glx);
|
||||
|
||||
GType clutter_backend_glx_get_type (void) G_GNUC_CONST;
|
||||
|
@ -27,9 +27,8 @@
|
||||
* SECTION:clutter-glx
|
||||
* @short_description: GLX specific API
|
||||
*
|
||||
* The GLX backend for Clutter provides some specific API, allowing
|
||||
* integration with the Xlibs API for embedding and manipulating the
|
||||
* stage window, or for trapping X errors.
|
||||
* The GLX backend for Clutter provides some specific API for GLX
|
||||
* related calls.
|
||||
*
|
||||
* The ClutterGLX API is available since Clutter 0.4
|
||||
*/
|
||||
@ -40,40 +39,10 @@
|
||||
#include <glib.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <clutter/clutter-stage.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
CLUTTER_GLX_FILTER_CONTINUE, /* Event not handled, continue processesing */
|
||||
CLUTTER_GLX_FILTER_TRANSLATE, /* Native event translated into a Clutter
|
||||
event and stored in the "event" structure
|
||||
that was passed in */
|
||||
CLUTTER_GLX_FILTER_REMOVE /* Terminate processing, removing event */
|
||||
} ClutterGLXFilterReturn;
|
||||
|
||||
typedef ClutterGLXFilterReturn (*ClutterGLXFilterFunc) (XEvent *xev,
|
||||
ClutterEvent *cev,
|
||||
gpointer *data);
|
||||
|
||||
void clutter_glx_trap_x_errors (void);
|
||||
gint clutter_glx_untrap_x_errors (void);
|
||||
|
||||
Display *clutter_glx_get_default_display (void);
|
||||
int clutter_glx_get_default_screen (void);
|
||||
Window clutter_glx_get_root_window (void);
|
||||
|
||||
Window clutter_glx_get_stage_window (ClutterStage *stage);
|
||||
XVisualInfo *clutter_glx_get_stage_visual (ClutterStage *stage);
|
||||
|
||||
gboolean clutter_glx_set_stage_foreign (ClutterStage *stage,
|
||||
Window xwindow);
|
||||
|
||||
void clutter_glx_add_filter (ClutterGLXFilterFunc func, gpointer data);
|
||||
|
||||
void clutter_glx_remove_filter (ClutterGLXFilterFunc func,
|
||||
gpointer data);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -39,172 +39,71 @@
|
||||
|
||||
#include "cogl.h"
|
||||
|
||||
#ifdef HAVE_XFIXES
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#endif
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
|
||||
|
||||
G_DEFINE_TYPE (ClutterStageGLX, clutter_stage_glx, CLUTTER_TYPE_STAGE);
|
||||
|
||||
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
||||
#define _NET_WM_STATE_ADD 1 /* add/set property */
|
||||
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
|
||||
|
||||
static void
|
||||
send_wmspec_change_state (ClutterBackendGLX *backend_glx,
|
||||
Window window,
|
||||
Atom state,
|
||||
gboolean add)
|
||||
{
|
||||
XClientMessageEvent xclient;
|
||||
|
||||
memset (&xclient, 0, sizeof (xclient));
|
||||
|
||||
xclient.type = ClientMessage;
|
||||
xclient.window = window;
|
||||
xclient.message_type = backend_glx->atom_WM_STATE;
|
||||
xclient.format = 32;
|
||||
|
||||
xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
|
||||
xclient.data.l[1] = state;
|
||||
xclient.data.l[2] = 0;
|
||||
xclient.data.l[3] = 0;
|
||||
xclient.data.l[4] = 0;
|
||||
|
||||
XSendEvent (backend_glx->xdpy,
|
||||
DefaultRootWindow(backend_glx->xdpy),
|
||||
False,
|
||||
SubstructureRedirectMask|SubstructureNotifyMask,
|
||||
(XEvent *)&xclient);
|
||||
}
|
||||
|
||||
static void
|
||||
fix_window_size (ClutterStageGLX *stage_glx)
|
||||
{
|
||||
gboolean resize;
|
||||
|
||||
resize = clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_glx));
|
||||
|
||||
if (stage_glx->xwin != None && stage_glx->is_foreign_xwin == FALSE)
|
||||
{
|
||||
XSizeHints *size_hints;
|
||||
|
||||
size_hints = XAllocSizeHints();
|
||||
|
||||
if (!resize)
|
||||
{
|
||||
size_hints->max_width
|
||||
= size_hints->min_width = stage_glx->xwin_width;
|
||||
size_hints->max_height
|
||||
= size_hints->min_height = stage_glx->xwin_height;
|
||||
size_hints->flags = PMinSize|PMaxSize;
|
||||
}
|
||||
|
||||
XSetWMNormalHints (stage_glx->xdpy, stage_glx->xwin, size_hints);
|
||||
|
||||
XFree(size_hints);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_show (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
|
||||
|
||||
/* Chain up to set mapped flags */
|
||||
CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->show(actor);
|
||||
|
||||
if (stage_glx->xwin)
|
||||
{
|
||||
/* Fire off a redraw to avoid flicker on first map.
|
||||
* Appears not to work perfectly on intel drivers at least.
|
||||
*/
|
||||
clutter_redraw();
|
||||
XSync (stage_glx->xdpy, FALSE);
|
||||
XMapWindow (stage_glx->xdpy, stage_glx->xwin);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_hide (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
|
||||
|
||||
if (stage_glx->xwin)
|
||||
XUnmapWindow (stage_glx->xdpy, stage_glx->xwin);
|
||||
}
|
||||
G_DEFINE_TYPE (ClutterStageGLX, clutter_stage_glx, CLUTTER_TYPE_STAGE_X11);
|
||||
|
||||
static void
|
||||
clutter_stage_glx_unrealize (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
|
||||
|
||||
gboolean was_offscreen;
|
||||
|
||||
CLUTTER_MARK();
|
||||
|
||||
g_object_get (actor, "offscreen", &was_offscreen, NULL);
|
||||
|
||||
clutter_glx_trap_x_errors ();
|
||||
clutter_x11_trap_x_errors ();
|
||||
|
||||
if (G_UNLIKELY (was_offscreen))
|
||||
{
|
||||
if (stage_glx->glxpixmap)
|
||||
{
|
||||
glXDestroyGLXPixmap (stage_glx->xdpy, stage_glx->glxpixmap);
|
||||
glXDestroyGLXPixmap (stage_x11->xdpy,stage_glx->glxpixmap);
|
||||
stage_glx->glxpixmap = None;
|
||||
}
|
||||
|
||||
if (stage_glx->xpixmap)
|
||||
if (stage_x11->xpixmap)
|
||||
{
|
||||
XFreePixmap (stage_glx->xdpy, stage_glx->xpixmap);
|
||||
stage_glx->xpixmap = None;
|
||||
XFreePixmap (stage_x11->xdpy, stage_x11->xpixmap);
|
||||
stage_x11->xpixmap = None;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!stage_glx->is_foreign_xwin && stage_glx->xwin != None)
|
||||
if (!stage_x11->is_foreign_xwin && stage_x11->xwin != None)
|
||||
{
|
||||
XDestroyWindow (stage_glx->xdpy, stage_glx->xwin);
|
||||
stage_glx->xwin = None;
|
||||
XDestroyWindow (stage_x11->xdpy, stage_x11->xwin);
|
||||
stage_x11->xwin = None;
|
||||
}
|
||||
else
|
||||
stage_glx->xwin = None;
|
||||
stage_x11->xwin = None;
|
||||
}
|
||||
|
||||
glXMakeCurrent (stage_glx->xdpy, None, NULL);
|
||||
glXMakeCurrent (stage_x11->xdpy, None, NULL);
|
||||
|
||||
if (stage_glx->gl_context != None)
|
||||
{
|
||||
glXDestroyContext (stage_glx->xdpy, stage_glx->gl_context);
|
||||
glXDestroyContext (stage_x11->xdpy, stage_glx->gl_context);
|
||||
stage_glx->gl_context = None;
|
||||
}
|
||||
|
||||
XSync (stage_glx->xdpy, False);
|
||||
XSync (stage_x11->xdpy, False);
|
||||
|
||||
clutter_glx_untrap_x_errors ();
|
||||
clutter_x11_untrap_x_errors ();
|
||||
|
||||
CLUTTER_MARK ();
|
||||
}
|
||||
|
||||
static void
|
||||
set_wm_protocols (Display *xdisplay,
|
||||
Window xwindow)
|
||||
{
|
||||
Atom protocols[2];
|
||||
int n = 0;
|
||||
|
||||
protocols[n++] = XInternAtom (xdisplay, "WM_DELETE_WINDOW", False);
|
||||
protocols[n++] = XInternAtom (xdisplay, "_NET_WM_PING", False);
|
||||
|
||||
XSetWMProtocols (xdisplay, xwindow, protocols, n);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_realize (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
|
||||
gboolean is_offscreen;
|
||||
|
||||
@ -225,21 +124,21 @@ clutter_stage_glx_realize (ClutterActor *actor)
|
||||
0
|
||||
};
|
||||
|
||||
if (stage_glx->xvisinfo)
|
||||
XFree (stage_glx->xvisinfo);
|
||||
if (stage_x11->xvisinfo)
|
||||
XFree (stage_x11->xvisinfo);
|
||||
|
||||
if (stage_glx->xvisinfo == None)
|
||||
stage_glx->xvisinfo = glXChooseVisual (stage_glx->xdpy,
|
||||
stage_glx->xscreen,
|
||||
if (stage_x11->xvisinfo == None)
|
||||
stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy,
|
||||
stage_x11->xscreen,
|
||||
gl_attributes);
|
||||
if (!stage_glx->xvisinfo)
|
||||
if (!stage_x11->xvisinfo)
|
||||
{
|
||||
g_critical ("Unable to find suitable GL visual.");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stage_glx->xwin == None)
|
||||
if (stage_x11->xwin == None)
|
||||
{
|
||||
XSetWindowAttributes xattr;
|
||||
unsigned long mask;
|
||||
@ -247,28 +146,28 @@ clutter_stage_glx_realize (ClutterActor *actor)
|
||||
CLUTTER_NOTE (MISC, "Creating stage X window");
|
||||
|
||||
/* window attributes */
|
||||
xattr.background_pixel = WhitePixel (stage_glx->xdpy,
|
||||
stage_glx->xscreen);
|
||||
xattr.background_pixel = WhitePixel (stage_x11->xdpy,
|
||||
stage_x11->xscreen);
|
||||
xattr.border_pixel = 0;
|
||||
xattr.colormap = XCreateColormap (stage_glx->xdpy,
|
||||
stage_glx->xwin_root,
|
||||
stage_glx->xvisinfo->visual,
|
||||
xattr.colormap = XCreateColormap (stage_x11->xdpy,
|
||||
stage_x11->xwin_root,
|
||||
stage_x11->xvisinfo->visual,
|
||||
AllocNone);
|
||||
mask = CWBackPixel | CWBorderPixel | CWColormap;
|
||||
stage_glx->xwin = XCreateWindow (stage_glx->xdpy,
|
||||
stage_glx->xwin_root,
|
||||
stage_x11->xwin = XCreateWindow (stage_x11->xdpy,
|
||||
stage_x11->xwin_root,
|
||||
0, 0,
|
||||
stage_glx->xwin_width,
|
||||
stage_glx->xwin_height,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height,
|
||||
0,
|
||||
stage_glx->xvisinfo->depth,
|
||||
stage_x11->xvisinfo->depth,
|
||||
InputOutput,
|
||||
stage_glx->xvisinfo->visual,
|
||||
stage_x11->xvisinfo->visual,
|
||||
mask, &xattr);
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (MISC, "XSelectInput");
|
||||
XSelectInput (stage_glx->xdpy, stage_glx->xwin,
|
||||
XSelectInput (stage_x11->xdpy, stage_x11->xwin,
|
||||
StructureNotifyMask |
|
||||
FocusChangeMask |
|
||||
ExposureMask |
|
||||
@ -279,16 +178,16 @@ clutter_stage_glx_realize (ClutterActor *actor)
|
||||
PropertyChangeMask);
|
||||
|
||||
/* no user resize.. */
|
||||
fix_window_size (stage_glx);
|
||||
clutter_stage_x11_fix_window_size (stage_x11);
|
||||
|
||||
set_wm_protocols (stage_glx->xdpy, stage_glx->xwin);
|
||||
clutter_stage_x11_set_wm_protocols (stage_x11->xdpy, stage_x11->xwin);
|
||||
|
||||
if (stage_glx->gl_context)
|
||||
glXDestroyContext (stage_glx->xdpy, stage_glx->gl_context);
|
||||
glXDestroyContext (stage_x11->xdpy, stage_glx->gl_context);
|
||||
|
||||
CLUTTER_NOTE (GL, "Creating GL Context");
|
||||
stage_glx->gl_context = glXCreateContext (stage_glx->xdpy,
|
||||
stage_glx->xvisinfo,
|
||||
stage_glx->gl_context = glXCreateContext (stage_x11->xdpy,
|
||||
stage_x11->xvisinfo,
|
||||
0,
|
||||
True);
|
||||
|
||||
@ -302,7 +201,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (GL, "glXMakeCurrent");
|
||||
glXMakeCurrent (stage_glx->xdpy, stage_glx->xwin, stage_glx->gl_context);
|
||||
glXMakeCurrent (stage_x11->xdpy, stage_x11->xwin, stage_glx->gl_context);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -317,78 +216,50 @@ clutter_stage_glx_realize (ClutterActor *actor)
|
||||
0
|
||||
};
|
||||
|
||||
if (stage_glx->xvisinfo)
|
||||
XFree (stage_glx->xvisinfo);
|
||||
if (stage_x11->xvisinfo)
|
||||
XFree (stage_x11->xvisinfo);
|
||||
|
||||
CLUTTER_NOTE (GL, "glXChooseVisual");
|
||||
stage_glx->xvisinfo = glXChooseVisual (stage_glx->xdpy,
|
||||
stage_glx->xscreen,
|
||||
stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy,
|
||||
stage_x11->xscreen,
|
||||
gl_attributes);
|
||||
if (!stage_glx->xvisinfo)
|
||||
if (!stage_x11->xvisinfo)
|
||||
{
|
||||
g_critical ("Unable to find suitable GL visual.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (stage_glx->gl_context)
|
||||
glXDestroyContext (stage_glx->xdpy, stage_glx->gl_context);
|
||||
glXDestroyContext (stage_x11->xdpy, stage_glx->gl_context);
|
||||
|
||||
stage_glx->xpixmap = XCreatePixmap (stage_glx->xdpy,
|
||||
stage_glx->xwin_root,
|
||||
stage_glx->xwin_width,
|
||||
stage_glx->xwin_height,
|
||||
DefaultDepth (stage_glx->xdpy,
|
||||
stage_glx->xscreen));
|
||||
stage_x11->xpixmap = XCreatePixmap (stage_x11->xdpy,
|
||||
stage_x11->xwin_root,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height,
|
||||
DefaultDepth (stage_x11->xdpy,
|
||||
stage_x11->xscreen));
|
||||
|
||||
stage_glx->glxpixmap = glXCreateGLXPixmap (stage_glx->xdpy,
|
||||
stage_glx->xvisinfo,
|
||||
stage_glx->xpixmap);
|
||||
stage_glx->glxpixmap = glXCreateGLXPixmap (stage_x11->xdpy,
|
||||
stage_x11->xvisinfo,
|
||||
stage_x11->xpixmap);
|
||||
|
||||
/* indirect */
|
||||
stage_glx->gl_context = glXCreateContext (stage_glx->xdpy,
|
||||
stage_glx->xvisinfo,
|
||||
stage_glx->gl_context = glXCreateContext (stage_x11->xdpy,
|
||||
stage_x11->xvisinfo,
|
||||
0,
|
||||
False);
|
||||
|
||||
clutter_glx_trap_x_errors ();
|
||||
clutter_x11_trap_x_errors ();
|
||||
|
||||
glXMakeCurrent (stage_glx->xdpy,
|
||||
glXMakeCurrent (stage_x11->xdpy,
|
||||
stage_glx->glxpixmap,
|
||||
stage_glx->gl_context);
|
||||
|
||||
if (clutter_glx_untrap_x_errors ())
|
||||
if (clutter_x11_untrap_x_errors ())
|
||||
{
|
||||
g_critical ("Unable to set up offscreen context.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Debug code for monitoring a off screen pixmap via window */
|
||||
{
|
||||
Colormap cmap;
|
||||
XSetWindowAttributes swa;
|
||||
|
||||
cmap = XCreateColormap(clutter_glx_display(),
|
||||
clutter_glx_root_window(),
|
||||
backend->xvisinfo->visual, AllocNone);
|
||||
|
||||
/* create a window */
|
||||
swa.colormap = cmap;
|
||||
|
||||
foo_win = XCreateWindow(clutter_glx_display(),
|
||||
clutter_glx_root_window(),
|
||||
0, 0,
|
||||
backend->xwin_width, backend->xwin_height,
|
||||
0,
|
||||
backend->xvisinfo->depth,
|
||||
InputOutput,
|
||||
backend->xvisinfo->visual,
|
||||
CWColormap, &swa);
|
||||
|
||||
XMapWindow(clutter_glx_display(), foo_win);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Make sure the viewport gets set up correctly */
|
||||
@ -402,235 +273,6 @@ clutter_stage_glx_realize (ClutterActor *actor)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_query_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (self);
|
||||
|
||||
box->x1 = box->y1 = 0;
|
||||
box->x2 = box->x1 + CLUTTER_UNITS_FROM_INT (stage_glx->xwin_width);
|
||||
box->y2 = box->y1 + CLUTTER_UNITS_FROM_INT (stage_glx->xwin_height);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_request_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (self);
|
||||
gint new_width, new_height;
|
||||
|
||||
new_width = ABS (CLUTTER_UNITS_TO_INT (box->x2 - box->x1));
|
||||
new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1));
|
||||
|
||||
if (new_width != stage_glx->xwin_width ||
|
||||
new_height != stage_glx->xwin_height)
|
||||
{
|
||||
stage_glx->xwin_width = new_width;
|
||||
stage_glx->xwin_height = new_height;
|
||||
|
||||
if (stage_glx->xwin != None)
|
||||
{
|
||||
XResizeWindow (stage_glx->xdpy,
|
||||
stage_glx->xwin,
|
||||
stage_glx->xwin_width,
|
||||
stage_glx->xwin_height);
|
||||
|
||||
fix_window_size (stage_glx);
|
||||
}
|
||||
|
||||
if (stage_glx->xpixmap != None)
|
||||
{
|
||||
/* Need to recreate to resize */
|
||||
clutter_actor_unrealize (self);
|
||||
clutter_actor_realize (self);
|
||||
}
|
||||
|
||||
CLUTTER_SET_PRIVATE_FLAGS(self, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
if (stage_glx->xwin != None) /* Do we want to bother ? */
|
||||
XMoveWindow (stage_glx->xdpy,
|
||||
stage_glx->xwin,
|
||||
CLUTTER_UNITS_TO_INT (box->x1),
|
||||
CLUTTER_UNITS_TO_INT (box->y1));
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_set_fullscreen (ClutterStage *stage,
|
||||
gboolean fullscreen)
|
||||
{
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage);
|
||||
ClutterBackendGLX *backend_glx = stage_glx->backend;
|
||||
|
||||
static gboolean was_resizeable = FALSE;
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
if (stage_glx->xwin != None)
|
||||
{
|
||||
if (!CLUTTER_ACTOR_IS_MAPPED(CLUTTER_ACTOR (stage_glx)))
|
||||
{
|
||||
gint width, height;
|
||||
|
||||
width = DisplayWidth (stage_glx->xdpy, stage_glx->xscreen);
|
||||
height = DisplayHeight (stage_glx->xdpy, stage_glx->xscreen);
|
||||
|
||||
clutter_actor_set_size (CLUTTER_ACTOR (stage_glx),
|
||||
width, height);
|
||||
/* FIXME: This wont work if we support more states */
|
||||
XChangeProperty
|
||||
(stage_glx->xdpy,
|
||||
stage_glx->xwin,
|
||||
backend_glx->atom_WM_STATE, XA_ATOM, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char *)&backend_glx->atom_WM_STATE_FULLSCREEN,
|
||||
1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We need to set window user resize-able for metacity at
|
||||
* at least to allow the window to fullscreen *sigh*
|
||||
*/
|
||||
if (clutter_stage_get_user_resizable (stage) == TRUE)
|
||||
was_resizeable = TRUE;
|
||||
else
|
||||
clutter_stage_set_user_resizable (stage, TRUE);
|
||||
|
||||
send_wmspec_change_state(backend_glx,
|
||||
stage_glx->xwin,
|
||||
backend_glx->atom_WM_STATE_FULLSCREEN,
|
||||
TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stage_glx->xwin != None)
|
||||
{
|
||||
if (!CLUTTER_ACTOR_IS_MAPPED(CLUTTER_ACTOR (stage_glx)))
|
||||
{
|
||||
/* FIXME: This wont work if we support more states */
|
||||
XDeleteProperty (stage_glx->xdpy,
|
||||
stage_glx->xwin,
|
||||
backend_glx->atom_WM_STATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_stage_set_user_resizable (stage, TRUE);
|
||||
|
||||
send_wmspec_change_state(backend_glx,
|
||||
stage_glx->xwin,
|
||||
backend_glx->atom_WM_STATE_FULLSCREEN,
|
||||
FALSE);
|
||||
|
||||
/* reset the windows state - this isn't fun - see above */
|
||||
if (!was_resizeable)
|
||||
clutter_stage_set_user_resizable (stage, FALSE);
|
||||
|
||||
was_resizeable = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLUTTER_SET_PRIVATE_FLAGS(stage, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_set_cursor_visible (ClutterStage *stage,
|
||||
gboolean show_cursor)
|
||||
{
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage);
|
||||
|
||||
if (stage_glx->xwin == None)
|
||||
return;
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "setting cursor state ('%s') over stage window (%u)",
|
||||
show_cursor ? "visible" : "invisible",
|
||||
(unsigned int) stage_glx->xwin);
|
||||
|
||||
if (show_cursor)
|
||||
{
|
||||
#if 0 /* HAVE_XFIXES - borked on fiesty at least so disabled until further
|
||||
* investigation.
|
||||
*/
|
||||
XFixesShowCursor (stage_glx->xdpy, stage_glx->xwin);
|
||||
#else
|
||||
XUndefineCursor (stage_glx->xdpy, stage_glx->xwin);
|
||||
#endif /* HAVE_XFIXES */
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0 /* HAVE_XFIXES - borked */
|
||||
XFixesHideCursor (stage_glx->xdpy, stage_glx->xwin);
|
||||
#else
|
||||
XColor col;
|
||||
Pixmap pix;
|
||||
Cursor curs;
|
||||
|
||||
pix = XCreatePixmap (stage_glx->xdpy, stage_glx->xwin, 1, 1, 1);
|
||||
memset (&col, 0, sizeof (col));
|
||||
curs = XCreatePixmapCursor (stage_glx->xdpy,
|
||||
pix, pix,
|
||||
&col, &col,
|
||||
1, 1);
|
||||
XFreePixmap (stage_glx->xdpy, pix);
|
||||
XDefineCursor (stage_glx->xdpy, stage_glx->xwin, curs);
|
||||
#endif /* HAVE_XFIXES */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_set_title (ClutterStage *stage,
|
||||
const gchar *title)
|
||||
{
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage);
|
||||
Atom atom_NET_WM_NAME, atom_UTF8_STRING;
|
||||
|
||||
if (stage_glx->xwin == None)
|
||||
return;
|
||||
|
||||
/* FIXME: pre create these to avoid too many round trips */
|
||||
atom_NET_WM_NAME = XInternAtom (stage_glx->xdpy, "_NET_WM_NAME", False);
|
||||
atom_UTF8_STRING = XInternAtom (stage_glx->xdpy, "UTF8_STRING", False);
|
||||
|
||||
if (title == NULL)
|
||||
{
|
||||
XDeleteProperty (stage_glx->xdpy,
|
||||
stage_glx->xwin,
|
||||
atom_NET_WM_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
XChangeProperty (stage_glx->xdpy,
|
||||
stage_glx->xwin,
|
||||
atom_NET_WM_NAME,
|
||||
atom_UTF8_STRING,
|
||||
8,
|
||||
PropModeReplace,
|
||||
(unsigned char*)title,
|
||||
(int)strlen(title));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_set_user_resize (ClutterStage *stage,
|
||||
gboolean value)
|
||||
{
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage);
|
||||
|
||||
fix_window_size (stage_glx);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_set_offscreen (ClutterStage *stage,
|
||||
gboolean offscreen)
|
||||
{
|
||||
/* Do nothing ? */
|
||||
}
|
||||
|
||||
static void
|
||||
snapshot_pixbuf_free (guchar *pixels,
|
||||
gpointer data)
|
||||
@ -649,9 +291,11 @@ clutter_stage_glx_draw_to_pixbuf (ClutterStage *stage,
|
||||
GdkPixbuf *pixb;
|
||||
ClutterActor *actor;
|
||||
ClutterStageGLX *stage_glx;
|
||||
ClutterStageX11 *stage_x11;
|
||||
gboolean is_offscreen = FALSE;
|
||||
|
||||
stage_glx = CLUTTER_STAGE_GLX (stage);
|
||||
stage_x11 = CLUTTER_STAGE_X11 (stage);
|
||||
actor = CLUTTER_ACTOR (stage);
|
||||
|
||||
if (width < 0)
|
||||
@ -664,13 +308,13 @@ clutter_stage_glx_draw_to_pixbuf (ClutterStage *stage,
|
||||
|
||||
if (G_UNLIKELY (is_offscreen))
|
||||
{
|
||||
gdk_pixbuf_xlib_init (stage_glx->xdpy, stage_glx->xscreen);
|
||||
gdk_pixbuf_xlib_init (stage_x11->xdpy, stage_x11->xscreen);
|
||||
|
||||
pixb = gdk_pixbuf_xlib_get_from_drawable (NULL,
|
||||
(Drawable) stage_glx->xpixmap,
|
||||
DefaultColormap (stage_glx->xdpy,
|
||||
stage_glx->xscreen),
|
||||
stage_glx->xvisinfo->visual,
|
||||
(Drawable) stage_x11->xpixmap,
|
||||
DefaultColormap (stage_x11->xdpy,
|
||||
stage_x11->xscreen),
|
||||
stage_x11->xvisinfo->visual,
|
||||
x, y,
|
||||
0, 0,
|
||||
width, height);
|
||||
@ -712,8 +356,9 @@ static void
|
||||
clutter_stage_glx_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (gobject);
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject);
|
||||
|
||||
if (stage_glx->xwin)
|
||||
if (stage_x11->xwin)
|
||||
clutter_actor_unrealize (CLUTTER_ACTOR (stage_glx));
|
||||
|
||||
G_OBJECT_CLASS (clutter_stage_glx_parent_class)->dispose (gobject);
|
||||
@ -728,133 +373,13 @@ clutter_stage_glx_class_init (ClutterStageGLXClass *klass)
|
||||
|
||||
gobject_class->dispose = clutter_stage_glx_dispose;
|
||||
|
||||
actor_class->show = clutter_stage_glx_show;
|
||||
actor_class->hide = clutter_stage_glx_hide;
|
||||
actor_class->realize = clutter_stage_glx_realize;
|
||||
actor_class->unrealize = clutter_stage_glx_unrealize;
|
||||
actor_class->request_coords = clutter_stage_glx_request_coords;
|
||||
actor_class->query_coords = clutter_stage_glx_query_coords;
|
||||
|
||||
stage_class->set_fullscreen = clutter_stage_glx_set_fullscreen;
|
||||
stage_class->set_cursor_visible = clutter_stage_glx_set_cursor_visible;
|
||||
stage_class->set_offscreen = clutter_stage_glx_set_offscreen;
|
||||
stage_class->draw_to_pixbuf = clutter_stage_glx_draw_to_pixbuf;
|
||||
stage_class->set_title = clutter_stage_glx_set_title;
|
||||
stage_class->set_user_resize = clutter_stage_glx_set_user_resize;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_init (ClutterStageGLX *stage)
|
||||
{
|
||||
stage->xdpy = NULL;
|
||||
stage->xwin_root = None;
|
||||
stage->xscreen = 0;
|
||||
|
||||
stage->xwin = None;
|
||||
stage->xwin_width = 640;
|
||||
stage->xwin_height = 480;
|
||||
stage->xvisinfo = None;
|
||||
|
||||
stage->is_foreign_xwin = FALSE;
|
||||
|
||||
CLUTTER_SET_PRIVATE_FLAGS(stage, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_get_stage_window:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* Gets the stages X Window.
|
||||
*
|
||||
* Return value: An XID for the stage window.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
Window
|
||||
clutter_glx_get_stage_window (ClutterStage *stage)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_GLX (stage), None);
|
||||
|
||||
return CLUTTER_STAGE_GLX (stage)->xwin;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_get_stage_visual:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* Returns the stage XVisualInfo
|
||||
*
|
||||
* Return value: The XVisualInfo for the stage.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
XVisualInfo *
|
||||
clutter_glx_get_stage_visual (ClutterStage *stage)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_GLX (stage), NULL);
|
||||
|
||||
return CLUTTER_STAGE_GLX (stage)->xvisinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_set_stage_foreign:
|
||||
* @stage: a #ClutterStage
|
||||
* @xwindow: an existing X Window id
|
||||
*
|
||||
* Target the #ClutterStage to use an existing external X Window
|
||||
*
|
||||
* Return value: %TRUE if foreign window is valid
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
gboolean
|
||||
clutter_glx_set_stage_foreign (ClutterStage *stage,
|
||||
Window xwindow)
|
||||
{
|
||||
ClutterStageGLX *stage_glx;
|
||||
ClutterActor *actor;
|
||||
gint x, y;
|
||||
guint width, height, border, depth;
|
||||
Window root_return;
|
||||
Status status;
|
||||
ClutterGeometry geom;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_GLX (stage), FALSE);
|
||||
g_return_val_if_fail (xwindow != None, FALSE);
|
||||
|
||||
stage_glx = CLUTTER_STAGE_GLX (stage);
|
||||
actor = CLUTTER_ACTOR (stage);
|
||||
|
||||
clutter_glx_trap_x_errors ();
|
||||
|
||||
status = XGetGeometry (stage_glx->xdpy,
|
||||
xwindow,
|
||||
&root_return,
|
||||
&x, &y,
|
||||
&width, &height,
|
||||
&border,
|
||||
&depth);
|
||||
|
||||
if (clutter_glx_untrap_x_errors () ||
|
||||
!status ||
|
||||
width == 0 || height == 0 ||
|
||||
depth != stage_glx->xvisinfo->depth)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
clutter_actor_unrealize (actor);
|
||||
|
||||
stage_glx->xwin = xwindow;
|
||||
stage_glx->is_foreign_xwin = TRUE;
|
||||
|
||||
geom.x = x;
|
||||
geom.y = y;
|
||||
geom.width = stage_glx->xwin_width = width;
|
||||
geom.height = stage_glx->xwin_height = height;
|
||||
|
||||
clutter_actor_set_geometry (actor, &geom);
|
||||
clutter_actor_realize (actor);
|
||||
|
||||
return TRUE;
|
||||
;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include "clutter-backend-glx.h"
|
||||
#include "../x11/clutter-stage-x11.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -45,32 +46,15 @@ typedef struct _ClutterStageGLXClass ClutterStageGLXClass;
|
||||
|
||||
struct _ClutterStageGLX
|
||||
{
|
||||
ClutterStage parent_instance;
|
||||
|
||||
/* from the backend */
|
||||
Display *xdpy;
|
||||
Window xwin_root;
|
||||
int xscreen;
|
||||
|
||||
XVisualInfo *xvisinfo;
|
||||
Window xwin;
|
||||
gint xwin_width;
|
||||
gint xwin_height; /* FIXME target_width / height */
|
||||
Pixmap xpixmap;
|
||||
ClutterStageX11 parent_instance;
|
||||
|
||||
GLXPixmap glxpixmap;
|
||||
GLXContext gl_context;
|
||||
|
||||
guint is_foreign_xwin : 1;
|
||||
|
||||
ClutterBackendGLX *backend;
|
||||
|
||||
ClutterStageState state;
|
||||
};
|
||||
|
||||
struct _ClutterStageGLXClass
|
||||
{
|
||||
ClutterStageClass parent_class;
|
||||
ClutterStageX11Class parent_class;
|
||||
};
|
||||
|
||||
GType clutter_stage_glx_get_type (void) G_GNUC_CONST;
|
||||
|
23
clutter/x11/Makefile.am
Normal file
23
clutter/x11/Makefile.am
Normal file
@ -0,0 +1,23 @@
|
||||
libclutterincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter
|
||||
libclutterinclude_HEADERS = clutter-x11.h
|
||||
|
||||
INCLUDES = \
|
||||
-DG_LOG_DOMAIN=\"ClutterX11\" \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/clutter/cogl \
|
||||
-I$(top_srcdir)/clutter/cogl/@CLUTTER_COGL@ \
|
||||
$(CLUTTER_CFLAGS) \
|
||||
$(CLUTTER_DEBUG_CFLAGS) \
|
||||
$(GCC_FLAGS)
|
||||
|
||||
LDADD = $(CLUTTER_LIBS)
|
||||
|
||||
noinst_LTLIBRARIES = libclutter-x11.la
|
||||
|
||||
libclutter_x11_la_SOURCES = \
|
||||
clutter-backend-x11.h \
|
||||
clutter-backend-x11.c \
|
||||
clutter-event-x11.c \
|
||||
clutter-stage-x11.h \
|
||||
clutter-stage-x11.c \
|
||||
clutter-x11.h
|
32
clutter/x11/clutter-backend-x11-private.h
Normal file
32
clutter/x11/clutter-backend-x11-private.h
Normal 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#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
|
463
clutter/x11/clutter-backend-x11.c
Normal file
463
clutter/x11/clutter-backend-x11.c
Normal file
@ -0,0 +1,463 @@
|
||||
/* 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
#include "clutter-x11.h"
|
||||
|
||||
#include "../clutter-event.h"
|
||||
#include "../clutter-main.h"
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-private.h"
|
||||
|
||||
#include "cogl.h"
|
||||
|
||||
G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND);
|
||||
|
||||
/* singleton object */
|
||||
static ClutterBackendX11 *backend_singleton = NULL;
|
||||
|
||||
/* options */
|
||||
static gchar *clutter_display_name = NULL;
|
||||
static gint clutter_screen = 0;
|
||||
static gboolean clutter_synchronise = FALSE;
|
||||
|
||||
/* X error trap */
|
||||
static int TrappedErrorCode = 0;
|
||||
static int (* old_error_handler) (Display *, XErrorEvent *);
|
||||
|
||||
gboolean
|
||||
clutter_backend_x11_pre_parse (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *env_string;
|
||||
|
||||
/* we don't fail here if DISPLAY is not set, as the user
|
||||
* might pass the --display command line switch
|
||||
*/
|
||||
env_string = g_getenv ("DISPLAY");
|
||||
if (env_string)
|
||||
{
|
||||
clutter_display_name = g_strdup (env_string);
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_backend_x11_post_parse (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
if (clutter_display_name)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "XOpenDisplay on `%s'", clutter_display_name);
|
||||
backend_x11->xdpy = XOpenDisplay (clutter_display_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_BACKEND,
|
||||
"Unable to open display. You have to set the DISPLAY "
|
||||
"environment variable, or use the --display command "
|
||||
"line argument");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (backend_x11->xdpy)
|
||||
{
|
||||
double dpi;
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Getting the X screen");
|
||||
|
||||
if (clutter_screen == 0)
|
||||
backend_x11->xscreen = DefaultScreenOfDisplay (backend_x11->xdpy);
|
||||
else
|
||||
backend_x11->xscreen = ScreenOfDisplay (backend_x11->xdpy,
|
||||
clutter_screen);
|
||||
|
||||
backend_x11->xscreen_num = XScreenNumberOfScreen (backend_x11->xscreen);
|
||||
|
||||
backend_x11->xwin_root = RootWindow (backend_x11->xdpy,
|
||||
backend_x11->xscreen_num);
|
||||
|
||||
backend_x11->display_name = g_strdup (clutter_display_name);
|
||||
|
||||
dpi = (((double) DisplayHeight (backend_x11->xdpy, backend_x11->xscreen_num) * 25.4)
|
||||
/ (double) DisplayHeightMM (backend_x11->xdpy, backend_x11->xscreen_num));
|
||||
|
||||
clutter_backend_set_resolution (backend, dpi);
|
||||
|
||||
if (clutter_synchronise)
|
||||
XSynchronize (backend_x11->xdpy, True);
|
||||
|
||||
backend_x11->atom_WM_STATE
|
||||
= XInternAtom (backend_x11->xdpy, "_NET_WM_STATE", False);
|
||||
backend_x11->atom_WM_STATE_FULLSCREEN
|
||||
= XInternAtom (backend_x11->xdpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
}
|
||||
|
||||
g_free (clutter_display_name);
|
||||
|
||||
CLUTTER_NOTE (BACKEND,
|
||||
"X Display `%s'[%p] opened (screen:%d, root:%u, dpi:%f)",
|
||||
backend_x11->display_name,
|
||||
backend_x11->xdpy,
|
||||
backend_x11->xscreen_num,
|
||||
(unsigned int) backend_x11->xwin_root,
|
||||
clutter_backend_get_resolution (backend));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
clutter_backend_x11_init_events (ClutterBackend *backend)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "initialising the event loop");
|
||||
|
||||
_clutter_backend_x11_events_init (backend);
|
||||
}
|
||||
|
||||
ClutterActor *
|
||||
clutter_backend_x11_get_stage (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
return backend_x11->stage;
|
||||
}
|
||||
|
||||
static const GOptionEntry entries[] =
|
||||
{
|
||||
{
|
||||
"display", 0,
|
||||
G_OPTION_FLAG_IN_MAIN,
|
||||
G_OPTION_ARG_STRING, &clutter_display_name,
|
||||
"X display to use", "DISPLAY"
|
||||
},
|
||||
{
|
||||
"screen", 0,
|
||||
G_OPTION_FLAG_IN_MAIN,
|
||||
G_OPTION_ARG_INT, &clutter_screen,
|
||||
"X screen to use", "SCREEN"
|
||||
},
|
||||
{ "synch", 0,
|
||||
0,
|
||||
G_OPTION_ARG_NONE, &clutter_synchronise,
|
||||
"Make X calls synchronous", NULL,
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void
|
||||
clutter_backend_x11_add_options (ClutterBackend *backend,
|
||||
GOptionGroup *group)
|
||||
{
|
||||
g_option_group_add_entries (group, entries);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_x11_finalize (GObject *gobject)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (gobject);
|
||||
|
||||
g_free (backend_x11->display_name);
|
||||
|
||||
XCloseDisplay (backend_x11->xdpy);
|
||||
|
||||
if (backend_singleton)
|
||||
backend_singleton = NULL;
|
||||
|
||||
G_OBJECT_CLASS (clutter_backend_x11_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_x11_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (gobject);
|
||||
|
||||
if (backend_x11->stage)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "Disposing the main stage");
|
||||
|
||||
clutter_actor_destroy (backend_x11->stage);
|
||||
backend_x11->stage = NULL;
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Removing the event source");
|
||||
_clutter_backend_x11_events_uninit (CLUTTER_BACKEND (backend_x11));
|
||||
|
||||
G_OBJECT_CLASS (clutter_backend_x11_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static GObject *
|
||||
clutter_backend_x11_constructor (GType gtype,
|
||||
guint n_params,
|
||||
GObjectConstructParam *params)
|
||||
{
|
||||
GObjectClass *parent_class;
|
||||
GObject *retval;
|
||||
|
||||
if (!backend_singleton)
|
||||
{
|
||||
parent_class = G_OBJECT_CLASS (clutter_backend_x11_parent_class);
|
||||
retval = parent_class->constructor (gtype, n_params, params);
|
||||
|
||||
backend_singleton = CLUTTER_BACKEND_X11 (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);
|
||||
}
|
||||
|
||||
ClutterFeatureFlags
|
||||
clutter_backend_x11_get_features (ClutterBackend *backend)
|
||||
{
|
||||
ClutterFeatureFlags flags = 0;
|
||||
|
||||
/* FIXME: we really need to check if gl context is set */
|
||||
|
||||
flags = CLUTTER_FEATURE_STAGE_USER_RESIZE|CLUTTER_FEATURE_STAGE_CURSOR;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_x11_class_init (ClutterBackendX11Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
|
||||
|
||||
gobject_class->constructor = clutter_backend_x11_constructor;
|
||||
gobject_class->dispose = clutter_backend_x11_dispose;
|
||||
gobject_class->finalize = clutter_backend_x11_finalize;
|
||||
|
||||
backend_class->pre_parse = clutter_backend_x11_pre_parse;
|
||||
backend_class->post_parse = clutter_backend_x11_post_parse;
|
||||
backend_class->init_events = clutter_backend_x11_init_events;
|
||||
backend_class->get_stage = clutter_backend_x11_get_stage;
|
||||
backend_class->add_options = clutter_backend_x11_add_options;
|
||||
backend_class->get_features = clutter_backend_x11_get_features;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_x11_init (ClutterBackendX11 *backend_x11)
|
||||
{
|
||||
ClutterBackend *backend = CLUTTER_BACKEND (backend_x11);
|
||||
|
||||
/* FIXME: get from xsettings */
|
||||
clutter_backend_set_double_click_time (backend, 250);
|
||||
clutter_backend_set_double_click_distance (backend, 5);
|
||||
clutter_backend_set_resolution (backend, 96.0);
|
||||
}
|
||||
|
||||
static int
|
||||
error_handler(Display *xdpy,
|
||||
XErrorEvent *error)
|
||||
{
|
||||
TrappedErrorCode = error->error_code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_trap_x_errors:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
void
|
||||
clutter_x11_trap_x_errors (void)
|
||||
{
|
||||
TrappedErrorCode = 0;
|
||||
old_error_handler = XSetErrorHandler (error_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_untrap_x_errors:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
gint
|
||||
clutter_x11_untrap_x_errors (void)
|
||||
{
|
||||
XSetErrorHandler (old_error_handler);
|
||||
|
||||
return TrappedErrorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_get_default_display:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
Display *
|
||||
clutter_x11_get_default_display (void)
|
||||
{
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("X11 backend has not been initialised");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return backend_singleton->xdpy;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_get_default_screen:
|
||||
*
|
||||
* Gets the pointer to the default X Screen object.
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
int
|
||||
clutter_x11_get_default_screen (void)
|
||||
{
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("X11 backend has not been initialised");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return backend_singleton->xscreen_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_get_root_window:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
Window
|
||||
clutter_x11_get_root_window (void)
|
||||
{
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("X11 backend has not been initialised");
|
||||
return None;
|
||||
}
|
||||
|
||||
return backend_singleton->xwin_root;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_add_filter:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
void
|
||||
clutter_x11_add_filter (ClutterX11FilterFunc func, gpointer data)
|
||||
{
|
||||
ClutterX11EventFilter *filter;
|
||||
|
||||
g_return_if_fail (func != NULL);
|
||||
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("X11 backend has not been initialised");
|
||||
return;
|
||||
}
|
||||
|
||||
filter = g_new0(ClutterX11EventFilter, 1);
|
||||
filter->func = func;
|
||||
filter->data = data;
|
||||
|
||||
backend_singleton->event_filters
|
||||
= g_slist_append (backend_singleton->event_filters, filter);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_remove_filter:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
void
|
||||
clutter_x11_remove_filter (ClutterX11FilterFunc func, gpointer data)
|
||||
{
|
||||
GSList *tmp_list, *this;
|
||||
ClutterX11EventFilter *filter;
|
||||
|
||||
g_return_if_fail (func == NULL);
|
||||
|
||||
tmp_list = backend_singleton->event_filters;
|
||||
|
||||
while (tmp_list)
|
||||
{
|
||||
filter = (ClutterX11EventFilter *)tmp_list->data;
|
||||
this = tmp_list;
|
||||
tmp_list = tmp_list->next;
|
||||
|
||||
if (filter->func == func && filter->data == data)
|
||||
{
|
||||
backend_singleton->event_filters
|
||||
= g_slist_remove_link (backend_singleton->event_filters, this);
|
||||
|
||||
g_slist_free_1 (this);
|
||||
g_free (filter);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
110
clutter/x11/clutter-backend-x11.h
Normal file
110
clutter/x11/clutter-backend-x11.h
Normal file
@ -0,0 +1,110 @@
|
||||
/* 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CLUTTER_BACKEND_X11_H__
|
||||
#define __CLUTTER_BACKEND_X11_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter-event.h>
|
||||
#include <clutter/clutter-backend.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "clutter-x11.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_BACKEND_X11 (clutter_backend_x11_get_type ())
|
||||
#define CLUTTER_BACKEND_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_X11, ClutterBackendX11))
|
||||
#define CLUTTER_IS_BACKEND_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_X11))
|
||||
#define CLUTTER_BACKEND_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_X11, ClutterBackendX11Class))
|
||||
#define CLUTTER_IS_BACKEND_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_X11))
|
||||
#define CLUTTER_BACKEND_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_X11, ClutterBackendX11Class))
|
||||
|
||||
typedef struct _ClutterBackendX11 ClutterBackendX11;
|
||||
typedef struct _ClutterBackendX11Class ClutterBackendX11Class;
|
||||
|
||||
typedef struct _ClutterX11EventFilter
|
||||
{
|
||||
ClutterX11FilterFunc func;
|
||||
gpointer data;
|
||||
|
||||
} ClutterX11EventFilter;
|
||||
|
||||
struct _ClutterBackendX11
|
||||
{
|
||||
ClutterBackend parent_instance;
|
||||
|
||||
/* main stage singleton */
|
||||
ClutterActor *stage;
|
||||
|
||||
Display *xdpy;
|
||||
Window xwin_root;
|
||||
Screen *xscreen;
|
||||
int xscreen_num;
|
||||
gchar *display_name;
|
||||
|
||||
/* event source */
|
||||
GSource *event_source;
|
||||
GSList *event_filters;
|
||||
|
||||
/* props */
|
||||
Atom atom_WM_STATE;
|
||||
Atom atom_WM_STATE_FULLSCREEN;
|
||||
};
|
||||
|
||||
struct _ClutterBackendX11Class
|
||||
{
|
||||
ClutterBackendClass parent_class;
|
||||
};
|
||||
|
||||
void _clutter_backend_x11_events_init (ClutterBackend *backend);
|
||||
void _clutter_backend_x11_events_uninit (ClutterBackend *backend);
|
||||
|
||||
GType clutter_backend_x11_get_type (void) G_GNUC_CONST;
|
||||
|
||||
/* Private to glx/eglx backends */
|
||||
gboolean
|
||||
clutter_backend_x11_pre_parse (ClutterBackend *backend,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
clutter_backend_x11_post_parse (ClutterBackend *backend,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
clutter_backend_x11_init_stage (ClutterBackend *backend,
|
||||
GError **error);
|
||||
|
||||
ClutterActor *
|
||||
clutter_backend_x11_get_stage (ClutterBackend *backend);
|
||||
|
||||
void
|
||||
clutter_backend_x11_add_options (ClutterBackend *backend,
|
||||
GOptionGroup *group);
|
||||
|
||||
ClutterFeatureFlags
|
||||
clutter_backend_x11_get_features (ClutterBackend *backend);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_BACKEND_X11_H__ */
|
@ -19,13 +19,11 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-stage-glx.h"
|
||||
#include "clutter-backend-glx.h"
|
||||
#include "clutter-glx.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-x11.h"
|
||||
|
||||
#include "../clutter-backend.h"
|
||||
#include "../clutter-event.h"
|
||||
@ -107,7 +105,7 @@ clutter_event_source_new (ClutterBackend *backend)
|
||||
static gboolean
|
||||
check_xpending (ClutterBackend *backend)
|
||||
{
|
||||
return XPending (CLUTTER_BACKEND_GLX (backend)->xdpy);
|
||||
return XPending (CLUTTER_BACKEND_X11 (backend)->xdpy);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -132,12 +130,12 @@ xembed_send_message (Display *xdisplay,
|
||||
ev.xclient.data.l[3] = data1;
|
||||
ev.xclient.data.l[4] = data2;
|
||||
|
||||
clutter_glx_trap_x_errors ();
|
||||
clutter_x11_trap_x_errors ();
|
||||
|
||||
XSendEvent (xdisplay, window, False, NoEventMask, &ev);
|
||||
XSync (xdisplay, False);
|
||||
|
||||
if (clutter_glx_untrap_x_errors ())
|
||||
if (clutter_x11_untrap_x_errors ())
|
||||
return False;
|
||||
|
||||
return True;
|
||||
@ -156,29 +154,29 @@ xembed_set_info (Display *xdisplay,
|
||||
list[0] = MAX_SUPPORTED_XEMBED_VERSION;
|
||||
list[1] = XEMBED_MAPPED;
|
||||
|
||||
clutter_glx_trap_x_errors ();
|
||||
clutter_x11_trap_x_errors ();
|
||||
XChangeProperty (xdisplay, window,
|
||||
atom_XEMBED_INFO,
|
||||
atom_XEMBED_INFO, 32,
|
||||
PropModeReplace, (unsigned char *) list, 2);
|
||||
clutter_glx_untrap_x_errors ();
|
||||
clutter_x11_untrap_x_errors ();
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_backend_glx_events_init (ClutterBackend *backend)
|
||||
_clutter_backend_x11_events_init (ClutterBackend *backend)
|
||||
{
|
||||
GSource *source;
|
||||
ClutterEventSource *event_source;
|
||||
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
int connection_number;
|
||||
|
||||
connection_number = ConnectionNumber (backend_glx->xdpy);
|
||||
connection_number = ConnectionNumber (backend_x11->xdpy);
|
||||
CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number);
|
||||
|
||||
Atom_XEMBED = XInternAtom (backend_glx->xdpy, "_XEMBED", False);
|
||||
Atom_WM_PROTOCOLS = XInternAtom (backend_glx->xdpy, "WM_PROTOCOLS", False);
|
||||
Atom_XEMBED = XInternAtom (backend_x11->xdpy, "_XEMBED", False);
|
||||
Atom_WM_PROTOCOLS = XInternAtom (backend_x11->xdpy, "WM_PROTOCOLS", False);
|
||||
|
||||
source = backend_glx->event_source = clutter_event_source_new (backend);
|
||||
source = backend_x11->event_source = clutter_event_source_new (backend);
|
||||
event_source = (ClutterEventSource *) source;
|
||||
g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
|
||||
|
||||
@ -191,30 +189,30 @@ _clutter_backend_glx_events_init (ClutterBackend *backend)
|
||||
g_source_set_can_recurse (source, TRUE);
|
||||
g_source_attach (source, NULL);
|
||||
|
||||
xembed_set_info (backend_glx->xdpy,
|
||||
clutter_glx_get_stage_window (CLUTTER_STAGE (backend_glx->stage)),
|
||||
xembed_set_info (backend_x11->xdpy,
|
||||
clutter_x11_get_stage_window
|
||||
(CLUTTER_STAGE (backend_x11->stage)),
|
||||
0);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_backend_glx_events_uninit (ClutterBackend *backend)
|
||||
_clutter_backend_x11_events_uninit (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
if (backend_glx->event_source)
|
||||
if (backend_x11->event_source)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "Destroying the event source");
|
||||
|
||||
event_sources = g_list_remove (event_sources,
|
||||
backend_glx->event_source);
|
||||
backend_x11->event_source);
|
||||
|
||||
g_source_destroy (backend_glx->event_source);
|
||||
g_source_unref (backend_glx->event_source);
|
||||
backend_glx->event_source = NULL;
|
||||
g_source_destroy (backend_x11->event_source);
|
||||
g_source_unref (backend_x11->event_source);
|
||||
backend_x11->event_source = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_user_time (Display *display,
|
||||
Window *xwindow,
|
||||
@ -256,20 +254,20 @@ translate_key_event (ClutterBackend *backend,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_wm_protocols_event (ClutterBackendGLX *backend_glx,
|
||||
handle_wm_protocols_event (ClutterBackendX11 *backend_x11,
|
||||
XEvent *xevent)
|
||||
{
|
||||
Atom atom = (Atom) xevent->xclient.data.l[0];
|
||||
Atom Atom_WM_DELETE_WINDOW;
|
||||
Atom Atom_NEW_WM_PING;
|
||||
|
||||
ClutterStage *stage = CLUTTER_STAGE (backend_glx->stage);
|
||||
Window stage_xwindow = clutter_glx_get_stage_window (stage);
|
||||
ClutterStage *stage = CLUTTER_STAGE (backend_x11->stage);
|
||||
Window stage_xwindow = clutter_x11_get_stage_window (stage);
|
||||
|
||||
Atom_WM_DELETE_WINDOW = XInternAtom (backend_glx->xdpy,
|
||||
Atom_WM_DELETE_WINDOW = XInternAtom (backend_x11->xdpy,
|
||||
"WM_DELETE_WINDOW",
|
||||
False);
|
||||
Atom_NEW_WM_PING = XInternAtom (backend_glx->xdpy, "_NET_WM_PING", False);
|
||||
Atom_NEW_WM_PING = XInternAtom (backend_x11->xdpy, "_NET_WM_PING", False);
|
||||
|
||||
if (atom == Atom_WM_DELETE_WINDOW &&
|
||||
xevent->xany.window == stage_xwindow)
|
||||
@ -282,7 +280,7 @@ handle_wm_protocols_event (ClutterBackendGLX *backend_glx,
|
||||
CLUTTER_NOTE (EVENT, "delete window:\twindow: %ld",
|
||||
xevent->xclient.window);
|
||||
|
||||
set_user_time (backend_glx->xdpy,
|
||||
set_user_time (backend_x11->xdpy,
|
||||
&stage_xwindow,
|
||||
xevent->xclient.data.l[1]);
|
||||
|
||||
@ -293,8 +291,8 @@ handle_wm_protocols_event (ClutterBackendGLX *backend_glx,
|
||||
{
|
||||
XClientMessageEvent xclient = xevent->xclient;
|
||||
|
||||
xclient.window = backend_glx->xwin_root;
|
||||
XSendEvent (backend_glx->xdpy, xclient.window,
|
||||
xclient.window = backend_x11->xwin_root;
|
||||
XSendEvent (backend_x11->xdpy, xclient.window,
|
||||
False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
(XEvent *) &xclient);
|
||||
@ -307,12 +305,12 @@ handle_wm_protocols_event (ClutterBackendGLX *backend_glx,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_xembed_event (ClutterBackendGLX *backend_glx,
|
||||
handle_xembed_event (ClutterBackendX11 *backend_x11,
|
||||
XEvent *xevent)
|
||||
{
|
||||
ClutterActor *stage;
|
||||
|
||||
stage = _clutter_backend_get_stage (CLUTTER_BACKEND (backend_glx));
|
||||
stage = _clutter_backend_get_stage (CLUTTER_BACKEND (backend_x11));
|
||||
|
||||
switch (xevent->xclient.data.l[1])
|
||||
{
|
||||
@ -325,8 +323,8 @@ handle_xembed_event (ClutterBackendGLX *backend_glx,
|
||||
clutter_actor_realize (stage);
|
||||
clutter_actor_show (stage);
|
||||
|
||||
xembed_set_info (backend_glx->xdpy,
|
||||
clutter_glx_get_stage_window (CLUTTER_STAGE (stage)),
|
||||
xembed_set_info (backend_x11->xdpy,
|
||||
clutter_x11_get_stage_window (CLUTTER_STAGE (stage)),
|
||||
XEMBED_MAPPED);
|
||||
break;
|
||||
case XEMBED_WINDOW_ACTIVATE:
|
||||
@ -338,7 +336,7 @@ handle_xembed_event (ClutterBackendGLX *backend_glx,
|
||||
case XEMBED_FOCUS_IN:
|
||||
CLUTTER_NOTE (EVENT, "got XEMBED_FOCUS_IN");
|
||||
if (ParentEmbedderWin)
|
||||
xembed_send_message (backend_glx->xdpy, ParentEmbedderWin,
|
||||
xembed_send_message (backend_x11->xdpy, ParentEmbedderWin,
|
||||
XEMBED_FOCUS_NEXT,
|
||||
0, 0, 0);
|
||||
break;
|
||||
@ -356,39 +354,39 @@ event_translate (ClutterBackend *backend,
|
||||
ClutterEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
ClutterBackendGLX *backend_glx;
|
||||
ClutterStageGLX *stage_glx;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
ClutterStageX11 *stage_x11;
|
||||
ClutterStage *stage;
|
||||
gboolean res;
|
||||
Window xwindow, stage_xwindow;
|
||||
|
||||
backend_glx = CLUTTER_BACKEND_GLX (backend);
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
stage = CLUTTER_STAGE (_clutter_backend_get_stage (backend));
|
||||
stage_glx = CLUTTER_STAGE_GLX (stage);
|
||||
stage_xwindow = clutter_glx_get_stage_window (stage);
|
||||
stage_x11 = CLUTTER_STAGE_X11 (stage);
|
||||
stage_xwindow = clutter_x11_get_stage_window (stage);
|
||||
|
||||
xwindow = xevent->xany.window;
|
||||
if (xwindow == None)
|
||||
xwindow = stage_xwindow;
|
||||
|
||||
if (backend_glx->event_filters)
|
||||
if (backend_x11->event_filters)
|
||||
{
|
||||
GSList *node;
|
||||
ClutterGLXEventFilter *filter;
|
||||
ClutterX11EventFilter *filter;
|
||||
|
||||
node = backend_glx->event_filters;
|
||||
node = backend_x11->event_filters;
|
||||
|
||||
while (node)
|
||||
{
|
||||
filter = (ClutterGLXEventFilter *)node->data;
|
||||
filter = (ClutterX11EventFilter *)node->data;
|
||||
|
||||
switch (filter->func(xevent, event, filter->data))
|
||||
{
|
||||
case CLUTTER_GLX_FILTER_CONTINUE:
|
||||
case CLUTTER_X11_FILTER_CONTINUE:
|
||||
break;
|
||||
case CLUTTER_GLX_FILTER_TRANSLATE:
|
||||
case CLUTTER_X11_FILTER_TRANSLATE:
|
||||
return TRUE;
|
||||
case CLUTTER_GLX_FILTER_REMOVE:
|
||||
case CLUTTER_X11_FILTER_REMOVE:
|
||||
return FALSE;
|
||||
default:
|
||||
break;
|
||||
@ -414,7 +412,7 @@ event_translate (ClutterBackend *backend,
|
||||
break;
|
||||
case PropertyNotify:
|
||||
{
|
||||
if (xevent->xproperty.atom == backend_glx->atom_WM_STATE)
|
||||
if (xevent->xproperty.atom == backend_x11->atom_WM_STATE)
|
||||
{
|
||||
Atom type;
|
||||
gint format;
|
||||
@ -424,15 +422,15 @@ event_translate (ClutterBackend *backend,
|
||||
gulong i;
|
||||
gboolean fullscreen_set = FALSE;
|
||||
|
||||
clutter_glx_trap_x_errors ();
|
||||
XGetWindowProperty (backend_glx->xdpy,
|
||||
clutter_x11_trap_x_errors ();
|
||||
XGetWindowProperty (backend_x11->xdpy,
|
||||
stage_xwindow,
|
||||
backend_glx->atom_WM_STATE,
|
||||
backend_x11->atom_WM_STATE,
|
||||
0, G_MAXLONG,
|
||||
False, XA_ATOM,
|
||||
&type, &format, &nitems,
|
||||
&bytes_after, &data);
|
||||
clutter_glx_untrap_x_errors ();
|
||||
clutter_x11_untrap_x_errors ();
|
||||
|
||||
if (type != None && data != NULL)
|
||||
{
|
||||
@ -441,23 +439,23 @@ event_translate (ClutterBackend *backend,
|
||||
i = 0;
|
||||
while (i < nitems)
|
||||
{
|
||||
if (atoms[i] == backend_glx->atom_WM_STATE_FULLSCREEN)
|
||||
if (atoms[i] == backend_x11->atom_WM_STATE_FULLSCREEN)
|
||||
fullscreen_set = TRUE;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (fullscreen_set
|
||||
!= !!(stage_glx->state & CLUTTER_STAGE_STATE_FULLSCREEN))
|
||||
!= !!(stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN))
|
||||
{
|
||||
if (fullscreen_set)
|
||||
stage_glx->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
stage_x11->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
else
|
||||
stage_glx->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
stage_x11->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
|
||||
event->type = CLUTTER_STAGE_STATE;
|
||||
event->stage_state.changed_mask
|
||||
= CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
event->stage_state.new_state = stage_glx->state;
|
||||
event->stage_state.new_state = stage_x11->state;
|
||||
}
|
||||
else
|
||||
res = FALSE;
|
||||
@ -470,26 +468,26 @@ event_translate (ClutterBackend *backend,
|
||||
}
|
||||
break;
|
||||
case FocusIn:
|
||||
if (!(stage_glx->state & CLUTTER_STAGE_STATE_ACTIVATED))
|
||||
if (!(stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED))
|
||||
{
|
||||
/* TODO: check xevent->xfocus.detail ? */
|
||||
stage_glx->state |= CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
stage_x11->state |= CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
|
||||
event->type = CLUTTER_STAGE_STATE;
|
||||
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
event->stage_state.new_state = stage_glx->state;
|
||||
event->stage_state.new_state = stage_x11->state;
|
||||
}
|
||||
else
|
||||
res = FALSE;
|
||||
break;
|
||||
case FocusOut:
|
||||
if (stage_glx->state & CLUTTER_STAGE_STATE_ACTIVATED)
|
||||
if (stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED)
|
||||
{
|
||||
stage_glx->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
stage_x11->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
|
||||
event->type = CLUTTER_STAGE_STATE;
|
||||
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
event->stage_state.new_state = stage_glx->state;
|
||||
event->stage_state.new_state = stage_x11->state;
|
||||
}
|
||||
else
|
||||
res = FALSE;
|
||||
@ -499,7 +497,7 @@ event_translate (ClutterBackend *backend,
|
||||
XEvent foo_xev;
|
||||
|
||||
/* Cheap compress */
|
||||
while (XCheckTypedWindowEvent (backend_glx->xdpy,
|
||||
while (XCheckTypedWindowEvent (backend_x11->xdpy,
|
||||
xevent->xexpose.window,
|
||||
Expose,
|
||||
&foo_xev));
|
||||
@ -514,7 +512,7 @@ event_translate (ClutterBackend *backend,
|
||||
case KeyPress:
|
||||
event->type = CLUTTER_KEY_PRESS;
|
||||
translate_key_event (backend, event, xevent);
|
||||
set_user_time (backend_glx->xdpy, &xwindow, xevent->xkey.time);
|
||||
set_user_time (backend_x11->xdpy, &xwindow, xevent->xkey.time);
|
||||
break;
|
||||
case KeyRelease:
|
||||
event->type = CLUTTER_KEY_RELEASE;
|
||||
@ -555,7 +553,7 @@ event_translate (ClutterBackend *backend,
|
||||
break;
|
||||
}
|
||||
|
||||
set_user_time (backend_glx->xdpy, &xwindow, event->button.time);
|
||||
set_user_time (backend_x11->xdpy, &xwindow, event->button.time);
|
||||
break;
|
||||
case ButtonRelease:
|
||||
/* scroll events don't have a corresponding release */
|
||||
@ -593,10 +591,10 @@ event_translate (ClutterBackend *backend,
|
||||
event->type = event->any.type = CLUTTER_CLIENT_MESSAGE;
|
||||
|
||||
if (xevent->xclient.message_type == Atom_XEMBED)
|
||||
res = handle_xembed_event (backend_glx, xevent);
|
||||
res = handle_xembed_event (backend_x11, xevent);
|
||||
else if (xevent->xclient.message_type == Atom_WM_PROTOCOLS)
|
||||
{
|
||||
res = handle_wm_protocols_event (backend_glx, xevent);
|
||||
res = handle_wm_protocols_event (backend_x11, xevent);
|
||||
event->type = event->any.type = CLUTTER_DELETE;
|
||||
}
|
||||
break;
|
||||
@ -612,9 +610,9 @@ event_translate (ClutterBackend *backend,
|
||||
static void
|
||||
events_queue (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
ClutterEvent *event;
|
||||
Display *xdisplay = backend_glx->xdpy;
|
||||
Display *xdisplay = backend_x11->xdpy;
|
||||
XEvent xevent;
|
||||
ClutterMainContext *clutter_context;
|
||||
|
524
clutter/x11/clutter-stage-x11.c
Normal file
524
clutter/x11/clutter-stage-x11.c
Normal file
@ -0,0 +1,524 @@
|
||||
/* 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
#include "clutter-x11.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 "cogl.h"
|
||||
|
||||
#ifdef HAVE_XFIXES
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#endif
|
||||
|
||||
#include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
|
||||
|
||||
G_DEFINE_TYPE (ClutterStageX11, clutter_stage_x11, CLUTTER_TYPE_STAGE);
|
||||
|
||||
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
||||
#define _NET_WM_STATE_ADD 1 /* add/set property */
|
||||
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
|
||||
|
||||
static void
|
||||
send_wmspec_change_state (ClutterBackendX11 *backend_x11,
|
||||
Window window,
|
||||
Atom state,
|
||||
gboolean add)
|
||||
{
|
||||
XClientMessageEvent xclient;
|
||||
|
||||
memset (&xclient, 0, sizeof (xclient));
|
||||
|
||||
xclient.type = ClientMessage;
|
||||
xclient.window = window;
|
||||
xclient.message_type = backend_x11->atom_WM_STATE;
|
||||
xclient.format = 32;
|
||||
|
||||
xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
|
||||
xclient.data.l[1] = state;
|
||||
xclient.data.l[2] = 0;
|
||||
xclient.data.l[3] = 0;
|
||||
xclient.data.l[4] = 0;
|
||||
|
||||
XSendEvent (backend_x11->xdpy,
|
||||
DefaultRootWindow(backend_x11->xdpy),
|
||||
False,
|
||||
SubstructureRedirectMask|SubstructureNotifyMask,
|
||||
(XEvent *)&xclient);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11)
|
||||
{
|
||||
gboolean resize;
|
||||
|
||||
resize = clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_x11));
|
||||
|
||||
if (stage_x11->xwin != None && stage_x11->is_foreign_xwin == FALSE)
|
||||
{
|
||||
XSizeHints *size_hints;
|
||||
|
||||
size_hints = XAllocSizeHints();
|
||||
|
||||
if (!resize)
|
||||
{
|
||||
size_hints->max_width
|
||||
= size_hints->min_width = stage_x11->xwin_width;
|
||||
size_hints->max_height
|
||||
= size_hints->min_height = stage_x11->xwin_height;
|
||||
size_hints->flags = PMinSize|PMaxSize;
|
||||
}
|
||||
|
||||
XSetWMNormalHints (stage_x11->xdpy, stage_x11->xwin, size_hints);
|
||||
|
||||
XFree(size_hints);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_show (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
|
||||
|
||||
/* Chain up to set mapped flags */
|
||||
CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class)->show(actor);
|
||||
|
||||
if (stage_x11->xwin)
|
||||
{
|
||||
/* Fire off a redraw to avoid flicker on first map.
|
||||
* Appears not to work perfectly on intel drivers at least.
|
||||
*/
|
||||
clutter_redraw();
|
||||
XSync (stage_x11->xdpy, FALSE);
|
||||
XMapWindow (stage_x11->xdpy, stage_x11->xwin);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_hide (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
|
||||
|
||||
if (stage_x11->xwin)
|
||||
XUnmapWindow (stage_x11->xdpy, stage_x11->xwin);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_x11_set_wm_protocols (Display *xdisplay,
|
||||
Window xwindow)
|
||||
{
|
||||
Atom protocols[2];
|
||||
int n = 0;
|
||||
|
||||
protocols[n++] = XInternAtom (xdisplay, "WM_DELETE_WINDOW", False);
|
||||
protocols[n++] = XInternAtom (xdisplay, "_NET_WM_PING", False);
|
||||
|
||||
XSetWMProtocols (xdisplay, xwindow, protocols, n);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_query_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
|
||||
|
||||
box->x1 = box->y1 = 0;
|
||||
box->x2 = box->x1 + CLUTTER_UNITS_FROM_INT (stage_x11->xwin_width);
|
||||
box->y2 = box->y1 + CLUTTER_UNITS_FROM_INT (stage_x11->xwin_height);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_request_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
|
||||
gint new_width, new_height;
|
||||
|
||||
new_width = ABS (CLUTTER_UNITS_TO_INT (box->x2 - box->x1));
|
||||
new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1));
|
||||
|
||||
if (new_width != stage_x11->xwin_width ||
|
||||
new_height != stage_x11->xwin_height)
|
||||
{
|
||||
stage_x11->xwin_width = new_width;
|
||||
stage_x11->xwin_height = new_height;
|
||||
|
||||
if (stage_x11->xwin != None)
|
||||
{
|
||||
XResizeWindow (stage_x11->xdpy,
|
||||
stage_x11->xwin,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height);
|
||||
|
||||
clutter_stage_x11_fix_window_size (stage_x11);
|
||||
}
|
||||
|
||||
if (stage_x11->xpixmap != None)
|
||||
{
|
||||
/* Need to recreate to resize */
|
||||
clutter_actor_unrealize (self);
|
||||
clutter_actor_realize (self);
|
||||
}
|
||||
|
||||
CLUTTER_SET_PRIVATE_FLAGS(self, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
if (stage_x11->xwin != None) /* Do we want to bother ? */
|
||||
XMoveWindow (stage_x11->xdpy,
|
||||
stage_x11->xwin,
|
||||
CLUTTER_UNITS_TO_INT (box->x1),
|
||||
CLUTTER_UNITS_TO_INT (box->y1));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_set_fullscreen (ClutterStage *stage,
|
||||
gboolean fullscreen)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage);
|
||||
ClutterBackendX11 *backend_x11 = stage_x11->backend;
|
||||
|
||||
static gboolean was_resizeable = FALSE;
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
if (stage_x11->xwin != None)
|
||||
{
|
||||
if (!CLUTTER_ACTOR_IS_MAPPED(CLUTTER_ACTOR (stage_x11)))
|
||||
{
|
||||
gint width, height;
|
||||
|
||||
width = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
|
||||
height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
|
||||
|
||||
clutter_actor_set_size (CLUTTER_ACTOR (stage_x11),
|
||||
width, height);
|
||||
/* FIXME: This wont work if we support more states */
|
||||
XChangeProperty
|
||||
(stage_x11->xdpy,
|
||||
stage_x11->xwin,
|
||||
backend_x11->atom_WM_STATE, XA_ATOM, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char *)&backend_x11->atom_WM_STATE_FULLSCREEN,
|
||||
1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We need to set window user resize-able for metacity at
|
||||
* at least to allow the window to fullscreen *sigh*
|
||||
*/
|
||||
if (clutter_stage_get_user_resizable (stage) == TRUE)
|
||||
was_resizeable = TRUE;
|
||||
else
|
||||
clutter_stage_set_user_resizable (stage, TRUE);
|
||||
|
||||
send_wmspec_change_state(backend_x11,
|
||||
stage_x11->xwin,
|
||||
backend_x11->atom_WM_STATE_FULLSCREEN,
|
||||
TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stage_x11->xwin != None)
|
||||
{
|
||||
if (!CLUTTER_ACTOR_IS_MAPPED(CLUTTER_ACTOR (stage_x11)))
|
||||
{
|
||||
/* FIXME: This wont work if we support more states */
|
||||
XDeleteProperty (stage_x11->xdpy,
|
||||
stage_x11->xwin,
|
||||
backend_x11->atom_WM_STATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_stage_set_user_resizable (stage, TRUE);
|
||||
|
||||
send_wmspec_change_state(backend_x11,
|
||||
stage_x11->xwin,
|
||||
backend_x11->atom_WM_STATE_FULLSCREEN,
|
||||
FALSE);
|
||||
|
||||
/* reset the windows state - this isn't fun - see above */
|
||||
if (!was_resizeable)
|
||||
clutter_stage_set_user_resizable (stage, FALSE);
|
||||
|
||||
was_resizeable = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLUTTER_SET_PRIVATE_FLAGS(stage, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_set_cursor_visible (ClutterStage *stage,
|
||||
gboolean show_cursor)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage);
|
||||
|
||||
if (stage_x11->xwin == None)
|
||||
return;
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "setting cursor state ('%s') over stage window (%u)",
|
||||
show_cursor ? "visible" : "invisible",
|
||||
(unsigned int) stage_x11->xwin);
|
||||
|
||||
if (show_cursor)
|
||||
{
|
||||
#if 0 /* HAVE_XFIXES - borked on fiesty at least so disabled until further
|
||||
* investigation.
|
||||
*/
|
||||
XFixesShowCursor (stage_x11->xdpy, stage_x11->xwin);
|
||||
#else
|
||||
XUndefineCursor (stage_x11->xdpy, stage_x11->xwin);
|
||||
#endif /* HAVE_XFIXES */
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0 /* HAVE_XFIXES - borked */
|
||||
XFixesHideCursor (stage_x11->xdpy, stage_x11->xwin);
|
||||
#else
|
||||
XColor col;
|
||||
Pixmap pix;
|
||||
Cursor curs;
|
||||
|
||||
pix = XCreatePixmap (stage_x11->xdpy, stage_x11->xwin, 1, 1, 1);
|
||||
memset (&col, 0, sizeof (col));
|
||||
curs = XCreatePixmapCursor (stage_x11->xdpy,
|
||||
pix, pix,
|
||||
&col, &col,
|
||||
1, 1);
|
||||
XFreePixmap (stage_x11->xdpy, pix);
|
||||
XDefineCursor (stage_x11->xdpy, stage_x11->xwin, curs);
|
||||
#endif /* HAVE_XFIXES */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_set_title (ClutterStage *stage,
|
||||
const gchar *title)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage);
|
||||
Atom atom_NET_WM_NAME, atom_UTF8_STRING;
|
||||
|
||||
if (stage_x11->xwin == None)
|
||||
return;
|
||||
|
||||
/* FIXME: pre create these to avoid too many round trips */
|
||||
atom_NET_WM_NAME = XInternAtom (stage_x11->xdpy, "_NET_WM_NAME", False);
|
||||
atom_UTF8_STRING = XInternAtom (stage_x11->xdpy, "UTF8_STRING", False);
|
||||
|
||||
if (title == NULL)
|
||||
{
|
||||
XDeleteProperty (stage_x11->xdpy,
|
||||
stage_x11->xwin,
|
||||
atom_NET_WM_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
XChangeProperty (stage_x11->xdpy,
|
||||
stage_x11->xwin,
|
||||
atom_NET_WM_NAME,
|
||||
atom_UTF8_STRING,
|
||||
8,
|
||||
PropModeReplace,
|
||||
(unsigned char*)title,
|
||||
(int)strlen(title));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_set_user_resize (ClutterStage *stage,
|
||||
gboolean value)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage);
|
||||
|
||||
clutter_stage_x11_fix_window_size (stage_x11);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_set_offscreen (ClutterStage *stage,
|
||||
gboolean offscreen)
|
||||
{
|
||||
/* Do nothing ? */
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject);
|
||||
|
||||
if (stage_x11->xwin)
|
||||
clutter_actor_unrealize (CLUTTER_ACTOR (stage_x11));
|
||||
|
||||
G_OBJECT_CLASS (clutter_stage_x11_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_class_init (ClutterStageX11Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
ClutterStageClass *stage_class = CLUTTER_STAGE_CLASS (klass);
|
||||
|
||||
gobject_class->dispose = clutter_stage_x11_dispose;
|
||||
|
||||
actor_class->show = clutter_stage_x11_show;
|
||||
actor_class->hide = clutter_stage_x11_hide;
|
||||
actor_class->request_coords = clutter_stage_x11_request_coords;
|
||||
actor_class->query_coords = clutter_stage_x11_query_coords;
|
||||
|
||||
stage_class->set_fullscreen = clutter_stage_x11_set_fullscreen;
|
||||
stage_class->set_cursor_visible = clutter_stage_x11_set_cursor_visible;
|
||||
stage_class->set_offscreen = clutter_stage_x11_set_offscreen;
|
||||
stage_class->set_title = clutter_stage_x11_set_title;
|
||||
stage_class->set_user_resize = clutter_stage_x11_set_user_resize;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_x11_init (ClutterStageX11 *stage)
|
||||
{
|
||||
stage->xdpy = NULL;
|
||||
stage->xwin_root = None;
|
||||
stage->xscreen = 0;
|
||||
|
||||
stage->xwin = None;
|
||||
stage->xwin_width = 640;
|
||||
stage->xwin_height = 480;
|
||||
stage->xvisinfo = None;
|
||||
|
||||
stage->is_foreign_xwin = FALSE;
|
||||
|
||||
CLUTTER_SET_PRIVATE_FLAGS(stage, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_get_stage_window:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* Gets the stages X Window.
|
||||
*
|
||||
* Return value: An XID for the stage window.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
Window
|
||||
clutter_x11_get_stage_window (ClutterStage *stage)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_X11 (stage), None);
|
||||
|
||||
return CLUTTER_STAGE_X11 (stage)->xwin;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_get_stage_visual:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* Returns the stage XVisualInfo
|
||||
*
|
||||
* Return value: The XVisualInfo for the stage.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
XVisualInfo *
|
||||
clutter_x11_get_stage_visual (ClutterStage *stage)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_X11 (stage), NULL);
|
||||
|
||||
return CLUTTER_STAGE_X11 (stage)->xvisinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_set_stage_foreign:
|
||||
* @stage: a #ClutterStage
|
||||
* @xwindow: an existing X Window id
|
||||
*
|
||||
* Target the #ClutterStage to use an existing external X Window
|
||||
*
|
||||
* Return value: %TRUE if foreign window is valid
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
gboolean
|
||||
clutter_x11_set_stage_foreign (ClutterStage *stage,
|
||||
Window xwindow)
|
||||
{
|
||||
ClutterStageX11 *stage_x11;
|
||||
ClutterActor *actor;
|
||||
gint x, y;
|
||||
guint width, height, border, depth;
|
||||
Window root_return;
|
||||
Status status;
|
||||
ClutterGeometry geom;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_X11 (stage), FALSE);
|
||||
g_return_val_if_fail (xwindow != None, FALSE);
|
||||
|
||||
stage_x11 = CLUTTER_STAGE_X11 (stage);
|
||||
actor = CLUTTER_ACTOR (stage);
|
||||
|
||||
clutter_x11_trap_x_errors ();
|
||||
|
||||
status = XGetGeometry (stage_x11->xdpy,
|
||||
xwindow,
|
||||
&root_return,
|
||||
&x, &y,
|
||||
&width, &height,
|
||||
&border,
|
||||
&depth);
|
||||
|
||||
if (clutter_x11_untrap_x_errors () ||
|
||||
!status ||
|
||||
width == 0 || height == 0 ||
|
||||
depth != stage_x11->xvisinfo->depth)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
clutter_actor_unrealize (actor);
|
||||
|
||||
stage_x11->xwin = xwindow;
|
||||
stage_x11->is_foreign_xwin = TRUE;
|
||||
|
||||
geom.x = x;
|
||||
geom.y = y;
|
||||
geom.width = stage_x11->xwin_width = width;
|
||||
geom.height = stage_x11->xwin_height = height;
|
||||
|
||||
clutter_actor_set_geometry (actor, &geom);
|
||||
clutter_actor_realize (actor);
|
||||
|
||||
return TRUE;
|
||||
}
|
80
clutter/x11/clutter-stage-x11.h
Normal file
80
clutter/x11/clutter-stage-x11.h
Normal file
@ -0,0 +1,80 @@
|
||||
/* 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CLUTTER_STAGE_X11_H__
|
||||
#define __CLUTTER_STAGE_X11_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter-stage.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "clutter-backend-x11.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_STAGE_X11 (clutter_stage_x11_get_type ())
|
||||
#define CLUTTER_STAGE_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_X11, ClutterStageX11))
|
||||
#define CLUTTER_IS_STAGE_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_X11))
|
||||
#define CLUTTER_STAGE_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_X11, ClutterStageX11Class))
|
||||
#define CLUTTER_IS_STAGE_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_X11))
|
||||
#define CLUTTER_STAGE_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_X11, ClutterStageX11Class))
|
||||
|
||||
typedef struct _ClutterStageX11 ClutterStageX11;
|
||||
typedef struct _ClutterStageX11Class ClutterStageX11Class;
|
||||
|
||||
struct _ClutterStageX11
|
||||
{
|
||||
ClutterStage parent_instance;
|
||||
|
||||
int is_foreign_xwin :1;
|
||||
|
||||
Display *xdpy;
|
||||
Window xwin_root;
|
||||
int xscreen;
|
||||
XVisualInfo *xvisinfo;
|
||||
Window xwin;
|
||||
gint xwin_width;
|
||||
gint xwin_height; /* FIXME target_width / height */
|
||||
Pixmap xpixmap;
|
||||
|
||||
ClutterBackendX11 *backend;
|
||||
ClutterStageState state;
|
||||
};
|
||||
|
||||
struct _ClutterStageX11Class
|
||||
{
|
||||
ClutterStageClass parent_class;
|
||||
};
|
||||
|
||||
GType clutter_stage_x11_get_type (void) G_GNUC_CONST;
|
||||
|
||||
/* Private to subclasses */
|
||||
void
|
||||
clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11);
|
||||
|
||||
void
|
||||
clutter_stage_x11_set_wm_protocols (Display *xdisplay,
|
||||
Window xwindow);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_STAGE_H__ */
|
80
clutter/x11/clutter-x11.h
Normal file
80
clutter/x11/clutter-x11.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:clutter-x11
|
||||
* @short_description: X11 specific API
|
||||
*
|
||||
* The X11 backend for Clutter provides some specific API, allowing
|
||||
* integration with the Xlibs API for embedding and manipulating the
|
||||
* stage window, or for trapping X errors.
|
||||
*
|
||||
* The ClutterX11 API is available since Clutter 0.6
|
||||
*/
|
||||
|
||||
#ifndef __CLUTTER_X11_H__
|
||||
#define __CLUTTER_X11_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <clutter/clutter-stage.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
CLUTTER_X11_FILTER_CONTINUE, /* Event not handled, continue processesing */
|
||||
CLUTTER_X11_FILTER_TRANSLATE, /* Native event translated into a Clutter
|
||||
event and stored in the "event" structure
|
||||
that was passed in */
|
||||
CLUTTER_X11_FILTER_REMOVE /* Terminate processing, removing event */
|
||||
} ClutterX11FilterReturn;
|
||||
|
||||
typedef ClutterX11FilterReturn (*ClutterX11FilterFunc) (XEvent *xev,
|
||||
ClutterEvent *cev,
|
||||
gpointer *data);
|
||||
|
||||
void clutter_x11_trap_x_errors (void);
|
||||
gint clutter_x11_untrap_x_errors (void);
|
||||
|
||||
Display *clutter_x11_get_default_display (void);
|
||||
int clutter_x11_get_default_screen (void);
|
||||
Window clutter_x11_get_root_window (void);
|
||||
|
||||
Window clutter_x11_get_stage_window (ClutterStage *stage);
|
||||
XVisualInfo *clutter_x11_get_stage_visual (ClutterStage *stage);
|
||||
|
||||
gboolean clutter_x11_set_stage_foreign (ClutterStage *stage,
|
||||
Window xwindow);
|
||||
|
||||
void clutter_x11_add_filter (ClutterX11FilterFunc func, gpointer data);
|
||||
|
||||
void clutter_x11_remove_filter (ClutterX11FilterFunc func,
|
||||
gpointer data);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_X11_H__ */
|
62
configure.ac
62
configure.ac
@ -87,6 +87,8 @@ fi
|
||||
|
||||
AC_SUBST(CLUTTER_NO_FPU)
|
||||
|
||||
backendextra=
|
||||
backendextralib=
|
||||
clutterbackend=glx
|
||||
AC_ARG_WITH([flavour],
|
||||
AC_HELP_STRING([--with-flavour=@<:@glx/eglx/eglnative/sdl@:>@],
|
||||
@ -151,35 +153,6 @@ case $clutterbackend in
|
||||
fi
|
||||
;;
|
||||
|
||||
sdles)
|
||||
#
|
||||
# Temp Hack for building with dgles (runs atop SDL)
|
||||
#
|
||||
clutterbackend=sdl
|
||||
CLUTTER_FLAVOUR="sdl"
|
||||
AC_DEFINE([HAVE_CLUTTER_SDL], 1, [Have the SDL backend])
|
||||
|
||||
CLUTTER_COGL="gles"
|
||||
AC_DEFINE([HAVE_COGL_GLES], 1, [Have GL for rendering])
|
||||
|
||||
AC_PATH_PROG(SDL_CONFIG, sdl-config)
|
||||
if test "x$SDL_CONFIG" = "x"; then
|
||||
AC_MSG_ERROR([[No sdl-config binary found in path and SDL flavour requested.]])
|
||||
else
|
||||
SDL_CFLAGS=`$SDL_CONFIG --cflags`
|
||||
SDL_LIBS=`$SDL_CONFIG --libs`
|
||||
fi
|
||||
|
||||
# FIXME: Obviously we need some real detection here
|
||||
SDL_CFLAGS="-I/usr/local/include $SDL_CFLAGS"
|
||||
SDL_LIBS="-L/usr/local/lib -lGLES_CM $SDL_LIBS"
|
||||
|
||||
AC_MSG_WARN([])
|
||||
AC_MSG_WARN([The SDL/Open GL ES Backend is purely for experimental])
|
||||
AC_MSG_WARN([and devlopment purposes. Do not use in production code!!])
|
||||
AC_MSG_WARN([])
|
||||
;;
|
||||
|
||||
glx)
|
||||
|
||||
clutter_gl_header="GL/gl.h"
|
||||
@ -205,11 +178,13 @@ case $clutterbackend in
|
||||
|
||||
GLX_LIBS="$X11_LIBS -lGL"
|
||||
GLX_CFLAGS="$X11_CFLAGS"
|
||||
backendextra=x11
|
||||
backendextralib="x11/libclutter-x11.la"
|
||||
;;
|
||||
|
||||
eglx)
|
||||
|
||||
$clutter_gl_header="GLES/gl.h"
|
||||
clutter_gl_header="GLES/gl.h"
|
||||
CLUTTER_FLAVOUR="eglx"
|
||||
AC_DEFINE([HAVE_CLUTTER_EGL], 1, [Have the EGL backend])
|
||||
|
||||
@ -217,15 +192,11 @@ case $clutterbackend in
|
||||
CLUTTER_COGL="gles"
|
||||
AC_DEFINE([HAVE_COGL_GLES], 1, [Have GL/ES for rendering])
|
||||
|
||||
# try for libvincent first (though its not so good)
|
||||
PKG_CHECK_MODULES(EGL, libvincent, HAVE_OGLES=yes, HAVE_OGLES=no)
|
||||
if test "x$HAVE_OGLES" = "xno"; then
|
||||
AC_CHECK_HEADERS([GLES/egl.h $clutter_gl_header],,
|
||||
[AC_MSG_ERROR([Unable to locate required GLES headers])])
|
||||
|
||||
# No libvincent so start checking for upper/lower case libgles_em
|
||||
# check for upper/lower case libgles_em
|
||||
# The powervr sdk uses lower case.
|
||||
|
||||
AC_CHECK_LIB(GLES_CM, eglInitialize, HAVE_LIBGLES=yes, HAVE_LIBGLES=no)
|
||||
if test "x$HAVE_LIBGLES" = "xno"; then
|
||||
|
||||
@ -233,14 +204,21 @@ case $clutterbackend in
|
||||
if test "x$HAVE_LIBGLES" = "xno"; then
|
||||
AC_MSG_ERROR([GLES library not found and egl backend requested.]);
|
||||
fi
|
||||
EGL_LIBS="-lgles_cm"
|
||||
EGL_LIBS="gles_cm"
|
||||
|
||||
else
|
||||
EGL_LIBS="-lGLES_CM"
|
||||
fi
|
||||
EGL_LIBS="GLES_CM"
|
||||
fi
|
||||
|
||||
EGL_LIBS="$EGL_LIBS $X11_LIBS"
|
||||
# glColor4ub needed for more precise picking, seems presence is a
|
||||
# bit random in egl 1.1 (in SDK header, but not lib)
|
||||
AC_CHECK_LIB($EGL_LIBS, glColor4ub, COLOR4UB=1, COLOR4UB=0)
|
||||
AC_DEFINE([HAVE_GLES_COLOR4UB], $COLOR4UB, [Have GL/ES glColor4ub])
|
||||
|
||||
EGL_LIBS="-l$EGL_LIBS $X11_LIBS"
|
||||
EGL_CFLAGS="$EGL_CFLAGS $X11_CFLAGS"
|
||||
backendextra=x11
|
||||
backendextralib="x11/libclutter-x11.la"
|
||||
;;
|
||||
|
||||
eglnative)
|
||||
@ -264,6 +242,9 @@ case $clutterbackend in
|
||||
AC_MSG_ERROR([libGLES_CM not found and egl backend requested.]);
|
||||
fi
|
||||
|
||||
AC_CHECK_LIB(GLES_CM, glColor4ub, COLOR4UB=1, COLOR4UB=0)
|
||||
AC_DEFINE([HAVE_GLES_COLOR4UB], COLOR4UB, [Have GL/ES glColor4ub])
|
||||
|
||||
PKG_CHECK_MODULES(TSLIB, tslib-1.0, [have_tslib=yes], [have_tslib=no])
|
||||
if test x$have_tslib = xyes; then
|
||||
AC_DEFINE([HAVE_TSLIB], 1, [Have tslib for touchscreen handling])
|
||||
@ -295,6 +276,8 @@ esac
|
||||
CLUTTER_GL_HEADER=$clutter_gl_header
|
||||
|
||||
AC_SUBST([clutterbackend])
|
||||
AC_SUBST([backendextra])
|
||||
AC_SUBST([backendextralib])
|
||||
AC_SUBST(CLUTTER_FLAVOUR)
|
||||
AC_SUBST(CLUTTER_COGL)
|
||||
AC_SUBST(CLUTTER_GL_HEADER)
|
||||
@ -392,6 +375,7 @@ AC_CONFIG_FILES([
|
||||
Makefile
|
||||
clutter/Makefile
|
||||
clutter/clutter-version.h
|
||||
clutter/x11/Makefile
|
||||
clutter/glx/Makefile
|
||||
clutter/eglx/Makefile
|
||||
clutter/eglnative/Makefile
|
||||
|
Loading…
Reference in New Issue
Block a user