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:
Matthew Allum 2007-11-15 14:45:27 +00:00
parent a9efed235e
commit 3607a470aa
26 changed files with 1698 additions and 2097 deletions

View File

@ -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> 2007-11-15 Neil J. Patel <njp@o-hand.com>
* clutter/Makefile.am: * clutter/Makefile.am:

6
README
View File

@ -129,6 +129,12 @@ RELEASE NOTES
Relevant information for developers with existing Clutter applications Relevant information for developers with existing Clutter applications
wanting to port to newer releases (See NEWS for general new feature info). 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 Release Notes for Clutter 0.4.0
------------------------------- -------------------------------

View File

@ -1,8 +1,8 @@
NULL = 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) target = $(clutterbackend)
@ -181,7 +181,8 @@ libclutter_@CLUTTER_FLAVOUR@_@CLUTTER_API_VERSION@_la_LIBADD = \
pango/libpangoclutter.la \ pango/libpangoclutter.la \
@CLUTTER_FLAVOUR@/libclutter-@CLUTTER_FLAVOUR@.la \ @CLUTTER_FLAVOUR@/libclutter-@CLUTTER_FLAVOUR@.la \
cogl/@CLUTTER_COGL@/libclutter-cogl.la \ cogl/@CLUTTER_COGL@/libclutter-cogl.la \
json/libclutter-json.la json/libclutter-json.la \
$(backendextralib)
libclutter_@CLUTTER_FLAVOUR@_@CLUTTER_API_VERSION@_la_SOURCES = \ libclutter_@CLUTTER_FLAVOUR@_@CLUTTER_API_VERSION@_la_SOURCES = \
$(source_c) $(source_h) $(source_h_priv) $(source_c) $(source_h) $(source_h_priv)

View File

@ -239,9 +239,10 @@ cogl_enable (gulong flags)
void void
cogl_color (const ClutterColor *color) cogl_color (const ClutterColor *color)
{ {
#if HAVE_GLES_COLOR4UB
/* /*
* GLES 1.1 does actually have this function, it's in the header file but * 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 * http://www.khronos.org/egl/headers/1_1/gl.h
*/ */
@ -249,6 +250,13 @@ cogl_color (const ClutterColor *color)
color->green, color->green,
color->blue, color->blue,
color->alpha) ); 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 void

View File

@ -8,14 +8,14 @@ INCLUDES = \
$(CLUTTER_DEBUG_CFLAGS) \ $(CLUTTER_DEBUG_CFLAGS) \
$(GCC_FLAGS) $(GCC_FLAGS)
LDADD = $(CLUTTER_LIBS) LDADD = $(CLUTTER_LIBS) \
$(top_srcdir)/clutter/x11/libclutter-x11.la
noinst_LTLIBRARIES = libclutter-eglx.la noinst_LTLIBRARIES = libclutter-eglx.la
libclutter_eglx_la_SOURCES = \ libclutter_eglx_la_SOURCES = \
clutter-backend-egl.h \ clutter-backend-egl.h \
clutter-backend-egl.c \ clutter-backend-egl.c \
clutter-event-egl.c \
clutter-stage-egl.h \ clutter-stage-egl.h \
clutter-stage-egl.c \ clutter-stage-egl.c \
clutter-eglx.h clutter-eglx.h

View File

@ -10,79 +10,20 @@
static ClutterBackendEGL *backend_singleton = NULL; static ClutterBackendEGL *backend_singleton = NULL;
/* options */ G_DEFINE_TYPE (ClutterBackendEGL, clutter_backend_egl, CLUTTER_TYPE_BACKEND_X11);
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;
}
static gboolean static gboolean
clutter_backend_egl_post_parse (ClutterBackend *backend, clutter_backend_egl_post_parse (ClutterBackend *backend,
GError **error) GError **error)
{ {
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend); ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
if (clutter_display_name) if (clutter_backend_x11_post_parse (backend, error))
{
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)
{ {
EGLBoolean status; EGLBoolean status;
double dpi;
CLUTTER_NOTE (MISC, "Getting the X screen"); backend_egl->edpy = eglGetDisplay((NativeDisplayType)backend_x11->xdpy);
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);
status = eglInitialize(backend_egl->edpy, status = eglInitialize(backend_egl->edpy,
&backend_egl->egl_version_major, &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", CLUTTER_NOTE (BACKEND, "EGL Reports version %i.%i",
backend_egl->egl_version_major, backend_egl->egl_version_major,
backend_egl->egl_version_minor); backend_egl->egl_version_minor);
@ -113,80 +46,23 @@ clutter_backend_egl_post_parse (ClutterBackend *backend,
return TRUE; 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 static void
clutter_backend_egl_redraw (ClutterBackend *backend) clutter_backend_egl_redraw (ClutterBackend *backend)
{ {
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend); ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterStageEGL *stage_egl; 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)); clutter_actor_paint (CLUTTER_ACTOR(stage_egl));
/* Why this paint is done in backend as likely GL windowing system /* Why this paint is done in backend as likely GL windowing system
* specific calls, like swapping buffers. * specific calls, like swapping buffers.
*/ */
if (stage_egl->xwin) if (stage_x11->xwin)
{ {
/* clutter_feature_wait_for_vblank (); */ /* clutter_feature_wait_for_vblank (); */
eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface); 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 static void
clutter_backend_egl_finalize (GObject *gobject) 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) if (backend_singleton)
backend_singleton = NULL; backend_singleton = NULL;
@ -231,16 +86,6 @@ clutter_backend_egl_finalize (GObject *gobject)
static void static void
clutter_backend_egl_dispose (GObject *gobject) 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); 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; 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 static void
clutter_backend_egl_class_init (ClutterBackendEGLClass *klass) 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->dispose = clutter_backend_egl_dispose;
gobject_class->finalize = clutter_backend_egl_finalize; 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->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->redraw = clutter_backend_egl_redraw;
backend_class->get_features = clutter_backend_egl_get_features; backend_class->get_features = clutter_backend_egl_get_features;
backend_class->init_stage = clutter_backend_egl_init_stage;
} }
static void static void
clutter_backend_egl_init (ClutterBackendEGL *backend_egl) 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 GType
@ -312,108 +191,6 @@ _clutter_backend_impl_get_type (void)
return clutter_backend_egl_get_type (); 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 * clutter_egl_display
* *

View File

