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