diff --git a/ChangeLog b/ChangeLog index a831e5f19..1e91fcb1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2007-03-27 Matthew Allum + + * clutter/cogl/Makefile.am: + * clutter/cogl/cogl.h: + * clutter/cogl/gles/Makefile.am: + * clutter/cogl/gles/cogl.c: + Begin poplulating cogl GLES code. + + * configure.ac: + * clutter/egl/clutter-event-egl.c: + * clutter/egl/clutter-stage-egl.c: + * clutter/egl/clutter-stage-egl.h: + * clutter/egl/clutter-backend-egl.c: + * clutter/egl/clutter-backend-egl.h: + * clutter/egl/clutter-egl.h: + Add initial EGL/X backend work mostly ported from backend branch. + Builds but untested as yet. + + * clutter/glx/clutter-stage-glx.c: + Only include XFixes Header if we have have it. + + * clutter/clutter-behaviour.c: (clutter_behaviour_apply): + * clutter/clutter-behaviour.h: + Add clutter_behaviour_is_applied() + 2007-03-27 Emmanuele Bassi * clutter/clutter-stage.h: Remove unused clutter_stage_flush() diff --git a/clutter/clutter-behaviour.c b/clutter/clutter-behaviour.c index e9987c5c1..44f5c211d 100644 --- a/clutter/clutter-behaviour.c +++ b/clutter/clutter-behaviour.c @@ -214,6 +214,27 @@ clutter_behaviour_apply (ClutterBehaviour *behave, behave->priv->actors = g_slist_prepend (behave->priv->actors, actor); } +/** + * clutter_behaviour_is_applied: + * @behave: a #ClutterBehaviour + * @actor: a #ClutterActor + * + * Check if @behave applied to @actor. + * + * Return value: TRUE if actor has behaviour. FALSE otherwise. + * + * Since: 0.3 + */ +gboolean +clutter_behaviour_is_applied (ClutterBehaviour *behave, + ClutterActor *actor) +{ + g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behave)); + g_return_if_fail (CLUTTER_IS_ACTOR (actor)); + + return (g_slist_find (behave->priv->actors, actor) != NULL); +} + /** * clutter_behaviour_remove: * @behave: a #ClutterBehaviour diff --git a/clutter/clutter-behaviour.h b/clutter/clutter-behaviour.h index 19d16741b..fc9c50ed2 100644 --- a/clutter/clutter-behaviour.h +++ b/clutter/clutter-behaviour.h @@ -113,6 +113,9 @@ ClutterAlpha *clutter_behaviour_get_alpha (ClutterBehaviour *beh void clutter_behaviour_set_alpha (ClutterBehaviour *behave, ClutterAlpha *alpha); +gboolean clutter_behaviour_is_applied (ClutterBehaviour *behave, + ClutterActor *actor); + G_END_DECLS #endif diff --git a/clutter/cogl/Makefile.am b/clutter/cogl/Makefile.am index 938d72ad8..98ef0bc17 100644 --- a/clutter/cogl/Makefile.am +++ b/clutter/cogl/Makefile.am @@ -1,3 +1,5 @@ -SUBDIRS=gl +SUBDIRS = $(CLUTTER_COGL) -EXTRA_DIST=cogl.h \ No newline at end of file +EXTRA_DIST=cogl.h + +DIST_SUBDIRS = gl gles diff --git a/clutter/cogl/cogl.h b/clutter/cogl/cogl.h index 863dc63af..fce18144a 100644 --- a/clutter/cogl/cogl.h +++ b/clutter/cogl/cogl.h @@ -63,6 +63,34 @@ cogl_rotatex (ClutterFixed angle, gint x, gint y, gint z); void cogl_rotate (gint angle, gint x, gint y, gint z); +void +cogl_color (ClutterColor *color); + +#if 0 + +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glColor3f' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glColor4ub' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glGetTexLevelParameteriv' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glSelectBuffer' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glScaled' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glPushName' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glRecti' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glBegin' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glInitNames' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glVertex2i' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glGetTexImage' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glTexCoord2f' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glRenderMode' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glTranslated' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glRotated' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glLoadName' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glTexEnvi' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glVertex2d' +../clutter/.libs/libclutter-egl-0.3.so: undefined reference to `glEnd' + +#endif + G_END_DECLS #endif /* __COGL_H__ */ + diff --git a/clutter/cogl/gles/Makefile.am b/clutter/cogl/gles/Makefile.am new file mode 100644 index 000000000..a4cef4eeb --- /dev/null +++ b/clutter/cogl/gles/Makefile.am @@ -0,0 +1,17 @@ +libclutterincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter +libclutterinclude_HEADERS = $(top_srcdir)/clutter/cogl/cogl.h + +INCLUDES = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/clutter/cogl \ + $(CLUTTER_CFLAGS) \ + $(CLUTTER_DEBUG_CFLAGS) \ + $(GCC_FLAGS) + +LDADD = $(CLUTTER_LIBS) + +noinst_LTLIBRARIES = libclutter-cogl.la + +libclutter_cogl_la_SOURCES = \ + $(top_srcdir)/clutter/cogl/cogl.h \ + cogl.c diff --git a/clutter/cogl/gles/cogl.c b/clutter/cogl/gles/cogl.c new file mode 100644 index 000000000..97b045f36 --- /dev/null +++ b/clutter/cogl/gles/cogl.c @@ -0,0 +1,103 @@ +/* + * Clutter COGL + * + * A basic GL/GLES Abstraction/Utility Layer + * + * Authored By Matthew Allum + * + * Copyright (C) 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. + */ + +#include "cogl.h" +#include + +CoglFuncPtr +cogl_get_proc_address (const gchar* name) +{ + return NULL; +} + +gboolean +cogl_check_extension (const gchar *name, const gchar *ext) +{ + return FALSE; +} + +void +cogl_paint_init (ClutterColor *color) +{ + glClearColorx ((color->red << 16) / 0xff, + (color->green << 16) / 0xff, + (color->blue << 16) / 0xff, + 0xff); + + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glDisable (GL_LIGHTING); + glDisable (GL_DEPTH_TEST); +} + +/* FIXME: inline most of these */ +void +cogl_push_matrix (void) +{ + glPushMatrix(); +} + +void +cogl_pop_matrix (void) +{ + glPopMatrix(); +} + +void +cogl_scaled (ClutterFixed x, ClutterFixed y) +{ + glScalex (x, y, CFX_ONE); +} + +void +cogl_translatex (ClutterFixed x, ClutterFixed y, ClutterFixed z) +{ + glTranslatex (x, y, z); +} + +void +cogl_translate (gint x, gint y, gint z) +{ + glTranslatex (CLUTTER_INT_TO_FIXED(x), + CLUTTER_INT_TO_FIXED(y), + CLUTTER_INT_TO_FIXED(z)); +} + +void +cogl_rotatex (ClutterFixed angle, + ClutterFixed x, + ClutterFixed y, + ClutterFixed z) +{ + glRotatex (angle,x,y,z); +} + +void +cogl_rotate (gint angle, gint x, gint y, gint z) +{ + glRotatef (CLUTTER_INT_TO_FIXED(angle), + CLUTTER_INT_TO_FIXED(x), + CLUTTER_INT_TO_FIXED(y), + CLUTTER_INT_TO_FIXED(z)); +} diff --git a/clutter/egl/clutter-backend-egl.c b/clutter/egl/clutter-backend-egl.c index 4398da0a0..92fbd1497 100644 --- a/clutter/egl/clutter-backend-egl.c +++ b/clutter/egl/clutter-backend-egl.c @@ -4,15 +4,36 @@ #include "clutter-stage-egl.h" #include "../clutter-private.h" #include "../clutter-main.h" +#include "../clutter-debug.h" 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; } @@ -20,6 +41,50 @@ static gboolean clutter_backend_egl_post_parse (ClutterBackend *backend, GError **error) { + ClutterBackendEgl *backend_egl = CLUTTER_BACKEND_EGL (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) + { + CLUTTER_NOTE (MISC, "Getting the X screen"); + + if (clutter_screen == 0) + backend_egl->xscreen = DefaultScreen (backend_egl->xdpy); + else + { + Screen *xscreen; + + xscreen = ScreenOfDisplay (backend_egl->xdpy, clutter_screen); + backend_egl->xscreen = XScreenNumberOfScreen (xscreen); + } + + backend_egl->xwin_root = RootWindow (backend_egl->xdpy, + backend_egl->xscreen); + + backend_egl->display_name = g_strdup (clutter_display_name); + } + + g_free (clutter_display_name); + + CLUTTER_NOTE (MISC, "X Display `%s' [%p] opened (screen:%d, root:%u)", + backend_egl->display_name, + backend_egl->xdpy, + backend_egl->xscreen, + (unsigned int) backend_egl->xwin_root); + return TRUE; } @@ -27,20 +92,68 @@ 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; + + 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_add_options (ClutterBackend *backend, GOptionGroup *group) { - + g_option_group_add_entries (group, entries); } static ClutterActor * @@ -49,11 +162,72 @@ clutter_backend_egl_get_stage (ClutterBackend *backend) return NULL; } +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; + + G_OBJECT_CLASS (clutter_backend_egl_parent_class)->finalize (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) + { + g_object_unref (backend_egl->stage); + backend_egl->stage = NULL; + } + + G_OBJECT_CLASS (clutter_backend_egl_parent_class)->dispose (gobject); +} + +static GObject * +clutter_backend_egl_constructor (GType gtype, + guint n_params, + GObjectConstructParam *params) +{ + GObjectClass *parent_class; + GObject *retval; + + if (!backend_singleton) + { + parent_class = G_OBJECT_CLASS (clutter_backend_egl_parent_class); + retval = parent_class->constructor (gtype, n_params, params); + + backend_singleton = CLUTTER_BACKEND_EGL (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); +} + + static void clutter_backend_egl_class_init (ClutterBackendEglClass *klass) { + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass); + gobject_class->constructor = clutter_backend_egl_constructor; + 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; @@ -73,3 +247,111 @@ _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_egl_trap_x_errors: + * + * FIXME + * + * Since: 0.4 + */ +void +clutter_egl_trap_x_errors (void) +{ + TrappedErrorCode = 0; + old_error_handler = XSetErrorHandler (error_handler); +} + +/** + * clutter_egl_untrap_x_errors: + * + * FIXME + * + * Return value: FIXME + * + * Since: 0.4 + */ +gint +clutter_egl_untrap_x_errors (void) +{ + XSetErrorHandler (old_error_handler); + + return TrappedErrorCode; +} + +/** + * clutter_egl_get_default_display: + * + * FIXME + * + * Return value: FIXME + * + * Since: 0.4 + */ +Display * +clutter_egl_get_default_display (void) +{ + if (!backend_singleton) + { + g_critical ("EGL backend has not been initialised"); + return NULL; + } + + return backend_singleton->xdpy; +} + +/** + * clutter_egl_get_default_screen: + * + * FIXME + * + * Return value: FIXME + * + * Since: 0.4 + */ +gint +clutter_egl_get_default_screen (void) +{ + if (!backend_singleton) + { + g_critical ("EGL backend has not been initialised"); + return -1; + } + + return backend_singleton->xscreen; +} + +/** + * clutter_egl_get_default_root_window: + * + * FIXME + * + * Return value: FIXME + * + * Since: 0.4 + */ +Window +clutter_egl_get_default_root_window (void) +{ + if (!backend_singleton) + { + g_critical ("EGL backend has not been initialised"); + return None; + } + + return backend_singleton->xwin_root; +} + +EGLDisplay +clutter_egl_display (void) +{ + return (EGLDisplay)clutter_egl_get_default_display (); +} diff --git a/clutter/egl/clutter-backend-egl.h b/clutter/egl/clutter-backend-egl.h index e4d501562..f9092ab34 100644 --- a/clutter/egl/clutter-backend-egl.h +++ b/clutter/egl/clutter-backend-egl.h @@ -24,6 +24,8 @@ #include #include +#include +#include G_BEGIN_DECLS @@ -41,6 +43,17 @@ struct _ClutterBackendEgl { ClutterBackend parent_instance; + Display *xdpy; + gchar *display_name; + Window xwin_root; + int xscreen; + + /* main stage singleton */ + ClutterActor *stage; + + /* event source */ + GSource *event_source; + /*< private >*/ }; diff --git a/clutter/egl/clutter-egl.h b/clutter/egl/clutter-egl.h new file mode 100644 index 000000000..784783a02 --- /dev/null +++ b/clutter/egl/clutter-egl.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef __CLUTTER_EGL_H__ +#define __CLUTTER_EGL_H__ + +#include + +#include +#include +#include + +#include +#include + +#include + +G_BEGIN_DECLS + +void clutter_egl_trap_x_errors (void); +gint clutter_egl_untrap_x_errors (void); + +Display *clutter_egl_get_default_display (void); +gint clutter_egl_get_default_screen (void); +Window clutter_egl_get_default_root_window (void); + +Window clutter_egl_get_stage_window (ClutterStage *stage); +XVisualInfo *clutter_egl_get_stage_visual (ClutterStage *stage); + +void clutter_egl_set_stage_foreign (ClutterStage *stage, + Window window); + +EGLDisplay +clutter_egl_display (void); + +G_END_DECLS + +#endif /* __CLUTTER_EGL_H__ */ diff --git a/clutter/egl/clutter-event-egl.c b/clutter/egl/clutter-event-egl.c index e69de29bb..1992c22bd 100644 --- a/clutter/egl/clutter-event-egl.c +++ b/clutter/egl/clutter-event-egl.c @@ -0,0 +1,415 @@ +/* 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. + */ + +#include "config.h" + +#include "clutter-stage-egl.h" +#include "clutter-backend-egl.h" +#include "clutter-egl.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); + } +} + +/** + * clutter_events_pending: + * + * FIXME + * + * Return value: FIXME + * + * Since: 0.4 + */ +gboolean +clutter_events_pending (void) +{ + GList *i; + + for (i = event_sources; i != NULL; i = i->next) + { + ClutterEventSource *source = i->data; + ClutterBackend *backend = source->backend; + + if (_clutter_event_queue_check_pending (backend)) + return TRUE; + } + + for (i = event_sources; i != NULL; i = i->next) + { + ClutterEventSource *source = i->data; + ClutterBackend *backend = source->backend; + + if (clutter_check_xpending (backend)) + return TRUE; + } + + return FALSE; +} + +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_egl_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; + + _clutter_event_button_generate (backend, event); + 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; +} + +void +_clutter_events_queue (ClutterBackend *backend) +{ + ClutterBackendEgl *backend_egl = CLUTTER_BACKEND_EGL (backend); + ClutterEvent *event; + XEvent xevent; + Display *xdisplay = backend_egl->xdpy; + + while (!_clutter_event_queue_check_pending (backend) && XPending (xdisplay)) + { + XNextEvent (xdisplay, &xevent); + + switch (xevent.type) + { + case KeyPress: + case KeyRelease: + break; + default: + if (XFilterEvent (&xevent, None)) + continue; + } + + event = clutter_event_new (CLUTTER_NOTHING); + if (clutter_event_translate (backend, event, &xevent)) + { + _clutter_event_queue_push (backend, event); + } + else + { + clutter_event_free (event); + } + } +} + +static gboolean +clutter_event_prepare (GSource *source, + gint *timeout) +{ + ClutterBackend *backend = ((ClutterEventSource *) source)->backend; + gboolean retval; + + *timeout = -1; + retval = (_clutter_event_queue_check_pending (backend) || + clutter_check_xpending (backend)); + + return retval; +} + +static gboolean +clutter_event_check (GSource *source) +{ + ClutterEventSource *event_source = (ClutterEventSource *) source; + ClutterBackend *backend = event_source->backend; + gboolean retval; + + if (event_source->event_poll_fd.revents & G_IO_IN) + retval = (_clutter_event_queue_check_pending (backend) || + clutter_check_xpending (backend)); + else + retval = FALSE; + + return retval; +} + +static gboolean +clutter_event_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + ClutterBackend *backend = ((ClutterEventSource *) source)->backend; + ClutterEvent *event; + + _clutter_events_queue (backend); + event = _clutter_event_queue_pop (backend); + + if (event) + { + if (_clutter_event_func) + { + CLUTTER_NOTE (EVENT, "Dispatching _clutter_event_func"); + (* _clutter_event_func) (event, _clutter_event_data); + } + + clutter_event_free (event); + } + + return TRUE; +} diff --git a/clutter/egl/clutter-stage-egl.c b/clutter/egl/clutter-stage-egl.c index b6ce84442..f6bb7f395 100644 --- a/clutter/egl/clutter-stage-egl.c +++ b/clutter/egl/clutter-stage-egl.c @@ -1,19 +1,485 @@ #include "config.h" #include "clutter-stage-egl.h" -#include "../clutter-private.h" +#include "clutter-egl.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" + +#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); +} + +static void +clutter_stage_egl_unrealize (ClutterActor *actor) +{ + ClutterStageEgl *stage_egl = CLUTTER_STAGE_EGL (actor); + gboolean was_offscreen; + + CLUTTER_MARK(); + + g_object_get (actor, "offscreen", &was_offscreen, NULL); + + if (G_UNLIKELY (was_offscreen)) + { + /* No support as yet for this */ + } + else + { + if (stage_egl->xwin != None) + { + XDestroyWindow (stage_egl->xdpy, stage_egl->xwin); + stage_egl->xwin = None; + } + else + stage_egl->xwin = None; + } + + if (stage_egl->egl_surface) + eglDestroySurface (clutter_egl_display(), stage_egl->egl_surface); + stage_egl->egl_surface = NULL; + + if (stage_egl->egl_context) + eglDestroyContext (clutter_egl_display(), stage_egl->egl_context); + stage_egl->egl_context = NULL; + + eglMakeCurrent (clutter_egl_display(), + EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + stage_egl->egl_context = None; +} + +static void +clutter_stage_egl_realize (ClutterActor *actor) +{ + ClutterStageEgl *stage_egl = CLUTTER_STAGE_EGL (actor); + + EGLConfig configs[2]; + EGLint config_count; + EGLBoolean status; + + gboolean is_offscreen; + + CLUTTER_NOTE (MISC, "Realizing main stage"); + + g_object_get (actor, "offscreen", &is_offscreen, NULL); + + if (G_LIKELY (!is_offscreen)) + { + EGLint cfg_attribs[] = { EGL_BUFFER_SIZE, EGL_DONT_CARE, + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + EGL_NONE }; + + status = eglGetConfigs (clutter_egl_get_default_display(), + configs, + 2, + &config_count); + + if (status != EGL_TRUE) + g_warning ("eglGetConfigs"); + + status = eglChooseConfig (clutter_egl_get_default_display(), + cfg_attribs, + configs, + sizeof configs / sizeof configs[0], + &config_count); + + if (stage_egl->xwin == None) + stage_egl->xwin = XCreateSimpleWindow(clutter_egl_get_default_display(), + clutter_egl_get_default_root_window(), + 0, 0, + stage_egl->xwin_width, + stage_egl->xwin_height, + 0, 0, + WhitePixel(clutter_egl_get_default_display(), + clutter_egl_get_default_screen())); + XSelectInput(clutter_egl_get_default_display(), + stage_egl->xwin, + StructureNotifyMask + |ExposureMask + /* FIXME: we may want to eplicity enable MotionMask */ + |PointerMotionMask + |KeyPressMask + |KeyReleaseMask + |ButtonPressMask + |ButtonReleaseMask + |PropertyChangeMask); + + if (stage_egl->egl_context) + eglDestroyContext (clutter_egl_display(), stage_egl->egl_context); + + if (stage_egl->egl_surface) + eglDestroySurface (clutter_egl_display(), stage_egl->egl_surface); + + stage_egl->egl_surface + = eglCreateWindowSurface (clutter_egl_display(), + configs[0], + (NativeWindowType)stage_egl->xwin, + NULL); + if (stage_egl->egl_surface == EGL_NO_SURFACE) + g_warning ("eglCreateWindowSurface"); + + stage_egl->egl_context = eglCreateContext (clutter_egl_display(), + configs[0], + EGL_NO_CONTEXT, + NULL); + + if (stage_egl->egl_context == EGL_NO_CONTEXT) + g_warning ("eglCreateContext"); + + status = eglMakeCurrent (clutter_egl_display(), + stage_egl->egl_surface, + EGL_NO_SURFACE, + stage_egl->egl_context); + + if (status != EGL_TRUE) + g_warning ("eglMakeCurrent"); + + } + else + { + /* FIXME */ + } + + _clutter_stage_sync_viewport (CLUTTER_STAGE (stage_egl)); +} + +static void +clutter_stage_egl_paint (ClutterActor *self) +{ + ClutterStageEgl *stage_egl = CLUTTER_STAGE_EGL (self); + ClutterStage *stage = CLUTTER_STAGE (self); + ClutterColor stage_color; + static GTimer *timer = NULL; + static guint timer_n_frames = 0; + + CLUTTER_NOTE (PAINT, " Redraw enter"); + + if (clutter_get_show_fps ()) + { + if (!timer) + timer = g_timer_new (); + } + + clutter_stage_get_color (stage, &stage_color); + + /* FIXME: move below into cogl_paint_start() ? */ + glClearColorx ((stage_color.red << 16) / 0xff, + (stage_color.green << 16) / 0xff, + (stage_color.blue << 16) / 0xff, + 0xff); + + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glDisable (GL_LIGHTING); + glDisable (GL_DEPTH_TEST); + + /* FIXME Check is redundant */ + if (G_LIKELY(CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->paint)) + /* Basically call up to ClutterGroup paint here */ + CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->paint (self); + + /* Why this paint is done in backend as likely GL windowing system + * specific calls, like swapping buffers. + */ + if (stage_egl->xwin) + { + clutter_feature_wait_for_vblank (); + eglSwapBuffers ((EGLDisplay)stage_egl->xdpy, + (EGLSurface)stage_egl->xwin); + } + else + { + eglWaitGL (); + CLUTTER_GLERR (); + } + + if (clutter_get_show_fps ()) + { + timer_n_frames++; + + if (g_timer_elapsed (timer, NULL) >= 1.0) + { + g_print ("*** FPS: %i ***\n", timer_n_frames); + timer_n_frames = 0; + g_timer_start (timer); + } + } + + CLUTTER_NOTE (PAINT, " Redraw leave"); +} + +static void +clutter_stage_egl_allocate_coords (ClutterActor *self, + ClutterActorBox *box) +{ + ClutterStageEgl *stage_egl = CLUTTER_STAGE_EGL (self); + + box->x1 = box->y1 = 0; + box->x2 = box->x1 + stage_egl->xwin_width; + box->y2 = box->y1 + 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 (box->x2 - box->x1); + new_height = ABS (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_stage_sync_viewport (CLUTTER_STAGE (stage_egl)); + } + + if (stage_egl->xwin != None) /* Do we want to bother ? */ + XMoveWindow (stage_egl->xdpy, + stage_egl->xwin, + box->x1, + 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_stage_sync_viewport (stage); +} + +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 */ + } + + _clutter_stage_sync_viewport (stage); +} + +static void +clutter_stage_egl_set_offscreen (ClutterStage *stage, + gboolean offscreen) +{ + +} + +static void +snapshot_pixbuf_free (guchar *pixels, + gpointer data) +{ + g_free (pixels); +} + +static void +clutter_stage_egl_draw_to_pixbuf (ClutterStage *stage, + GdkPixbuf *dest, + gint x, + gint y, + gint width, + gint height) +{ + /* FIXME: implement */ +} + +static void +clutter_stage_egl_dispose (GObject *gobject) +{ + ClutterStageEgl *stage_egl = CLUTTER_STAGE_EGL (gobject); + + if (stage_egl->xwin) + clutter_actor_unrealize (CLUTTER_ACTOR (stage_egl)); + + G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject); +} + static void clutter_stage_egl_class_init (ClutterStageEglClass *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_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->paint = clutter_stage_egl_paint; + actor_class->request_coords = clutter_stage_egl_request_coords; + actor_class->allocate_coords = clutter_stage_egl_allocate_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_egl_get_stage_window: + * @stage: a #ClutterStage + * + * FIXME + * + * Return value: FIXME + * + * Since: 0.4 + */ +Window +clutter_egl_get_stage_window (ClutterStage *stage) +{ + g_return_val_if_fail (CLUTTER_IS_STAGE_EGL (stage), None); + + return CLUTTER_STAGE_EGL (stage)->xwin; +} + +/** + * clutter_egl_get_stage_visual: + * @stage: a #ClutterStage + * + * FIXME + * + * Return value: FIXME + * + * Since: 0.4 + */ +XVisualInfo * +clutter_egl_get_stage_visual (ClutterStage *stage) +{ + g_return_val_if_fail (CLUTTER_IS_STAGE_EGL (stage), NULL); + + return CLUTTER_STAGE_EGL (stage)->xvisinfo; +} + +void +clutter_egl_set_stage_foreign (ClutterStage *stage, + Window window) +{ + g_return_if_fail (CLUTTER_IS_STAGE_EGL (stage)); + + /* FIXME */ +} + diff --git a/clutter/egl/clutter-stage-egl.h b/clutter/egl/clutter-stage-egl.h index 19c29aa28..88530d7f0 100644 --- a/clutter/egl/clutter-stage-egl.h +++ b/clutter/egl/clutter-stage-egl.h @@ -1,8 +1,17 @@ #ifndef __CLUTTER_STAGE_EGL_H__ #define __CLUTTER_STAGE_EGL_H__ +#include #include +#include +#include +#include + +#include +#include + + #define CLUTTER_TYPE_STAGE_EGL (clutter_stage_egl_get_type ()) #define CLUTTER_STAGE_EGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_EGL, ClutterStageEgl)) #define CLUTTER_IS_STAGE_EGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_EGL)) @@ -16,6 +25,18 @@ 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; + + EGLSurface egl_surface; + EGLContext egl_context; }; struct _ClutterStageEglClass diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index a284941bb..9cf2e3247 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -36,7 +36,9 @@ #include "../clutter-private.h" #include "../clutter-debug.h" +#ifdef HAVE_XFIXES #include +#endif #include #include diff --git a/configure.ac b/configure.ac index 7e66b7c85..b22008815 100644 --- a/configure.ac +++ b/configure.ac @@ -92,18 +92,6 @@ if $PKG_CONFIG --exists xfixes ; then X11_LIBS="$X11_LIBS -lXfixes" fi -AC_CHECK_HEADERS([GL/gl.h GL/glx.h],, - [AC_MSG_ERROR([Unable to locate required GL headers])]) - -AC_CHECK_LIB(GL, glXCreateContext, HAVE_LIBGL=yes, HAVE_LIBGL=no) - -if test "x$HAVE_LIBGL" = "xno"; then - AC_MSG_ERROR(libGL not found); -else - GLX_LIBS="$X11_LIBS -lGL" -fi - -GLX_CFLAGS="$X11_CFLAGS" clutterbackend=glx AC_ARG_WITH([flavour], @@ -112,19 +100,46 @@ AC_ARG_WITH([flavour], clutterbackend=$with_flavour) AC_SUBST([clutterbackend]) + case $clutterbackend in + glx) + CLUTTER_FLAVOUR="glx" CLUTTER_GOGL="gl" AC_DEFINE([HAVE_CLUTTER_GLX], 1, [Have the GLX backend]) + + AC_CHECK_HEADERS([GL/gl.h GL/glx.h],, + [AC_MSG_ERROR([Unable to locate required GL headers])]) + + AC_CHECK_LIB(GL, glXCreateContext, HAVE_LIBGL=yes, HAVE_LIBGL=no) + + if test "x$HAVE_LIBGL" = "xno"; then + AC_MSG_ERROR([GLX not found and GLX backend requested]); + fi + + GLX_LIBS="$X11_LIBS -lGL" + GLX_CFLAGS="$X11_CFLAGS" ;; + egl) + CLUTTER_FLAVOUR="egl" CLUTTER_GOGL="gles" AC_DEFINE([HAVE_CLUTTER_EGL], 1, [Have the EGL backend]) + + PKG_CHECK_MODULES(EGL, libvincent, HAVE_OGLES=yes, HAVE_OGLES=no) + if test "x$HAVE_OGLES" = "xno"; then + AC_MSG_ERROR([libvincent (ogles) not found and egl backend requested.]); + fi + + EGL_LIBS="$EGL_LIBS $X11_LIBS" + EGL_CFLAGS="$EGL_CFLAGS $X11_CFLAGS" ;; + *) AC_MSG_ERROR([Invalid backend for Clutter: use glx or egl]) ;; + esac AC_SUBST(CLUTTER_FLAVOUR) @@ -186,8 +201,8 @@ dnl ======================================================================== AC_SUBST(GCC_FLAGS) -CLUTTER_CFLAGS="$GLX_CLAGS $CLUTTER_DEPS_CFLAGS $CLUTTER_FIXED_CFLAGS" -CLUTTER_LIBS="$GLX_LIBS $CLUTTER_DEPS_LIBS" +CLUTTER_CFLAGS="$EGL_CFLAGS $GLX_CFLAGS $CLUTTER_DEPS_CFLAGS $CLUTTER_FIXED_CFLAGS" +CLUTTER_LIBS="$EGL_LIBS $GLX_LIBS $CLUTTER_DEPS_LIBS" AC_SUBST(CLUTTER_CFLAGS) AC_SUBST(CLUTTER_LIBS) @@ -201,6 +216,7 @@ AC_CONFIG_FILES([ clutter/egl/Makefile clutter/cogl/Makefile clutter/cogl/gl/Makefile + clutter/cogl/gles/Makefile examples/Makefile doc/Makefile doc/reference/Makefile