@ -23,6 +23,7 @@
#define __CLUTTER_BACKEND_EGL_H__ #define __CLUTTER_BACKEND_EGL_H__
#include <glib-object.h> #include <glib-object.h>
#include <clutter/clutter-event.h>
#include <clutter/clutter-backend.h> #include <clutter/clutter-backend.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
@ -30,6 +31,9 @@
#include <GLES/gl.h> #include <GLES/gl.h>
#include <GLES/egl.h> #include <GLES/egl.h>
#include "../x11/clutter-backend-x11.h"
#include "clutter-eglx.h"
G_BEGIN_DECLS G_BEGIN_DECLS
#define CLUTTER_TYPE_BACKEND_EGL (clutter_backend_egl_get_type ()) #define CLUTTER_TYPE_BACKEND_EGL (clutter_backend_egl_get_type ())
@ -44,37 +48,21 @@ typedef struct _ClutterBackendEGLClass ClutterBackendEGLClass;
struct _ClutterBackendEGL struct _ClutterBackendEGL
{ {
ClutterBackend parent_instance; ClutterBackendX11 parent_instance;
Display *xdpy;
gchar *display_name;
Window xwin_root;
int xscreen_num;
Screen *xscreen;
/* EGL Specific */ /* EGL Specific */
EGLDisplay edpy; EGLDisplay edpy;
gint egl_version_major, egl_version_minor; gint egl_version_major, egl_version_minor;
/* main stage singleton */
ClutterActor *stage;
/* event source */
GSource *event_source;
/*< private >*/
}; };
struct _ClutterBackendEGLClass struct _ClutterBackendEGLClass
{ {
ClutterBackendClass parent_class; ClutterBackendX11Class parent_class;
}; };
GType clutter_backend_egl_get_type (void) G_GNUC_CONST; 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 G_END_DECLS
#endif /* __CLUTTER_BACKEND_EGL_H__ */ #endif /* __CLUTTER_BACKEND_EGL_H__ */

View File

@ -39,19 +39,6 @@
G_BEGIN_DECLS 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 EGLDisplay
clutter_eglx_display (void); clutter_eglx_display (void);

View File

@ -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 *) &timestamp, 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;
}

View File

@ -15,39 +15,13 @@
#include "../clutter-debug.h" #include "../clutter-debug.h"
#include "../clutter-units.h" #include "../clutter-units.h"
#ifdef HAVE_XFIXES G_DEFINE_TYPE (ClutterStageEGL, clutter_stage_egl, CLUTTER_TYPE_STAGE_X11);
#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);
}
static void static void
clutter_stage_egl_unrealize (ClutterActor *actor) clutter_stage_egl_unrealize (ClutterActor *actor)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor); ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
gboolean was_offscreen; gboolean was_offscreen;
CLUTTER_MARK(); CLUTTER_MARK();
@ -60,13 +34,13 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
} }
else else
{ {
if (stage_egl->xwin != None) if (stage_x11->xwin != None)
{ {
XDestroyWindow (stage_egl->xdpy, stage_egl->xwin); XDestroyWindow (stage_x11->xdpy, stage_x11->xwin);
stage_egl->xwin = None; stage_x11->xwin = None;
} }
else else
stage_egl->xwin = None; stage_x11->xwin = None;
} }
if (stage_egl->egl_surface) if (stage_egl->egl_surface)
@ -87,6 +61,7 @@ static void
clutter_stage_egl_realize (ClutterActor *actor) clutter_stage_egl_realize (ClutterActor *actor)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor); ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
EGLConfig configs[2]; EGLConfig configs[2];
EGLint config_count; EGLint config_count;
@ -123,19 +98,19 @@ clutter_stage_egl_realize (ClutterActor *actor)
if (status != EGL_TRUE) if (status != EGL_TRUE)
g_warning ("eglChooseConfig"); g_warning ("eglChooseConfig");
if (stage_egl->xwin == None) if (stage_x11->xwin == None)
stage_egl->xwin stage_x11->xwin
= XCreateSimpleWindow(clutter_eglx_get_default_xdisplay(), = XCreateSimpleWindow(stage_x11->xdpy,
clutter_eglx_get_default_root_window(), stage_x11->xwin_root,
0, 0, 0, 0,
stage_egl->xwin_width, stage_x11->xwin_width,
stage_egl->xwin_height, stage_x11->xwin_height,
0, 0, 0, 0,
WhitePixel(clutter_eglx_get_default_xdisplay(), WhitePixel (stage_x11->xdpy,
clutter_eglx_get_default_screen())); stage_x11->xscreen));
XSelectInput(clutter_eglx_get_default_xdisplay(), XSelectInput(stage_x11->xdpy,
stage_egl->xwin, stage_x11->xwin,
StructureNotifyMask StructureNotifyMask
|ExposureMask |ExposureMask
/* FIXME: we may want to eplicity enable MotionMask */ /* FIXME: we may want to eplicity enable MotionMask */
@ -155,7 +130,7 @@ clutter_stage_egl_realize (ClutterActor *actor)
stage_egl->egl_surface stage_egl->egl_surface
= eglCreateWindowSurface (clutter_eglx_display(), = eglCreateWindowSurface (clutter_eglx_display(),
configs[0], configs[0],
(NativeWindowType)stage_egl->xwin, (NativeWindowType)stage_x11->xwin,
NULL); NULL);
if (stage_egl->egl_surface == EGL_NO_SURFACE) if (stage_egl->egl_surface == EGL_NO_SURFACE)
@ -176,8 +151,6 @@ clutter_stage_egl_realize (ClutterActor *actor)
if (status != EGL_TRUE) if (status != EGL_TRUE)
g_warning ("eglMakeCurrent"); g_warning ("eglMakeCurrent");
} }
else else
{ {
@ -187,137 +160,6 @@ clutter_stage_egl_realize (ClutterActor *actor)
CLUTTER_SET_PRIVATE_FLAGS(actor, CLUTTER_ACTOR_SYNC_MATRICES); 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* static GdkPixbuf*
clutter_stage_egl_draw_to_pixbuf (ClutterStage *stage, clutter_stage_egl_draw_to_pixbuf (ClutterStage *stage,
gint x, gint x,
@ -334,8 +176,9 @@ static void
clutter_stage_egl_dispose (GObject *gobject) clutter_stage_egl_dispose (GObject *gobject)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (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)); clutter_actor_unrealize (CLUTTER_ACTOR (stage_egl));
G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject); 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; 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->realize = clutter_stage_egl_realize;
actor_class->unrealize = clutter_stage_egl_unrealize; 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; stage_class->draw_to_pixbuf = clutter_stage_egl_draw_to_pixbuf;
} }
static void static void
clutter_stage_egl_init (ClutterStageEGL *stage) 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 */
}

View File

