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