@ -11,6 +11,7 @@
#include <GLES/gl.h> #include <GLES/gl.h>
#include <GLES/egl.h> #include <GLES/egl.h>
#include "../x11/clutter-stage-x11.h"
#define CLUTTER_TYPE_STAGE_EGL (clutter_stage_egl_get_type ()) #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)) #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 struct _ClutterStageEGL
{ {
ClutterStage parent_instance; ClutterStageX11 parent_instance;
/* from the backend */
Display *xdpy;
Window xwin_root;
int xscreen;
XVisualInfo *xvisinfo;
Window xwin;
gint xwin_width;
gint xwin_height;
EGLSurface egl_surface; EGLSurface egl_surface;
EGLContext egl_context; EGLContext egl_context;
@ -41,7 +33,7 @@ struct _ClutterStageEGL
struct _ClutterStageEGLClass struct _ClutterStageEGLClass
{ {
ClutterStageClass parent_class; ClutterStageX11Class parent_class;
}; };
GType clutter_stage_egl_get_type (void) G_GNUC_CONST; GType clutter_stage_egl_get_type (void) G_GNUC_CONST;

View File

@ -17,7 +17,6 @@ noinst_LTLIBRARIES = libclutter-glx.la
libclutter_glx_la_SOURCES = \ libclutter_glx_la_SOURCES = \
clutter-backend-glx.h \ clutter-backend-glx.h \
clutter-backend-glx.c \ clutter-backend-glx.c \
clutter-event-glx.c \
clutter-stage-glx.h \ clutter-stage-glx.h \
clutter-stage-glx.c \ clutter-stage-glx.c \
clutter-glx.h clutter-glx.h

View File

@ -37,8 +37,6 @@
#include <GL/glx.h> #include <GL/glx.h>
#include <GL/gl.h> #include <GL/gl.h>
#include "clutter-backend-glx.h" #include "clutter-backend-glx.h"
#include "clutter-stage-glx.h" #include "clutter-stage-glx.h"
#include "clutter-glx.h" #include "clutter-glx.h"
@ -50,20 +48,11 @@
#include "cogl.h" #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 */ /* singleton object */
static ClutterBackendGLX *backend_singleton = NULL; 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; static gchar *clutter_vblank_name = NULL;
#ifdef __linux__ #ifdef __linux__
@ -120,16 +109,6 @@ clutter_backend_glx_pre_parse (ClutterBackend *backend,
{ {
const gchar *env_string; 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"); env_string = g_getenv ("CLUTTER_VBLANK");
if (env_string) if (env_string)
{ {
@ -137,53 +116,19 @@ clutter_backend_glx_pre_parse (ClutterBackend *backend,
env_string = NULL; env_string = NULL;
} }
return TRUE; return clutter_backend_x11_pre_parse (backend, error);
} }
static gboolean static gboolean
clutter_backend_glx_post_parse (ClutterBackend *backend, clutter_backend_glx_post_parse (ClutterBackend *backend,
GError **error) GError **error)
{ {
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (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)
{
int glx_major, glx_minor; int glx_major, glx_minor;
double dpi;
CLUTTER_NOTE (BACKEND, "Getting the X screen"); if (clutter_backend_x11_post_parse (backend, error))
{
if (clutter_screen == 0) if (!glXQueryVersion (backend_x11->xdpy, &glx_major, &glx_minor)
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)
|| !(glx_major > 1 || glx_minor > 1)) || !(glx_major > 1 || glx_minor > 1))
{ {
g_set_error (error, CLUTTER_INIT_ERROR, 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"); "XServer appears to lack required GLX support");
return 1; 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; 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[] = 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, { "vblank", 0,
0, 0,
G_OPTION_ARG_STRING, &clutter_vblank_name, G_OPTION_ARG_STRING, &clutter_vblank_name,
"VBlank method to be used (none, dri or glx)", "METHOD" "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 } { NULL }
}; };
@ -321,17 +157,12 @@ clutter_backend_glx_add_options (ClutterBackend *backend,
GOptionGroup *group) GOptionGroup *group)
{ {
g_option_group_add_entries (group, entries); g_option_group_add_entries (group, entries);
clutter_backend_x11_add_options (backend, group);
} }
static void static void
clutter_backend_glx_finalize (GObject *gobject) 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) if (backend_singleton)
backend_singleton = NULL; backend_singleton = NULL;
@ -341,19 +172,6 @@ clutter_backend_glx_finalize (GObject *gobject)
static void static void
clutter_backend_glx_dispose (GObject *gobject) 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); G_OBJECT_CLASS (clutter_backend_glx_parent_class)->dispose (gobject);
} }
@ -390,7 +208,6 @@ check_vblank_env (const char *name)
return FALSE; return FALSE;
} }
static ClutterFeatureFlags static ClutterFeatureFlags
clutter_backend_glx_get_features (ClutterBackend *backend) 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 */ /* 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" CLUTTER_NOTE (BACKEND, "Checking features\n"
"GL_VENDOR: %s\n" "GL_VENDOR: %s\n"
"GL_RENDERER: %s\n" "GL_RENDERER: %s\n"
@ -413,8 +228,8 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
glGetString (GL_EXTENSIONS)); glGetString (GL_EXTENSIONS));
glx_extensions = glx_extensions =
glXQueryExtensionsString (clutter_glx_get_default_display (), glXQueryExtensionsString (clutter_x11_get_default_display (),
clutter_glx_get_default_screen ()); clutter_x11_get_default_screen ());
CLUTTER_NOTE (BACKEND, "GLX Extensions: %s", glx_extensions); 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"); CLUTTER_NOTE (MISC, "backend features checked");
return flags; return flags|clutter_backend_x11_get_features (backend);
} }
static void static void
clutter_backend_glx_redraw (ClutterBackend *backend) clutter_backend_glx_redraw (ClutterBackend *backend)
{ {
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterStageGLX *stage_glx; 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)); clutter_actor_paint (CLUTTER_ACTOR (stage_glx));
/* Why this paint is done in backend as likely GL windowing system /* Why this paint is done in backend as likely GL windowing system
* specific calls, like swapping buffers. * specific calls, like swapping buffers.
*/ */
if (stage_glx->xwin) if (stage_x11->xwin)
{ {
clutter_backend_glx_wait_for_vblank (stage_glx->backend); clutter_backend_glx_wait_for_vblank (CLUTTER_BACKEND_GLX(backend));
glXSwapBuffers (stage_glx->xdpy, stage_glx->xwin); glXSwapBuffers (stage_x11->xdpy, stage_x11->xwin);
} }
else else
{ {
@ -539,9 +356,52 @@ clutter_backend_glx_redraw (ClutterBackend *backend)
glXWaitGL (); glXWaitGL ();
CLUTTER_GLERR (); 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 static void
clutter_backend_glx_class_init (ClutterBackendGLXClass *klass) 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->pre_parse = clutter_backend_glx_pre_parse;
backend_class->post_parse = clutter_backend_glx_post_parse; backend_class->post_parse = clutter_backend_glx_post_parse;
backend_class->init_stage = clutter_backend_glx_init_stage; 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->add_options = clutter_backend_glx_add_options;
backend_class->get_features = clutter_backend_glx_get_features; backend_class->get_features = clutter_backend_glx_get_features;
backend_class->redraw = clutter_backend_glx_redraw; backend_class->redraw = clutter_backend_glx_redraw;
@ -565,12 +423,7 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
static void static void
clutter_backend_glx_init (ClutterBackendGLX *backend_glx) 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 */ /* every backend must implement this function */
@ -580,14 +433,6 @@ _clutter_backend_impl_get_type (void)
return clutter_backend_glx_get_type (); return clutter_backend_glx_get_type ();
} }
static int
error_handler(Display *xdpy,
XErrorEvent *error)
{
TrappedErrorCode = error->error_code;
return 0;
}
void void
clutter_backend_glx_wait_for_vblank (ClutterBackendGLX *backend_glx) clutter_backend_glx_wait_for_vblank (ClutterBackendGLX *backend_glx)
{ {
@ -623,175 +468,3 @@ clutter_backend_glx_wait_for_vblank (ClutterBackendGLX *backend_glx)
break; 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;
}
}
}

View File

@ -30,6 +30,7 @@
#include <GL/glx.h> #include <GL/glx.h>
#include <GL/gl.h> #include <GL/gl.h>
#include "../x11/clutter-backend-x11.h"
#include "clutter-glx.h" #include "clutter-glx.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -59,29 +60,9 @@ typedef int (*WaitVideoSyncProc) (int divisor,
unsigned int *count); unsigned int *count);
typedef int (*SwapIntervalProc) (int interval); typedef int (*SwapIntervalProc) (int interval);
typedef struct _ClutterGLXEventFilter
{
ClutterGLXFilterFunc func;
gpointer data;
} ClutterGLXEventFilter;
struct _ClutterBackendGLX struct _ClutterBackendGLX
{ {
ClutterBackend parent_instance; ClutterBackendX11 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;
/* Vblank stuff */ /* Vblank stuff */
GetVideoSyncProc get_video_sync; GetVideoSyncProc get_video_sync;
@ -89,20 +70,13 @@ struct _ClutterBackendGLX
SwapIntervalProc swap_interval; SwapIntervalProc swap_interval;
gint dri_fd; gint dri_fd;
ClutterGLXVBlankType vblank_type; ClutterGLXVBlankType vblank_type;
/* props */
Atom atom_WM_STATE;
Atom atom_WM_STATE_FULLSCREEN;
}; };
struct _ClutterBackendGLXClass 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); void clutter_backend_glx_wait_for_vblank (ClutterBackendGLX *backend_glx);
GType clutter_backend_glx_get_type (void) G_GNUC_CONST; GType clutter_backend_glx_get_type (void) G_GNUC_CONST;

View File

@ -27,9 +27,8 @@
* SECTION:clutter-glx * SECTION:clutter-glx
* @short_description: GLX specific API * @short_description: GLX specific API
* *
* The GLX backend for Clutter provides some specific API, allowing * The GLX backend for Clutter provides some specific API for GLX
* integration with the Xlibs API for embedding and manipulating the * related calls.
* stage window, or for trapping X errors.
* *
* The ClutterGLX API is available since Clutter 0.4 * The ClutterGLX API is available since Clutter 0.4
*/ */
@ -40,40 +39,10 @@
#include <glib.h> #include <glib.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <clutter/clutter-stage.h> #include <clutter/clutter-stage.h>
G_BEGIN_DECLS 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 G_END_DECLS

View File

@ -39,172 +39,71 @@
#include "cogl.h" #include "cogl.h"
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#include <GL/glx.h> #include <GL/glx.h>
#include <GL/gl.h> #include <GL/gl.h>
#include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h> #include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
G_DEFINE_TYPE (ClutterStageGLX, clutter_stage_glx, CLUTTER_TYPE_STAGE); G_DEFINE_TYPE (ClutterStageGLX, clutter_stage_glx, CLUTTER_TYPE_STAGE_X11);
#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);
}
static void static void
clutter_stage_glx_unrealize (ClutterActor *actor) clutter_stage_glx_unrealize (ClutterActor *actor)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor); ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
gboolean was_offscreen; gboolean was_offscreen;
CLUTTER_MARK(); CLUTTER_MARK();
g_object_get (actor, "offscreen", &was_offscreen, NULL); g_object_get (actor, "offscreen", &was_offscreen, NULL);
clutter_glx_trap_x_errors (); clutter_x11_trap_x_errors ();
if (G_UNLIKELY (was_offscreen)) if (G_UNLIKELY (was_offscreen))
{ {
if (stage_glx->glxpixmap) if (stage_glx->glxpixmap)
{ {
glXDestroyGLXPixmap (stage_glx->xdpy, stage_glx->glxpixmap); glXDestroyGLXPixmap (stage_x11->xdpy,stage_glx->glxpixmap);
stage_glx->glxpixmap = None; stage_glx->glxpixmap = None;
} }
if (stage_glx->xpixmap) if (stage_x11->xpixmap)
{ {
XFreePixmap (stage_glx->xdpy, stage_glx->xpixmap); XFreePixmap (stage_x11->xdpy, stage_x11->xpixmap);
stage_glx->xpixmap = None; stage_x11->xpixmap = None;
} }
} }
else 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); XDestroyWindow (stage_x11->xdpy, stage_x11->xwin);
stage_glx->xwin = None; stage_x11->xwin = None;
} }
else 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) 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; 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 (); 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 static void
clutter_stage_glx_realize (ClutterActor *actor) clutter_stage_glx_realize (ClutterActor *actor)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor); ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
gboolean is_offscreen; gboolean is_offscreen;
@ -225,21 +124,21 @@ clutter_stage_glx_realize (ClutterActor *actor)
0 0
}; };
if (stage_glx->xvisinfo) if (stage_x11->xvisinfo)
XFree (stage_glx->xvisinfo); XFree (stage_x11->xvisinfo);
if (stage_glx->xvisinfo == None) if (stage_x11->xvisinfo == None)
stage_glx->xvisinfo = glXChooseVisual (stage_glx->xdpy, stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy,
stage_glx->xscreen, stage_x11->xscreen,
gl_attributes); gl_attributes);
if (!stage_glx->xvisinfo) if (!stage_x11->xvisinfo)
{ {
g_critical ("Unable to find suitable GL visual."); g_critical ("Unable to find suitable GL visual.");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return; return;
} }
if (stage_glx->xwin == None) if (stage_x11->xwin == None)
{ {
XSetWindowAttributes xattr; XSetWindowAttributes xattr;
unsigned long mask; unsigned long mask;
@ -247,28 +146,28 @@ clutter_stage_glx_realize (ClutterActor *actor)
CLUTTER_NOTE (MISC, "Creating stage X window"); CLUTTER_NOTE (MISC, "Creating stage X window");
/* window attributes */ /* window attributes */
xattr.background_pixel = WhitePixel (stage_glx->xdpy, xattr.background_pixel = WhitePixel (stage_x11->xdpy,
stage_glx->xscreen); stage_x11->xscreen);
xattr.border_pixel = 0; xattr.border_pixel = 0;
xattr.colormap = XCreateColormap (stage_glx->xdpy, xattr.colormap = XCreateColormap (stage_x11->xdpy,
stage_glx->xwin_root, stage_x11->xwin_root,
stage_glx->xvisinfo->visual, stage_x11->xvisinfo->visual,
AllocNone); AllocNone);
mask = CWBackPixel | CWBorderPixel | CWColormap; mask = CWBackPixel | CWBorderPixel | CWColormap;
stage_glx->xwin = XCreateWindow (stage_glx->xdpy, stage_x11->xwin = XCreateWindow (stage_x11->xdpy,
stage_glx->xwin_root, stage_x11->xwin_root,
0, 0, 0, 0,
stage_glx->xwin_width, stage_x11->xwin_width,
stage_glx->xwin_height, stage_x11->xwin_height,
0, 0,
stage_glx->xvisinfo->depth, stage_x11->xvisinfo->depth,
InputOutput, InputOutput,
stage_glx->xvisinfo->visual, stage_x11->xvisinfo->visual,
mask, &xattr); mask, &xattr);
} }
CLUTTER_NOTE (MISC, "XSelectInput"); CLUTTER_NOTE (MISC, "XSelectInput");
XSelectInput (stage_glx->xdpy, stage_glx->xwin, XSelectInput (stage_x11->xdpy, stage_x11->xwin,
StructureNotifyMask | StructureNotifyMask |
FocusChangeMask | FocusChangeMask |
ExposureMask | ExposureMask |
@ -279,16 +178,16 @@ clutter_stage_glx_realize (ClutterActor *actor)
PropertyChangeMask); PropertyChangeMask);
/* no user resize.. */ /* 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) 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"); CLUTTER_NOTE (GL, "Creating GL Context");
stage_glx->gl_context = glXCreateContext (stage_glx->xdpy, stage_glx->gl_context = glXCreateContext (stage_x11->xdpy,
stage_glx->xvisinfo, stage_x11->xvisinfo,
0, 0,
True); True);
@ -302,7 +201,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
} }
CLUTTER_NOTE (GL, "glXMakeCurrent"); 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 else
{ {
@ -317,78 +216,50 @@ clutter_stage_glx_realize (ClutterActor *actor)
0 0
}; };
if (stage_glx->xvisinfo) if (stage_x11->xvisinfo)
XFree (stage_glx->xvisinfo); XFree (stage_x11->xvisinfo);
CLUTTER_NOTE (GL, "glXChooseVisual"); CLUTTER_NOTE (GL, "glXChooseVisual");
stage_glx->xvisinfo = glXChooseVisual (stage_glx->xdpy, stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy,
stage_glx->xscreen, stage_x11->xscreen,
gl_attributes); gl_attributes);
if (!stage_glx->xvisinfo) if (!stage_x11->xvisinfo)
{ {
g_critical ("Unable to find suitable GL visual."); g_critical ("Unable to find suitable GL visual.");
goto fail; goto fail;
} }
if (stage_glx->gl_context) 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_x11->xpixmap = XCreatePixmap (stage_x11->xdpy,
stage_glx->xwin_root, stage_x11->xwin_root,
stage_glx->xwin_width, stage_x11->xwin_width,
stage_glx->xwin_height, stage_x11->xwin_height,
DefaultDepth (stage_glx->xdpy, DefaultDepth (stage_x11->xdpy,
stage_glx->xscreen)); stage_x11->xscreen));
stage_glx->glxpixmap = glXCreateGLXPixmap (stage_glx->xdpy, stage_glx->glxpixmap = glXCreateGLXPixmap (stage_x11->xdpy,
stage_glx->xvisinfo, stage_x11->xvisinfo,
stage_glx->xpixmap); stage_x11->xpixmap);
/* indirect */ /* indirect */
stage_glx->gl_context = glXCreateContext (stage_glx->xdpy, stage_glx->gl_context = glXCreateContext (stage_x11->xdpy,
stage_glx->xvisinfo, stage_x11->xvisinfo,
0, 0,
False); False);
clutter_glx_trap_x_errors (); clutter_x11_trap_x_errors ();
glXMakeCurrent (stage_glx->xdpy, glXMakeCurrent (stage_x11->xdpy,
stage_glx->glxpixmap, stage_glx->glxpixmap,
stage_glx->gl_context); stage_glx->gl_context);
if (clutter_glx_untrap_x_errors ()) if (clutter_x11_untrap_x_errors ())
{ {
g_critical ("Unable to set up offscreen context."); g_critical ("Unable to set up offscreen context.");
goto fail; 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 */ /* Make sure the viewport gets set up correctly */
@ -402,235 +273,6 @@ clutter_stage_glx_realize (ClutterActor *actor)
return; 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 static void
snapshot_pixbuf_free (guchar *pixels, snapshot_pixbuf_free (guchar *pixels,
gpointer data) gpointer data)
@ -649,9 +291,11 @@ clutter_stage_glx_draw_to_pixbuf (ClutterStage *stage,
GdkPixbuf *pixb; GdkPixbuf *pixb;
ClutterActor *actor; ClutterActor *actor;
ClutterStageGLX *stage_glx; ClutterStageGLX *stage_glx;
ClutterStageX11 *stage_x11;
gboolean is_offscreen = FALSE; gboolean is_offscreen = FALSE;
stage_glx = CLUTTER_STAGE_GLX (stage); stage_glx = CLUTTER_STAGE_GLX (stage);
stage_x11 = CLUTTER_STAGE_X11 (stage);
actor = CLUTTER_ACTOR (stage); actor = CLUTTER_ACTOR (stage);
if (width < 0) if (width < 0)
@ -664,13 +308,13 @@ clutter_stage_glx_draw_to_pixbuf (ClutterStage *stage,
if (G_UNLIKELY (is_offscreen)) 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, pixb = gdk_pixbuf_xlib_get_from_drawable (NULL,
(Drawable) stage_glx->xpixmap, (Drawable) stage_x11->xpixmap,
DefaultColormap (stage_glx->xdpy, DefaultColormap (stage_x11->xdpy,
stage_glx->xscreen), stage_x11->xscreen),
stage_glx->xvisinfo->visual, stage_x11->xvisinfo->visual,
x, y, x, y,
0, 0, 0, 0,
width, height); width, height);
@ -712,8 +356,9 @@ static void
clutter_stage_glx_dispose (GObject *gobject) clutter_stage_glx_dispose (GObject *gobject)
{ {
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (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)); clutter_actor_unrealize (CLUTTER_ACTOR (stage_glx));
G_OBJECT_CLASS (clutter_stage_glx_parent_class)->dispose (gobject); 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; 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->realize = clutter_stage_glx_realize;
actor_class->unrealize = clutter_stage_glx_unrealize; 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->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 static void
clutter_stage_glx_init (ClutterStageGLX *stage) 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;
} }

View File

@ -30,6 +30,7 @@
#include <GL/gl.h> #include <GL/gl.h>
#include "clutter-backend-glx.h" #include "clutter-backend-glx.h"
#include "../x11/clutter-stage-x11.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -45,32 +46,15 @@ typedef struct _ClutterStageGLXClass ClutterStageGLXClass;
struct _ClutterStageGLX struct _ClutterStageGLX
{ {
ClutterStage parent_instance; ClutterStageX11 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;
GLXPixmap glxpixmap; GLXPixmap glxpixmap;
GLXContext gl_context; GLXContext gl_context;
guint is_foreign_xwin : 1;
ClutterBackendGLX *backend;
ClutterStageState state;
}; };
struct _ClutterStageGLXClass struct _ClutterStageGLXClass
{ {
ClutterStageClass parent_class; ClutterStageX11Class parent_class;
}; };
GType clutter_stage_glx_get_type (void) G_GNUC_CONST; GType clutter_stage_glx_get_type (void) G_GNUC_CONST;

23
clutter/x11/Makefile.am Normal file
View 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

View File

@ -0,0 +1,32 @@
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, 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

View 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;
}
}
}

View 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__ */

View File

@ -19,13 +19,11 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif
#include "clutter-stage-glx.h" #include "clutter-stage-x11.h"
#include "clutter-backend-glx.h" #include "clutter-backend-x11.h"
#include "clutter-glx.h" #include "clutter-x11.h"
#include "../clutter-backend.h" #include "../clutter-backend.h"
#include "../clutter-event.h" #include "../clutter-event.h"
@ -107,7 +105,7 @@ clutter_event_source_new (ClutterBackend *backend)
static gboolean static gboolean
check_xpending (ClutterBackend *backend) check_xpending (ClutterBackend *backend)
{ {
return XPending (CLUTTER_BACKEND_GLX (backend)->xdpy); return XPending (CLUTTER_BACKEND_X11 (backend)->xdpy);
} }
static gboolean static gboolean
@ -132,12 +130,12 @@ xembed_send_message (Display *xdisplay,
ev.xclient.data.l[3] = data1; ev.xclient.data.l[3] = data1;
ev.xclient.data.l[4] = data2; ev.xclient.data.l[4] = data2;
clutter_glx_trap_x_errors (); clutter_x11_trap_x_errors ();
XSendEvent (xdisplay, window, False, NoEventMask, &ev); XSendEvent (xdisplay, window, False, NoEventMask, &ev);
XSync (xdisplay, False); XSync (xdisplay, False);
if (clutter_glx_untrap_x_errors ()) if (clutter_x11_untrap_x_errors ())
return False; return False;
return True; return True;
@ -156,29 +154,29 @@ xembed_set_info (Display *xdisplay,
list[0] = MAX_SUPPORTED_XEMBED_VERSION; list[0] = MAX_SUPPORTED_XEMBED_VERSION;
list[1] = XEMBED_MAPPED; list[1] = XEMBED_MAPPED;
clutter_glx_trap_x_errors (); clutter_x11_trap_x_errors ();
XChangeProperty (xdisplay, window, XChangeProperty (xdisplay, window,
atom_XEMBED_INFO, atom_XEMBED_INFO,
atom_XEMBED_INFO, 32, atom_XEMBED_INFO, 32,
PropModeReplace, (unsigned char *) list, 2); PropModeReplace, (unsigned char *) list, 2);
clutter_glx_untrap_x_errors (); clutter_x11_untrap_x_errors ();
} }
void void
_clutter_backend_glx_events_init (ClutterBackend *backend) _clutter_backend_x11_events_init (ClutterBackend *backend)
{ {
GSource *source; GSource *source;
ClutterEventSource *event_source; ClutterEventSource *event_source;
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
int connection_number; int connection_number;
connection_number = ConnectionNumber (backend_glx->xdpy); connection_number = ConnectionNumber (backend_x11->xdpy);
CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number); CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number);
Atom_XEMBED = XInternAtom (backend_glx->xdpy, "_XEMBED", False); Atom_XEMBED = XInternAtom (backend_x11->xdpy, "_XEMBED", False);
Atom_WM_PROTOCOLS = XInternAtom (backend_glx->xdpy, "WM_PROTOCOLS", 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; event_source = (ClutterEventSource *) source;
g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS); 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_set_can_recurse (source, TRUE);
g_source_attach (source, NULL); g_source_attach (source, NULL);
xembed_set_info (backend_glx->xdpy, xembed_set_info (backend_x11->xdpy,
clutter_glx_get_stage_window (CLUTTER_STAGE (backend_glx->stage)), clutter_x11_get_stage_window
(CLUTTER_STAGE (backend_x11->stage)),
0); 0);
} }
void 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"); CLUTTER_NOTE (EVENT, "Destroying the event source");
event_sources = g_list_remove (event_sources, event_sources = g_list_remove (event_sources,
backend_glx->event_source); backend_x11->event_source);
g_source_destroy (backend_glx->event_source); g_source_destroy (backend_x11->event_source);
g_source_unref (backend_glx->event_source); g_source_unref (backend_x11->event_source);
backend_glx->event_source = NULL; backend_x11->event_source = NULL;
} }
} }
static void static void
set_user_time (Display *display, set_user_time (Display *display,
Window *xwindow, Window *xwindow,
@ -256,20 +254,20 @@ translate_key_event (ClutterBackend *backend,
} }
static gboolean static gboolean
handle_wm_protocols_event (ClutterBackendGLX *backend_glx, handle_wm_protocols_event (ClutterBackendX11 *backend_x11,
XEvent *xevent) XEvent *xevent)
{ {
Atom atom = (Atom) xevent->xclient.data.l[0]; Atom atom = (Atom) xevent->xclient.data.l[0];
Atom Atom_WM_DELETE_WINDOW; Atom Atom_WM_DELETE_WINDOW;
Atom Atom_NEW_WM_PING; Atom Atom_NEW_WM_PING;
ClutterStage *stage = CLUTTER_STAGE (backend_glx->stage); ClutterStage *stage = CLUTTER_STAGE (backend_x11->stage);
Window stage_xwindow = clutter_glx_get_stage_window (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", "WM_DELETE_WINDOW",
False); 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 && if (atom == Atom_WM_DELETE_WINDOW &&
xevent->xany.window == stage_xwindow) xevent->xany.window == stage_xwindow)
@ -282,7 +280,7 @@ handle_wm_protocols_event (ClutterBackendGLX *backend_glx,
CLUTTER_NOTE (EVENT, "delete window:\twindow: %ld", CLUTTER_NOTE (EVENT, "delete window:\twindow: %ld",
xevent->xclient.window); xevent->xclient.window);
set_user_time (backend_glx->xdpy, set_user_time (backend_x11->xdpy,
&stage_xwindow, &stage_xwindow,
xevent->xclient.data.l[1]); xevent->xclient.data.l[1]);
@ -293,8 +291,8 @@ handle_wm_protocols_event (ClutterBackendGLX *backend_glx,
{ {
XClientMessageEvent xclient = xevent->xclient; XClientMessageEvent xclient = xevent->xclient;
xclient.window = backend_glx->xwin_root; xclient.window = backend_x11->xwin_root;
XSendEvent (backend_glx->xdpy, xclient.window, XSendEvent (backend_x11->xdpy, xclient.window,
False, False,
SubstructureRedirectMask | SubstructureNotifyMask, SubstructureRedirectMask | SubstructureNotifyMask,
(XEvent *) &xclient); (XEvent *) &xclient);
@ -307,12 +305,12 @@ handle_wm_protocols_event (ClutterBackendGLX *backend_glx,
} }
static gboolean static gboolean
handle_xembed_event (ClutterBackendGLX *backend_glx, handle_xembed_event (ClutterBackendX11 *backend_x11,
XEvent *xevent) XEvent *xevent)
{ {
ClutterActor *stage; 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]) switch (xevent->xclient.data.l[1])
{ {
@ -325,8 +323,8 @@ handle_xembed_event (ClutterBackendGLX *backend_glx,
clutter_actor_realize (stage); clutter_actor_realize (stage);
clutter_actor_show (stage); clutter_actor_show (stage);
xembed_set_info (backend_glx->xdpy, xembed_set_info (backend_x11->xdpy,
clutter_glx_get_stage_window (CLUTTER_STAGE (stage)), clutter_x11_get_stage_window (CLUTTER_STAGE (stage)),
XEMBED_MAPPED); XEMBED_MAPPED);
break; break;
case XEMBED_WINDOW_ACTIVATE: case XEMBED_WINDOW_ACTIVATE:
@ -338,7 +336,7 @@ handle_xembed_event (ClutterBackendGLX *backend_glx,
case XEMBED_FOCUS_IN: case XEMBED_FOCUS_IN:
CLUTTER_NOTE (EVENT, "got XEMBED_FOCUS_IN"); CLUTTER_NOTE (EVENT, "got XEMBED_FOCUS_IN");
if (ParentEmbedderWin) if (ParentEmbedderWin)
xembed_send_message (backend_glx->xdpy, ParentEmbedderWin, xembed_send_message (backend_x11->xdpy, ParentEmbedderWin,
XEMBED_FOCUS_NEXT, XEMBED_FOCUS_NEXT,
0, 0, 0); 0, 0, 0);
break; break;
@ -356,39 +354,39 @@ event_translate (ClutterBackend *backend,
ClutterEvent *event, ClutterEvent *event,
XEvent *xevent) XEvent *xevent)
{ {
ClutterBackendGLX *backend_glx; ClutterBackendX11 *backend_x11;
ClutterStageGLX *stage_glx; ClutterStageX11 *stage_x11;
ClutterStage *stage; ClutterStage *stage;
gboolean res; gboolean res;
Window xwindow, stage_xwindow; 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 = CLUTTER_STAGE (_clutter_backend_get_stage (backend));
stage_glx = CLUTTER_STAGE_GLX (stage); stage_x11 = CLUTTER_STAGE_X11 (stage);
stage_xwindow = clutter_glx_get_stage_window (stage); stage_xwindow = clutter_x11_get_stage_window (stage);
xwindow = xevent->xany.window; xwindow = xevent->xany.window;
if (xwindow == None) if (xwindow == None)
xwindow = stage_xwindow; xwindow = stage_xwindow;
if (backend_glx->event_filters) if (backend_x11->event_filters)
{ {
GSList *node; GSList *node;
ClutterGLXEventFilter *filter; ClutterX11EventFilter *filter;
node = backend_glx->event_filters; node = backend_x11->event_filters;
while (node) while (node)
{ {
filter = (ClutterGLXEventFilter *)node->data; filter = (ClutterX11EventFilter *)node->data;
switch (filter->func(xevent, event, filter->data)) switch (filter->func(xevent, event, filter->data))
{ {
case CLUTTER_GLX_FILTER_CONTINUE: case CLUTTER_X11_FILTER_CONTINUE:
break; break;
case CLUTTER_GLX_FILTER_TRANSLATE: case CLUTTER_X11_FILTER_TRANSLATE:
return TRUE; return TRUE;
case CLUTTER_GLX_FILTER_REMOVE: case CLUTTER_X11_FILTER_REMOVE:
return FALSE; return FALSE;
default: default:
break; break;
@ -414,7 +412,7 @@ event_translate (ClutterBackend *backend,
break; break;
case PropertyNotify: case PropertyNotify:
{ {
if (xevent->xproperty.atom == backend_glx->atom_WM_STATE) if (xevent->xproperty.atom == backend_x11->atom_WM_STATE)
{ {
Atom type; Atom type;
gint format; gint format;
@ -424,15 +422,15 @@ event_translate (ClutterBackend *backend,
gulong i; gulong i;
gboolean fullscreen_set = FALSE; gboolean fullscreen_set = FALSE;
clutter_glx_trap_x_errors (); clutter_x11_trap_x_errors ();
XGetWindowProperty (backend_glx->xdpy, XGetWindowProperty (backend_x11->xdpy,
stage_xwindow, stage_xwindow,
backend_glx->atom_WM_STATE, backend_x11->atom_WM_STATE,
0, G_MAXLONG, 0, G_MAXLONG,
False, XA_ATOM, False, XA_ATOM,
&type, &format, &nitems, &type, &format, &nitems,
&bytes_after, &data); &bytes_after, &data);
clutter_glx_untrap_x_errors (); clutter_x11_untrap_x_errors ();
if (type != None && data != NULL) if (type != None && data != NULL)
{ {
@ -441,23 +439,23 @@ event_translate (ClutterBackend *backend,
i = 0; i = 0;
while (i < nitems) while (i < nitems)
{ {
if (atoms[i] == backend_glx->atom_WM_STATE_FULLSCREEN) if (atoms[i] == backend_x11->atom_WM_STATE_FULLSCREEN)
fullscreen_set = TRUE; fullscreen_set = TRUE;
i++; i++;
} }
if (fullscreen_set if (fullscreen_set
!= !!(stage_glx->state & CLUTTER_STAGE_STATE_FULLSCREEN)) != !!(stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN))
{ {
if (fullscreen_set) if (fullscreen_set)
stage_glx->state |= CLUTTER_STAGE_STATE_FULLSCREEN; stage_x11->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
else else
stage_glx->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN; stage_x11->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;
event->type = CLUTTER_STAGE_STATE; event->type = CLUTTER_STAGE_STATE;
event->stage_state.changed_mask event->stage_state.changed_mask
= CLUTTER_STAGE_STATE_FULLSCREEN; = CLUTTER_STAGE_STATE_FULLSCREEN;
event->stage_state.new_state = stage_glx->state; event->stage_state.new_state = stage_x11->state;
} }
else else
res = FALSE; res = FALSE;
@ -470,26 +468,26 @@ event_translate (ClutterBackend *backend,
} }
break; break;
case FocusIn: case FocusIn:
if (!(stage_glx->state & CLUTTER_STAGE_STATE_ACTIVATED)) if (!(stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED))
{ {
/* TODO: check xevent->xfocus.detail ? */ /* 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->type = CLUTTER_STAGE_STATE;
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED; 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 else
res = FALSE; res = FALSE;
break; break;
case FocusOut: 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->type = CLUTTER_STAGE_STATE;
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED; 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 else
res = FALSE; res = FALSE;
@ -499,7 +497,7 @@ event_translate (ClutterBackend *backend,
XEvent foo_xev; XEvent foo_xev;
/* Cheap compress */ /* Cheap compress */
while (XCheckTypedWindowEvent (backend_glx->xdpy, while (XCheckTypedWindowEvent (backend_x11->xdpy,
xevent->xexpose.window, xevent->xexpose.window,
Expose, Expose,
&foo_xev)); &foo_xev));
@ -514,7 +512,7 @@ event_translate (ClutterBackend *backend,
case KeyPress: case KeyPress:
event->type = CLUTTER_KEY_PRESS; event->type = CLUTTER_KEY_PRESS;
translate_key_event (backend, event, xevent); 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; break;
case KeyRelease: case KeyRelease:
event->type = CLUTTER_KEY_RELEASE; event->type = CLUTTER_KEY_RELEASE;
@ -555,7 +553,7 @@ event_translate (ClutterBackend *backend,
break; break;
} }
set_user_time (backend_glx->xdpy, &xwindow, event->button.time); set_user_time (backend_x11->xdpy, &xwindow, event->button.time);
break; break;
case ButtonRelease: case ButtonRelease:
/* scroll events don't have a corresponding release */ /* scroll events don't have a corresponding release */
@ -593,10 +591,10 @@ event_translate (ClutterBackend *backend,
event->type = event->any.type = CLUTTER_CLIENT_MESSAGE; event->type = event->any.type = CLUTTER_CLIENT_MESSAGE;
if (xevent->xclient.message_type == Atom_XEMBED) 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) 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; event->type = event->any.type = CLUTTER_DELETE;
} }
break; break;
@ -612,9 +610,9 @@ event_translate (ClutterBackend *backend,
static void static void
events_queue (ClutterBackend *backend) events_queue (ClutterBackend *backend)
{ {
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterEvent *event; ClutterEvent *event;
Display *xdisplay = backend_glx->xdpy; Display *xdisplay = backend_x11->xdpy;
XEvent xevent; XEvent xevent;
ClutterMainContext *clutter_context; ClutterMainContext *clutter_context;

View 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;
}

View 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
View 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__ */

View File

@ -87,6 +87,8 @@ fi
AC_SUBST(CLUTTER_NO_FPU) AC_SUBST(CLUTTER_NO_FPU)
backendextra=
backendextralib=
clutterbackend=glx clutterbackend=glx
AC_ARG_WITH([flavour], AC_ARG_WITH([flavour],
AC_HELP_STRING([--with-flavour=@<:@glx/eglx/eglnative/sdl@:>@], AC_HELP_STRING([--with-flavour=@<:@glx/eglx/eglnative/sdl@:>@],
@ -151,35 +153,6 @@ case $clutterbackend in
fi 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) glx)
clutter_gl_header="GL/gl.h" clutter_gl_header="GL/gl.h"
@ -205,11 +178,13 @@ case $clutterbackend in
GLX_LIBS="$X11_LIBS -lGL" GLX_LIBS="$X11_LIBS -lGL"
GLX_CFLAGS="$X11_CFLAGS" GLX_CFLAGS="$X11_CFLAGS"
backendextra=x11
backendextralib="x11/libclutter-x11.la"
;; ;;
eglx) eglx)
$clutter_gl_header="GLES/gl.h" clutter_gl_header="GLES/gl.h"
CLUTTER_FLAVOUR="eglx" CLUTTER_FLAVOUR="eglx"
AC_DEFINE([HAVE_CLUTTER_EGL], 1, [Have the EGL backend]) AC_DEFINE([HAVE_CLUTTER_EGL], 1, [Have the EGL backend])
@ -217,15 +192,11 @@ case $clutterbackend in
CLUTTER_COGL="gles" CLUTTER_COGL="gles"
AC_DEFINE([HAVE_COGL_GLES], 1, [Have GL/ES for rendering]) 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_CHECK_HEADERS([GLES/egl.h $clutter_gl_header],,
[AC_MSG_ERROR([Unable to locate required GLES headers])]) [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. # The powervr sdk uses lower case.
AC_CHECK_LIB(GLES_CM, eglInitialize, HAVE_LIBGLES=yes, HAVE_LIBGLES=no) AC_CHECK_LIB(GLES_CM, eglInitialize, HAVE_LIBGLES=yes, HAVE_LIBGLES=no)
if test "x$HAVE_LIBGLES" = "xno"; then if test "x$HAVE_LIBGLES" = "xno"; then
@ -233,14 +204,21 @@ case $clutterbackend in
if test "x$HAVE_LIBGLES" = "xno"; then if test "x$HAVE_LIBGLES" = "xno"; then
AC_MSG_ERROR([GLES library not found and egl backend requested.]); AC_MSG_ERROR([GLES library not found and egl backend requested.]);
fi fi
EGL_LIBS="-lgles_cm" EGL_LIBS="gles_cm"
else else
EGL_LIBS="-lGLES_CM" EGL_LIBS="GLES_CM"
fi
fi 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" EGL_CFLAGS="$EGL_CFLAGS $X11_CFLAGS"
backendextra=x11
backendextralib="x11/libclutter-x11.la"
;; ;;
eglnative) eglnative)
@ -264,6 +242,9 @@ case $clutterbackend in
AC_MSG_ERROR([libGLES_CM not found and egl backend requested.]); AC_MSG_ERROR([libGLES_CM not found and egl backend requested.]);
fi 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]) PKG_CHECK_MODULES(TSLIB, tslib-1.0, [have_tslib=yes], [have_tslib=no])
if test x$have_tslib = xyes; then if test x$have_tslib = xyes; then
AC_DEFINE([HAVE_TSLIB], 1, [Have tslib for touchscreen handling]) AC_DEFINE([HAVE_TSLIB], 1, [Have tslib for touchscreen handling])
@ -295,6 +276,8 @@ esac
CLUTTER_GL_HEADER=$clutter_gl_header CLUTTER_GL_HEADER=$clutter_gl_header
AC_SUBST([clutterbackend]) AC_SUBST([clutterbackend])
AC_SUBST([backendextra])
AC_SUBST([backendextralib])
AC_SUBST(CLUTTER_FLAVOUR) AC_SUBST(CLUTTER_FLAVOUR)
AC_SUBST(CLUTTER_COGL) AC_SUBST(CLUTTER_COGL)
AC_SUBST(CLUTTER_GL_HEADER) AC_SUBST(CLUTTER_GL_HEADER)
@ -392,6 +375,7 @@ AC_CONFIG_FILES([
Makefile Makefile
clutter/Makefile clutter/Makefile
clutter/clutter-version.h clutter/clutter-version.h
clutter/x11/Makefile
clutter/glx/Makefile clutter/glx/Makefile
clutter/eglx/Makefile clutter/eglx/Makefile
clutter/eglnative/Makefile clutter/eglnative/Makefile