+2007-10-26 Matthew Allum <mallum@openedhand.com>
+
+ * clutter/clutter-texture.c:
+ * clutter/cogl/cogl.h:
+ * clutter/cogl/gl/cogl-defines.h:
+ * clutter/cogl/gles/cogl-defines.h:
+ * clutter/cogl/gl/cogl.c:
+ * clutter/cogl/gles/cogl.c:
+ Switch from use of guint to COGLuint. Avoids problems when
+ guint != GLuint on some platforms, i.e OSX.
+ (Tommi Komulainen, #526)
+
+ * clutter/Makefile.am:
+ * clutter/osx/Makefile.am:
+ * clutter/osx/clutter-backend-osx.c:
+ * clutter/osx/clutter-backend-osx.h:
+ * clutter/osx/clutter-event-osx.c:
+ * clutter/osx/clutter-osx.h:
+ * clutter/osx/clutter-stage-osx.c:
+ * clutter/osx/clutter-stage-osx.h:
+ * configure.ac:
+ Add initial Cocoa/OSX Backend (by Tommi Komulainen, see #526)
+
2007-10-26 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-entry.c: Add a :x-align property for aligning
SUBDIRS = cogl pango json $(clutterbackend)
-DIST_SUBDIRS = pango glx eglx eglnative cogl sdl json
+DIST_SUBDIRS = pango glx eglx eglnative cogl sdl json osx
target = $(clutterbackend)
ClutterTextureTileDimension *y_tiles;
gint n_x_tiles;
gint n_y_tiles;
- guint *tiles;
+ COGLuint *tiles;
};
enum
/* Single Texture */
if (!priv->tiles)
{
- priv->tiles = g_new (guint, 1);
+ priv->tiles = g_new (COGLuint, 1);
glGenTextures (1, priv->tiles);
create_textures = TRUE;
}
if (priv->tiles == NULL)
{
- priv->tiles = g_new (guint, priv->n_x_tiles * priv->n_y_tiles);
+ priv->tiles = g_new (COGLuint, priv->n_x_tiles * priv->n_y_tiles);
glGenTextures (priv->n_x_tiles * priv->n_y_tiles, priv->tiles);
create_textures = TRUE;
}
if (!priv->tiles)
{
- priv->tiles = g_new (guint, 1);
+ priv->tiles = g_new (COGLuint, 1);
glGenTextures (1, priv->tiles);
}
#define __COGL_H__
#include <glib.h>
-#include <clutter/clutter-color.h>
-#include <clutter/clutter-feature.h>
-#include <clutter/clutter-fixed.h>
-#include <clutter/clutter-types.h>
+#include <clutter/clutter.h>
#include "cogl-defines.h"
ClutterFixed ty2);
void
-cogl_textures_create (guint num, guint *textures);
+cogl_textures_create (guint num, COGLuint *textures);
void
-cogl_textures_destroy (guint num, const guint *textures);
+cogl_textures_destroy (guint num, const COGLuint *textures);
void
-cogl_texture_bind (COGLenum target, guint texture);
+cogl_texture_bind (COGLenum target, COGLuint texture);
void
cogl_texture_set_alignment (COGLenum target,
#define __COGL_DEFINES_H__
#ifdef WIN32
+
#include <windows.h>
#include <GL/Glee.h>
+
#else
+
+#if defined(HAVE_GL_GL_H)
#include <GL/gl.h>
+#elif defined(HAVE_OPENGL_GL_H)
+#include <OpenGL/gl.h>
#endif
+#endif /* WIN32 */
+
G_BEGIN_DECLS
typedef GLenum COGLenum;
typedef GLint COGLint;
+typedef GLuint COGLuint;
/* FIXME + DOCUMENT */
#include "cogl.h"
-#ifdef WIN32
-#include <windows.h>
-#include <GL/Glee.h>
-#else
-#include <GL/gl.h>
-#endif
#include <string.h>
#ifdef HAVE_CLUTTER_GLX
#ifdef GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB
if (target == CGL_TEXTURE_RECTANGLE_ARB)
{
- gint max_size = 0;
+ GLint max_size = 0;
GE( glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &max_size) );
}
void
-cogl_textures_create (guint num, guint *textures)
+cogl_textures_create (guint num, COGLuint *textures)
{
GE( glGenTextures (num, textures) );
}
void
-cogl_textures_destroy (guint num, const guint *textures)
+cogl_textures_destroy (guint num, const COGLuint *textures)
{
GE( glDeleteTextures (num, textures) );
}
void
-cogl_texture_bind (COGLenum target, guint texture)
+cogl_texture_bind (COGLenum target, COGLuint texture)
{
GE( glBindTexture (target, texture) );
}
void
cogl_get_bitmasks (gint *red, gint *green, gint *blue, gint *alpha)
{
+ GLint value;
if (red)
- GE( glGetIntegerv(GL_RED_BITS, red) );
+ {
+ GE( glGetIntegerv(GL_RED_BITS, &value) );
+ *red = value;
+ }
if (green)
- GE( glGetIntegerv(GL_GREEN_BITS, green) );
+ {
+ GE( glGetIntegerv(GL_GREEN_BITS, &value) );
+ *green = value;
+ }
if (blue)
- GE( glGetIntegerv(GL_BLUE_BITS, blue) );
+ {
+ GE( glGetIntegerv(GL_BLUE_BITS, &value) );
+ *blue = value;
+ }
if (alpha)
- GE( glGetIntegerv(GL_ALPHA_BITS, alpha ) );
+ {
+ GE( glGetIntegerv(GL_ALPHA_BITS, &value ) );
+ *alpha = value;
+ }
}
typedef GLenum COGLenum;
typedef GLint COGLint;
+typedef GLuint COGLuint;
/* extras */
}
void
-cogl_textures_create (guint num, guint *textures)
+cogl_textures_create (guint num, COGLuint *textures)
{
GE( glGenTextures (num, textures) );
}
void
-cogl_textures_destroy (guint num, const guint *textures)
+cogl_textures_destroy (guint num, const COGLuint *textures)
{
GE( glDeleteTextures (num, textures) );
}
void
-cogl_texture_bind (COGLenum target, guint texture)
+cogl_texture_bind (COGLenum target, COGLuint texture)
{
GE( glBindTexture (target, texture) );
}
--- /dev/null
+libclutterincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter
+libclutterinclude_HEADERS = clutter-osx.h
+
+INCLUDES = \
+ -DG_LOG_DOMAIN=\"ClutterOSX\" \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/clutter/cogl \
+ -I$(top_srcdir)/clutter/cogl/@CLUTTER_COGL@ \
+ $(CLUTTER_CFLAGS) \
+ $(CLUTTER_DEBUG_CFLAGS) \
+ $(GCC_FLAGS) \
+ -xobjective-c
+
+LDADD = $(CLUTTER_LIBS)
+
+noinst_LTLIBRARIES = libclutter-osx.la
+
+libclutter_osx_la_SOURCES = \
+ clutter-backend-osx.h \
+ clutter-backend-osx.c \
+ clutter-event-osx.c \
+ clutter-stage-osx.h \
+ clutter-stage-osx.c \
+ clutter-osx.h
--- /dev/null
+/* Clutter - An OpenGL based 'interactive canvas' library.
+ * OSX backend - initial entry point
+ *
+ * Copyright (C) 2007 Tommi Komulainen <tommi.komulainen@iki.fi>
+ * Copyright (C) 2007 OpenedHand Ltd.
+ *
+ * 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-osx.h"
+#include "clutter-backend-osx.h"
+#include "clutter-stage-osx.h"
+
+#include <clutter/clutter-debug.h>
+#import <AppKit/AppKit.h>
+
+G_DEFINE_TYPE (ClutterBackendOSX, clutter_backend_osx, CLUTTER_TYPE_BACKEND)
+
+/*************************************************************************/
+static gboolean
+clutter_backend_osx_post_parse (ClutterBackend *backend,
+ GError **error)
+{
+ CLUTTER_NOTE (BACKEND, "post_parse");
+
+ CLUTTER_OSX_POOL_ALLOC();
+
+ /* Bring our app to foreground, background apps don't appear in dock or
+ * accept keyboard focus.
+ */
+ const ProcessSerialNumber psn = { 0, kCurrentProcess };
+ TransformProcessType (&psn, kProcessTransformToForegroundApplication);
+
+ /* Also raise our app to front, otherwise our window will remain under the
+ * terminal.
+ */
+ SetFrontProcess (&psn);
+
+ [NSApplication sharedApplication];
+
+ /* Initialize(?) OpenGL -- without this glGetString crashes
+ *
+ * Program received signal EXC_BAD_ACCESS, Could not access memory.
+ * Reason: KERN_PROTECTION_FAILURE at address: 0x00000ac0
+ * 0x92b22b2f in glGetString ()
+ */
+ [NSOpenGLView defaultPixelFormat];
+
+ CLUTTER_OSX_POOL_RELEASE();
+
+ return TRUE;
+}
+
+static ClutterFeatureFlags
+clutter_backend_osx_get_features (ClutterBackend *backend)
+{
+ return CLUTTER_FEATURE_STAGE_USER_RESIZE;
+}
+
+static gboolean
+clutter_backend_osx_init_stage (ClutterBackend *backend,
+ GError **error)
+{
+ ClutterBackendOSX *self = CLUTTER_BACKEND_OSX (backend);
+ ClutterActor *stage;
+
+ CLUTTER_NOTE (BACKEND, "init_stage");
+
+ CLUTTER_OSX_POOL_ALLOC();
+
+ g_assert (self->stage == NULL);
+
+ /* Allocate ourselves a GL context. We need one this early for clutter to
+ * manage textures.
+ */
+ NSOpenGLPixelFormatAttribute attrs[] = {
+ NSOpenGLPFADoubleBuffer,
+ 0
+ };
+ self->pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
+ self->context = [[NSOpenGLContext alloc]
+ initWithFormat: self->pixel_format
+ shareContext: nil];
+ [self->context makeCurrentContext];
+
+ stage = clutter_stage_osx_new (backend);
+ self->stage = g_object_ref_sink (stage);
+
+ CLUTTER_OSX_POOL_RELEASE();
+
+ return TRUE;
+}
+
+static void
+clutter_backend_osx_init_events (ClutterBackend *backend)
+{
+ CLUTTER_NOTE (BACKEND, "init_events");
+
+ _clutter_events_osx_init ();
+}
+
+static ClutterActor *
+clutter_backend_osx_get_stage (ClutterBackend *backend)
+{
+ ClutterBackendOSX *self = CLUTTER_BACKEND_OSX (backend);
+
+ return self->stage;
+}
+
+static void
+clutter_backend_osx_redraw (ClutterBackend *backend)
+{
+ ClutterBackendOSX *self = CLUTTER_BACKEND_OSX (backend);
+ ClutterStageOSX *stage_osx;
+
+ stage_osx = CLUTTER_STAGE_OSX (self->stage);
+ [stage_osx->view setNeedsDisplay: YES];
+}
+
+/*************************************************************************/
+
+static void
+clutter_backend_osx_init (ClutterBackendOSX *self)
+{
+}
+
+static void
+clutter_backend_osx_dispose (GObject *object)
+{
+ ClutterBackendOSX *self = CLUTTER_BACKEND_OSX (object);
+
+ if (self->stage)
+ {
+ clutter_actor_destroy (self->stage);
+ self->stage = NULL;
+ }
+
+ [self->context release];
+ self->context = NULL;
+
+ [self->pixel_format release];
+ self->pixel_format = NULL;
+
+
+ G_OBJECT_CLASS (clutter_backend_osx_parent_class)->dispose (object);
+}
+
+static void
+clutter_backend_osx_class_init (ClutterBackendOSXClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
+
+ object_class->dispose = clutter_backend_osx_dispose;
+
+ backend_class->post_parse = clutter_backend_osx_post_parse;
+ backend_class->get_features = clutter_backend_osx_get_features;
+ backend_class->init_stage = clutter_backend_osx_init_stage;
+ backend_class->init_events = clutter_backend_osx_init_events;
+ backend_class->get_stage = clutter_backend_osx_get_stage;
+ backend_class->redraw = clutter_backend_osx_redraw;
+}
+
+GType
+_clutter_backend_impl_get_type (void)
+{
+ return clutter_backend_osx_get_type ();
+}
--- /dev/null
+/* Clutter - An OpenGL based 'interactive canvas' library.
+ * OSX backend - initial entry point
+ *
+ * Copyright (C) 2007 Tommi Komulainen <tommi.komulainen@iki.fi>
+ * Copyright (C) 2007 OpenedHand Ltd.
+ *
+ * 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_OSX_H__
+#define __CLUTTER_BACKEND_OSX_H__
+
+#include <clutter/clutter-backend.h>
+
+@class NSOpenGLPixelFormat, NSOpenGLContext;
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_BACKEND_OSX (clutter_backend_osx_get_type())
+#define CLUTTER_BACKEND_OSX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),CLUTTER_TYPE_BACKEND_OSX,ClutterBackendOSX))
+#define CLUTTER_BACKEND_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),CLUTTER_TYPE_BACKEND_OSX,ClutterBackend))
+#define CLUTTER_IS_BACKEND_OSX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),CLUTTER_TYPE_BACKEND_OSX))
+#define CLUTTER_IS_BACKEND_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),CLUTTER_TYPE_BACKEND_OSX))
+#define CLUTTER_BACKEND_OSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),CLUTTER_TYPE_BACKEND_OSX,ClutterBackendOSXClass))
+
+typedef struct _ClutterBackendOSX ClutterBackendOSX;
+typedef struct _ClutterBackendOSXClass ClutterBackendOSXClass;
+
+struct _ClutterBackendOSX
+{
+ ClutterBackend parent;
+
+ NSOpenGLPixelFormat *pixel_format;
+ NSOpenGLContext *context;
+
+ ClutterActor *stage;
+};
+
+struct _ClutterBackendOSXClass
+{
+ ClutterBackendClass parent_class;
+};
+
+GType clutter_backend_osx_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __CLUTTER_BACKEND_OSX_H__ */
--- /dev/null
+/* Clutter - An OpenGL based 'interactive canvas' library.
+ * OSX backend - event loops integration
+ *
+ * Copyright (C) 2007 Tommi Komulainen <tommi.komulainen@iki.fi>
+ * Copyright (C) 2007 OpenedHand Ltd.
+ *
+ * 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-osx.h"
+
+#import <AppKit/AppKit.h>
+#include <glib/gmain.h>
+#include <clutter/clutter-debug.h>
+#include <clutter/clutter-private.h>
+#include <clutter/clutter-keysyms.h>
+
+/* Overriding the poll function because the events are not delivered over file
+ * descriptors and setting up a GSource would just introduce polling.
+ */
+
+static GPollFunc old_poll_func = NULL;
+
+/*************************************************************************/
+@interface NSEvent (Clutter)
+- (gint)clutterTime;
+- (gint)clutterButton;
+- (void)clutterX:(gint*)ptrX y:(gint*)ptrY;
+- (gint)clutterModifierState;
+- (guint)clutterKeyVal;
+@end
+
+@implementation NSEvent (Clutter)
+- (gint)clutterTime
+{
+ return [self timestamp] * 1000;
+}
+
+- (gint)clutterButton
+{
+ switch ([self buttonNumber])
+ {
+ case 0: return 1; /* left */
+ case 1: return 3; /* right */
+ case 2: return 2; /* middle */
+ default: return 1 + [self buttonNumber];
+ }
+}
+
+- (void)clutterX:(gint*)ptrX y:(gint*)ptrY
+{
+ NSView *view = [[self window] contentView];
+ NSPoint pt = [view convertPoint:[self locationInWindow] fromView:nil];
+
+ *ptrX = (gint)pt.x;
+ *ptrY = (gint)pt.y;
+}
+
+- (gint)clutterModifierState
+{
+ guint mods = [self modifierFlags];
+ gint rv = 0;
+
+ if (mods & NSAlphaShiftKeyMask)
+ rv |= CLUTTER_LOCK_MASK;
+ if (mods & NSShiftKeyMask)
+ rv |= CLUTTER_SHIFT_MASK;
+ if (mods & NSControlKeyMask)
+ rv |= CLUTTER_CONTROL_MASK;
+ if (mods & NSAlternateKeyMask)
+ rv |= CLUTTER_MOD1_MASK;
+ if (mods & NSCommandKeyMask)
+ rv |= CLUTTER_MOD2_MASK;
+
+ return rv;
+}
+
+- (guint)clutterKeyVal
+{
+ /* FIXME: doing this right is a lot of work, see gdkkeys-quartz.c in gtk+
+ * For now handle some common/simple keys only. Might not work with other
+ * hardware than mine (MacBook Pro, finnish layout). Sorry.
+ */
+ unichar c = [[self characters] characterAtIndex:0];
+
+ /* Latin-1 characters, 1:1 mapping - this ought to be reliable */
+ if ((c >= 0x0020 && c <= 0x007e) ||
+ (c >= 0x00a0 && c <= 0x00ff))
+ return c;
+
+ switch (c)
+ {
+ /* these should be fairly standard */
+ /* (maybe add 0x0008 (Ctrl+H) for backspace too) */
+ case 0x000d: return CLUTTER_Return;
+ case 0x001b: return CLUTTER_Escape;
+ case 0x007f: return CLUTTER_BackSpace;
+ /* Defined in NSEvent.h */
+ case NSUpArrowFunctionKey: return CLUTTER_Up;
+ case NSDownArrowFunctionKey: return CLUTTER_Down;
+ case NSLeftArrowFunctionKey: return CLUTTER_Left;
+ case NSRightArrowFunctionKey: return CLUTTER_Right;
+ case NSF1FunctionKey: return CLUTTER_F1;
+ case NSF2FunctionKey: return CLUTTER_F2;
+ case NSF3FunctionKey: return CLUTTER_F3;
+ case NSF4FunctionKey: return CLUTTER_F4;
+ case NSF5FunctionKey: return CLUTTER_F5;
+ case NSF6FunctionKey: return CLUTTER_F6;
+ case NSF7FunctionKey: return CLUTTER_F7;
+ case NSF8FunctionKey: return CLUTTER_F8;
+ case NSF9FunctionKey: return CLUTTER_F9;
+ case NSF10FunctionKey: return CLUTTER_F10;
+ case NSF11FunctionKey: return CLUTTER_F11;
+ case NSF12FunctionKey: return CLUTTER_F12;
+ case NSInsertFunctionKey: return CLUTTER_Insert;
+ case NSDeleteFunctionKey: return CLUTTER_Delete;
+ case NSHomeFunctionKey: return CLUTTER_Home;
+ case NSEndFunctionKey: return CLUTTER_End;
+ case NSPageUpFunctionKey: return CLUTTER_Page_Up;
+ case NSPageDownFunctionKey: return CLUTTER_Page_Down;
+ }
+
+ CLUTTER_NOTE (BACKEND, "unhandled unicode key 0x%x (%d)", c, c);
+
+ /* hardware dependent, worksforme(tm) Redundant due to above, left around as
+ * example.
+ */
+ switch ([self keyCode])
+ {
+ case 115: return CLUTTER_Home;
+ case 116: return CLUTTER_Page_Up;
+ case 117: return CLUTTER_Delete;
+ case 119: return CLUTTER_End;
+ case 121: return CLUTTER_Page_Down;
+ case 123: return CLUTTER_Left;
+ case 124: return CLUTTER_Right;
+ case 125: return CLUTTER_Down;
+ case 126: return CLUTTER_Up;
+ }
+
+ return 0;
+}
+@end
+
+/*************************************************************************/
+static gboolean
+clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event)
+{
+ event->any.time = [nsevent clutterTime];
+
+ switch ([nsevent type])
+ {
+ case NSLeftMouseDown:
+ case NSRightMouseDown:
+ case NSOtherMouseDown:
+ event->type = CLUTTER_BUTTON_PRESS;
+ /* fall through */
+ case NSLeftMouseUp:
+ case NSRightMouseUp:
+ case NSOtherMouseUp:
+ if (event->type != CLUTTER_BUTTON_PRESS)
+ event->type = CLUTTER_BUTTON_RELEASE;
+
+ event->button.button = [nsevent clutterButton];
+ event->button.click_count = [nsevent clickCount];
+ event->motion.modifier_state = [nsevent clutterModifierState];
+ [nsevent clutterX:&(event->button.x) y:&(event->button.y)];
+
+ CLUTTER_NOTE (EVENT, "button %d %s at %d,%d clicks=%d",
+ [nsevent buttonNumber],
+ event->type == CLUTTER_BUTTON_PRESS ? "press" : "release",
+ event->button.x, event->button.y,
+ event->button.click_count);
+ return TRUE;
+
+ case NSMouseMoved:
+ case NSLeftMouseDragged:
+ case NSRightMouseDragged:
+ case NSOtherMouseDragged:
+ event->type = CLUTTER_MOTION;
+
+ [nsevent clutterX:(&event->motion.x) y:&(event->motion.y)];
+ event->motion.modifier_state = [nsevent clutterModifierState];
+
+ CLUTTER_NOTE (EVENT, "motion %d at %d,%d",
+ [nsevent buttonNumber],
+ event->button.x, event->button.y);
+ return TRUE;
+
+ case NSKeyDown:
+ event->type = CLUTTER_KEY_PRESS;
+ /* fall through */
+ case NSKeyUp:
+ if (event->type != CLUTTER_KEY_PRESS)
+ event->type = CLUTTER_KEY_RELEASE;
+
+ event->key.hardware_keycode = [nsevent keyCode];
+ event->key.modifier_state = [nsevent clutterModifierState];
+ event->key.keyval = [nsevent clutterKeyVal];
+
+ CLUTTER_NOTE (EVENT, "key %d (%s) (%s) %s, keyval %d",
+ [nsevent keyCode],
+ [[nsevent characters] UTF8String],
+ [[nsevent charactersIgnoringModifiers] UTF8String],
+ event->type == CLUTTER_KEY_PRESS ? "press" : "release",
+ event->key.keyval);
+ return TRUE;
+
+ default:
+ CLUTTER_NOTE (EVENT, "unhandled event %d", [nsevent type]);
+ break;
+ }
+
+ return FALSE;
+}
+
+void
+_clutter_event_osx_put (NSEvent *nsevent)
+{
+ ClutterEvent event;
+ event.type = CLUTTER_NOTHING;
+
+ if (clutter_event_osx_translate (nsevent, &event))
+ {
+ g_assert (event.type != CLUTTER_NOTHING);
+ clutter_event_put (&event);
+ }
+}
+
+typedef struct {
+ CFSocketRef sock;
+ CFRunLoopSourceRef source;
+
+ gushort revents;
+} SocketInfo;
+
+static void
+socket_activity_cb (CFSocketRef sock,
+ CFSocketCallBackType cbtype,
+ CFDataRef address,
+ const void *data,
+ void *info)
+{
+ SocketInfo *si = info;
+
+ if (cbtype & kCFSocketReadCallBack)
+ si->revents |= G_IO_IN;
+ if (cbtype & kCFSocketWriteCallBack)
+ si->revents |= G_IO_OUT;
+}
+
+static gint
+clutter_event_osx_poll_func (GPollFD *ufds, guint nfds, gint timeout)
+{
+ NSDate *until_date;
+ NSEvent *nsevent;
+ SocketInfo *sockets = NULL;
+ gint n_active = 0;
+
+ CLUTTER_OSX_POOL_ALLOC();
+
+ if (timeout == -1)
+ until_date = [NSDate distantFuture];
+ else if (timeout == 0)
+ until_date = [NSDate distantPast];
+ else
+ until_date = [NSDate dateWithTimeIntervalSinceNow:timeout/1000.0];
+
+ /* File descriptors appear to be similar enough to sockets so that they can
+ * be used in CFRunLoopSource.
+ *
+ * We could also launch a thread to call old_poll_func and signal the main
+ * thread. No idea which way is better.
+ */
+ if (nfds > 0)
+ {
+ CFRunLoopRef run_loop;
+
+ run_loop = [[NSRunLoop currentRunLoop] getCFRunLoop];
+ sockets = g_new (SocketInfo, nfds);
+
+ int i;
+ for (i = 0; i < nfds; i++)
+ {
+ SocketInfo *si = &sockets[i];
+ CFSocketCallBackType cbtype;
+
+ cbtype = 0;
+ if (ufds[i].events & G_IO_IN)
+ cbtype |= kCFSocketReadCallBack;
+ if (ufds[i].events & G_IO_OUT)
+ cbtype |= kCFSocketWriteCallBack;
+ /* FIXME: how to handle G_IO_HUP and G_IO_ERR? */
+
+ const CFSocketContext ctxt = {
+ 0, si, NULL, NULL, NULL
+ };
+ si->sock = CFSocketCreateWithNative (NULL, ufds[i].fd, cbtype, socket_activity_cb, &ctxt);
+ si->source = CFSocketCreateRunLoopSource (NULL, si->sock, 0);
+ si->revents = 0;
+
+ CFRunLoopAddSource (run_loop, si->source, kCFRunLoopCommonModes);
+ }
+ }
+
+ nsevent = [NSApp nextEventMatchingMask: NSAnyEventMask
+ untilDate: until_date
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES];
+
+ /* Push the events to NSApplication which will do some magic(?) and forward
+ * interesting events to our view. While we could do event translation here
+ * we'd also need to filter out clicks on titlebar, and perhaps do special
+ * handling for the first click (couldn't figure it out - always ended up
+ * missing a screen refresh) and maybe other things.
+ */
+ [NSApp sendEvent:nsevent];
+
+ if (nfds > 0)
+ {
+ int i;
+ for (i = 0; i < nfds; i++)
+ {
+ SocketInfo *si = &sockets[i];
+
+ if ((ufds[i].revents = si->revents) != 0)
+ n_active++;
+
+ /* Invalidating the source also removes it from run loop and
+ * guarantees the callback is never called again.
+ * CFRunLoopRemoveSource removes the source from the loop, but might
+ * still call the callback which would be badly timed.
+ */
+ CFRunLoopSourceInvalidate (si->source);
+ CFRelease (si->source);
+ CFRelease (si->sock);
+ }
+
+ g_free (sockets);
+ }
+
+ /* FIXME this could result in infinite loop */
+ ClutterEvent *event = clutter_event_get ();
+ while (event)
+ {
+ clutter_do_event (event);
+ clutter_event_free (event);
+ event = clutter_event_get ();
+ }
+
+ CLUTTER_OSX_POOL_RELEASE();
+
+ return n_active;
+}
+
+void
+_clutter_events_osx_init (void)
+{
+ g_assert (old_poll_func == NULL);
+
+ old_poll_func = g_main_context_get_poll_func (NULL);
+ g_main_context_set_poll_func (NULL, clutter_event_osx_poll_func);
+}
+
+void
+_clutter_events_osx_uninit (void)
+{
+ if (old_poll_func)
+ {
+ g_main_context_set_poll_func (NULL, old_poll_func);
+ old_poll_func = NULL;
+ }
+}
--- /dev/null
+/* Clutter - An OpenGL based 'interactive canvas' library.
+ * OSX backend
+ *
+ * Copyright (C) 2007 Tommi Komulainen <tommi.komulainen@iki.fi>
+ * Copyright (C) 2007 OpenedHand Ltd.
+ *
+ * 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_OSX_H__
+#define __CLUTTER_OSX_H__
+
+#include <clutter/clutter-stage.h>
+
+@class NSEvent;
+
+G_BEGIN_DECLS
+
+#define CLUTTER_OSX_POOL_ALLOC() NSAutoreleasePool *autorelease_pool = [[NSAutoreleasePool alloc] init]
+#define CLUTTER_OSX_POOL_RELEASE() [autorelease_pool release];
+
+void _clutter_events_osx_init (void);
+void _clutter_events_osx_uninit (void);
+
+void _clutter_event_osx_put (NSEvent *nsevent);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_OSX_H__ */
--- /dev/null
+/* Clutter - An OpenGL based 'interactive canvas' library.
+ * OSX backend - integration with NSWindow and NSView
+ *
+ * Copyright (C) 2007 Tommi Komulainen <tommi.komulainen@iki.fi>
+ * Copyright (C) 2007 OpenedHand Ltd.
+ *
+ * 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-osx.h"
+#include "clutter-stage-osx.h"
+#include "clutter-backend-osx.h"
+#import <AppKit/AppKit.h>
+
+#include <clutter/clutter-debug.h>
+#include <clutter/clutter-private.h>
+
+G_DEFINE_TYPE (ClutterStageOSX, clutter_stage_osx, CLUTTER_TYPE_STAGE)
+
+/* FIXME: this should be in clutter-stage.c */
+static void
+clutter_stage_osx_state_update (ClutterStageOSX *self,
+ ClutterStageState unset_flags,
+ ClutterStageState set_flags);
+
+#define CLUTTER_OSX_FULLSCREEN_WINDOW_LEVEL (NSMainMenuWindowLevel + 1)
+
+/*************************************************************************/
+@interface ClutterGLWindow : NSWindow
+{
+ ClutterStageOSX *stage;
+}
+@end
+
+@implementation ClutterGLWindow
+- (id)initWithView:(NSView *)aView UTF8Title:(const char *)aTitle stage:(ClutterStageOSX *)aStage
+{
+ if ((self = [super initWithContentRect: [aView frame]
+ styleMask: NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask
+ backing: NSBackingStoreBuffered
+ defer: NO]) != nil)
+ {
+ [self setDelegate: self];
+ [self useOptimizedDrawing: YES];
+ [self setContentView: aView];
+ [self setTitle:[NSString stringWithUTF8String: aTitle]];
+ stage = aStage;
+ }
+ return self;
+}
+
+- (BOOL) windowShouldClose: (id) sender
+{
+ CLUTTER_NOTE (BACKEND, "windowShouldClose");
+
+ ClutterEvent event;
+ event.type = CLUTTER_DELETE;
+ clutter_event_put (&event);
+
+ return NO;
+}
+
+- (NSRect) constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen*)aScreen
+{
+ /* in fullscreen mode we don't want to be constrained by menubar or dock
+ * FIXME: calculate proper constraints depending on fullscreen mode
+ */
+
+ return frameRect;
+}
+
+- (void) windowDidBecomeKey:(NSNotification*)aNotification
+{
+ CLUTTER_NOTE (BACKEND, "windowDidBecomeKey");
+
+ if (stage->stage_state & CLUTTER_STAGE_STATE_FULLSCREEN)
+ [self setLevel: CLUTTER_OSX_FULLSCREEN_WINDOW_LEVEL];
+
+ clutter_stage_osx_state_update (stage, 0, CLUTTER_STAGE_STATE_ACTIVATED);
+}
+
+- (void) windowDidResignKey:(NSNotification*)aNotification
+{
+ CLUTTER_NOTE (BACKEND, "windowDidResignKey");
+
+ if (stage->stage_state & CLUTTER_STAGE_STATE_FULLSCREEN)
+ {
+ [self setLevel: NSNormalWindowLevel];
+ [self orderBack: nil];
+ }
+
+ clutter_stage_osx_state_update (stage, CLUTTER_STAGE_STATE_ACTIVATED, 0);
+}
+@end
+
+/*************************************************************************/
+@interface ClutterGLView : NSOpenGLView
+{
+ ClutterActor *stage;
+}
+- (void) drawRect: (NSRect) bounds;
+@end
+
+@implementation ClutterGLView
+- (id) initWithFrame: (NSRect)aFrame pixelFormat:(NSOpenGLPixelFormat*)aFormat stage:(ClutterActor*)aStage
+{
+ if ((self = [super initWithFrame:aFrame pixelFormat:aFormat]) != nil)
+ {
+ self->stage = aStage;
+ }
+ return self;
+}
+
+- (void) drawRect: (NSRect) bounds
+{
+ clutter_actor_paint (self->stage);
+ [[self openGLContext] flushBuffer];
+}
+
+/* In order to receive key events */
+- (BOOL) acceptsFirstResponder
+{
+ return YES;
+}
+
+/* We want 0,0 top left */
+- (BOOL) isFlipped
+{
+ return YES;
+}
+
+- (void) setFrameSize: (NSSize) aSize
+{
+ CLUTTER_NOTE (BACKEND, "setFrameSize: %dx%d",
+ (int)aSize.width, (int)aSize.height);
+
+ [super setFrameSize: aSize];
+
+ clutter_actor_set_size (self->stage, (int)aSize.width, (int)aSize.height);
+
+ CLUTTER_SET_PRIVATE_FLAGS(self->stage, CLUTTER_ACTOR_SYNC_MATRICES);
+}
+
+/* Simply forward all events that reach our view to clutter. */
+
+#define EVENT_HANDLER(event) -(void)event:(NSEvent *)theEvent { \
+ _clutter_event_osx_put (theEvent); \
+}
+EVENT_HANDLER(mouseDown)
+EVENT_HANDLER(mouseDragged)
+EVENT_HANDLER(mouseUp)
+EVENT_HANDLER(mouseMoved)
+EVENT_HANDLER(mouseEntered)
+EVENT_HANDLER(mouseExited)
+EVENT_HANDLER(rightMouseDown)
+EVENT_HANDLER(rightMouseDragged)
+EVENT_HANDLER(rightMouseUp)
+EVENT_HANDLER(otherMouseDown)
+EVENT_HANDLER(otherMouseDragged)
+EVENT_HANDLER(otherMouseUp)
+EVENT_HANDLER(scrollWheel)
+EVENT_HANDLER(keyDown)
+EVENT_HANDLER(keyUp)
+EVENT_HANDLER(flagsChanged)
+EVENT_HANDLER(helpRequested)
+EVENT_HANDLER(tabletPoint)
+EVENT_HANDLER(tabletProximity)
+
+#undef EVENT_HANDLER
+@end
+
+/*************************************************************************/
+static void
+clutter_stage_osx_state_update (ClutterStageOSX *self,
+ ClutterStageState unset_flags,
+ ClutterStageState set_flags)
+{
+ ClutterStageStateEvent event;
+
+ event.new_state = self->stage_state;
+ event.new_state |= set_flags;
+ event.new_state &= ~unset_flags;
+
+ if (event.new_state == self->stage_state)
+ return;
+
+ event.changed_mask = event.new_state ^ self->stage_state;
+
+ self->stage_state = event.new_state;
+
+ event.type = CLUTTER_STAGE_STATE;
+ clutter_event_put ((ClutterEvent*)&event);
+}
+
+static void
+clutter_stage_osx_save_frame (ClutterStageOSX *self)
+{
+ if (CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (self)))
+ {
+ g_assert (self->window != NULL);
+
+ self->normalFrame = [self->window frame];
+ self->haveNormalFrame = TRUE;
+ }
+}
+
+static void
+clutter_stage_osx_set_frame (ClutterStageOSX *self)
+{
+ g_assert (CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (self)));
+ g_assert (self->window != NULL);
+
+ if (self->stage_state & CLUTTER_STAGE_STATE_FULLSCREEN)
+ {
+ /* Raise above the menubar (and dock) covering the whole screen.
+ *
+ * NOTE: This effectively breaks Option-Tabbing as our window covers
+ * all other applications completely. However we deal with the situation
+ * by lowering the window to the bottom of the normal level stack on
+ * windowDidResignKey notification.
+ */
+ [self->window setLevel: CLUTTER_OSX_FULLSCREEN_WINDOW_LEVEL];
+
+ [self->window setFrame: [self->window frameRectForContentRect: [[self->window screen] frame]] display: NO];
+ }
+ else
+ {
+ [self->window setLevel: NSNormalWindowLevel];
+
+ if (self->haveNormalFrame)
+ [self->window setFrame: self->normalFrame display: NO];
+ else
+ /* looks better than positioning to 0,0 (bottom right) */
+ [self->window center];
+ }
+}
+
+/*************************************************************************/
+static void
+clutter_stage_osx_realize (ClutterActor *actor)
+{
+ ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor);
+ ClutterBackendOSX *backend_osx;
+
+ CLUTTER_NOTE (BACKEND, "realize");
+
+ CLUTTER_OSX_POOL_ALLOC();
+
+ if (CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->realize)
+ CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->realize (actor);
+
+ backend_osx = CLUTTER_BACKEND_OSX (self->backend);
+
+ NSRect rect = NSMakeRect(0, 0, self->requisition_width, self->requisition_height);
+
+ self->view = [[ClutterGLView alloc]
+ initWithFrame: rect
+ pixelFormat: backend_osx->pixel_format
+ stage: actor];
+
+ self->window = [[ClutterGLWindow alloc]
+ initWithView: self->view
+ UTF8Title: clutter_stage_get_title (CLUTTER_STAGE (self))
+ stage: self];
+
+ /* looks better than positioning to 0,0 (bottom right) */
+ [self->window center];
+
+ /* To not miss all textures created with the context created in the backend
+ * make sure we share the context. (By default NSOpenGLView creates its own
+ * context.)
+ */
+ NSOpenGLContext *context = backend_osx->context;
+
+ [self->view setOpenGLContext: context];
+ [context setView: self->view];
+
+ CLUTTER_OSX_POOL_RELEASE();
+
+ CLUTTER_SET_PRIVATE_FLAGS(self, CLUTTER_ACTOR_SYNC_MATRICES);
+}
+
+static void
+clutter_stage_osx_unrealize (ClutterActor *actor)
+{
+ ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor);
+
+ CLUTTER_NOTE (BACKEND, "unrealize");
+
+ CLUTTER_OSX_POOL_ALLOC();
+
+ [self->view release];
+ [self->window close];
+
+ self->view = NULL;
+ self->window = NULL;
+
+ CLUTTER_OSX_POOL_RELEASE();
+
+ if (CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->unrealize)
+ CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->unrealize (actor);
+}
+
+static void
+clutter_stage_osx_show (ClutterActor *actor)
+{
+ ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor);
+
+ CLUTTER_NOTE (BACKEND, "show");
+
+ if (CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->show)
+ CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->show (actor);
+
+ CLUTTER_OSX_POOL_ALLOC();
+
+ clutter_stage_osx_set_frame (self);
+
+ [self->window makeKeyAndOrderFront: nil];
+
+ CLUTTER_OSX_POOL_RELEASE();
+}
+
+static void
+clutter_stage_osx_hide (ClutterActor *actor)
+{
+ ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor);
+
+ CLUTTER_NOTE (BACKEND, "hide");
+
+ CLUTTER_OSX_POOL_ALLOC();
+
+ [self->window orderOut: nil];
+
+ CLUTTER_OSX_POOL_RELEASE();
+
+ if (CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->hide)
+ CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->hide (actor);
+}
+
+static void
+clutter_stage_osx_query_coords (ClutterActor *actor,
+ ClutterActorBox *box)
+{
+ ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor);
+
+ CLUTTER_OSX_POOL_ALLOC();
+
+ box->x1 = 0;
+ box->y1 = 0;
+ box->x2 = box->x1 + CLUTTER_UNITS_FROM_FLOAT (self->requisition_width);
+ box->y2 = box->y1 + CLUTTER_UNITS_FROM_FLOAT (self->requisition_height);
+
+ CLUTTER_OSX_POOL_RELEASE();
+}
+
+static void
+clutter_stage_osx_request_coords (ClutterActor *actor,
+ ClutterActorBox *box)
+{
+ ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor);
+
+ CLUTTER_NOTE (BACKEND, "request_coords: %d,%d %dx%d",
+ CLUTTER_UNITS_TO_INT (box->x1),
+ CLUTTER_UNITS_TO_INT (box->y1),
+ CLUTTER_UNITS_TO_INT (box->x2 - box->x1),
+ CLUTTER_UNITS_TO_INT (box->y2 - box->y1));
+
+ self->requisition_width = CLUTTER_UNITS_TO_INT (box->x2 - box->x1);
+ self->requisition_height = CLUTTER_UNITS_TO_INT (box->y2 - box->y1);
+
+ if (CLUTTER_ACTOR_IS_REALIZED (actor))
+ {
+ CLUTTER_OSX_POOL_ALLOC();
+
+ NSSize size = NSMakeSize(self->requisition_width,
+ self->requisition_height);
+ [self->window setContentSize: size];
+
+ CLUTTER_OSX_POOL_RELEASE();
+ }
+}
+
+/*************************************************************************/
+static void
+clutter_stage_osx_set_title (ClutterStage *stage,
+ const char *title)
+{
+ ClutterStageOSX *self = CLUTTER_STAGE_OSX (stage);
+
+ CLUTTER_NOTE (BACKEND, "set_title: %s", title);
+
+ CLUTTER_OSX_POOL_ALLOC();
+
+ if (CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stage)))
+ [self->window setTitle:[NSString stringWithUTF8String:title]];
+
+ CLUTTER_OSX_POOL_RELEASE();
+}
+
+static void
+clutter_stage_osx_set_fullscreen (ClutterStage *stage,
+ gboolean fullscreen)
+{
+ ClutterStageOSX *self = CLUTTER_STAGE_OSX (stage);
+
+ CLUTTER_NOTE (BACKEND, "set_fullscreen: %u", fullscreen);
+
+ CLUTTER_OSX_POOL_ALLOC();
+
+ /* Make sure to update the state before clutter_stage_osx_set_frame.
+ *
+ * Toggling fullscreen isn't atomic, there's two "events" involved:
+ * - stage state change (via state_update)
+ * - stage size change (via set_frame -> setFrameSize / set_size)
+ *
+ * We do state change first. Not sure there's any difference.
+ */
+ if (fullscreen)
+ clutter_stage_osx_state_update (self, 0, CLUTTER_STAGE_STATE_FULLSCREEN);
+ else
+ clutter_stage_osx_state_update (self, CLUTTER_STAGE_STATE_FULLSCREEN, 0);
+
+ if (CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (self)))
+ {
+ if (fullscreen)
+ clutter_stage_osx_save_frame (self);
+
+ clutter_stage_osx_set_frame (self);
+ }
+ else if (fullscreen)
+ {
+ /* FIXME: if you go fullscreen before realize we throw away the normal
+ * stage size and can't return. Need to maintain them separately.
+ */
+ NSSize size = [[NSScreen mainScreen] frame].size;
+
+ clutter_actor_set_size (CLUTTER_ACTOR (self),
+ (int)size.width, (int)size.height);
+ }
+
+ CLUTTER_OSX_POOL_RELEASE();
+}
+
+/*************************************************************************/
+ClutterActor *
+clutter_stage_osx_new (ClutterBackend *backend)
+{
+ ClutterStageOSX *self;
+
+ self = g_object_new (CLUTTER_TYPE_STAGE_OSX, NULL);
+ self->backend = backend;
+
+ return CLUTTER_ACTOR(self);
+}
+
+/*************************************************************************/
+static void
+clutter_stage_osx_init (ClutterStageOSX *self)
+{
+ self->requisition_width = 640;
+ self->requisition_height = 480;
+
+ CLUTTER_SET_PRIVATE_FLAGS(self, CLUTTER_ACTOR_SYNC_MATRICES);
+}
+
+static void
+clutter_stage_osx_class_init (ClutterStageOSXClass *klass)
+{
+ ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+ ClutterStageClass *stage_class = CLUTTER_STAGE_CLASS (klass);
+
+ actor_class->realize = clutter_stage_osx_realize;
+ actor_class->unrealize = clutter_stage_osx_unrealize;
+ actor_class->show = clutter_stage_osx_show;
+ actor_class->hide = clutter_stage_osx_hide;
+
+ actor_class->query_coords = clutter_stage_osx_query_coords;
+ actor_class->request_coords = clutter_stage_osx_request_coords;
+
+ stage_class->set_title = clutter_stage_osx_set_title;
+ stage_class->set_fullscreen = clutter_stage_osx_set_fullscreen;
+}
--- /dev/null
+/* Clutter - An OpenGL based 'interactive canvas' library.
+ * OSX backend - integration with NSWindow and NSView
+ *
+ * Copyright (C) 2007 Tommi Komulainen <tommi.komulainen@iki.fi>
+ * Copyright (C) 2007 OpenedHand Ltd.
+ *
+ * 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_OSX_H__
+#define __CLUTTER_STAGE_OSX_H__
+
+#include <clutter/clutter-stage.h>
+#include <clutter/clutter-backend.h>
+
+#import <Foundation/Foundation.h>
+@class NSOpenGLView, NSWindow;
+
+G_BEGIN_DECLS
+
+/* convenience macros */
+#define CLUTTER_TYPE_STAGE_OSX (clutter_stage_osx_get_type())
+#define CLUTTER_STAGE_OSX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),CLUTTER_TYPE_STAGE_OSX,ClutterStageOSX))
+#define CLUTTER_STAGE_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),CLUTTER_TYPE_STAGE_OSX,ClutterStage))
+#define CLUTTER_IS_STAGE_OSX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),CLUTTER_TYPE_STAGE_OSX))
+#define CLUTTER_IS_STAGE_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),CLUTTER_TYPE_STAGE_OSX))
+#define CLUTTER_STAGE_OSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),CLUTTER_TYPE_STAGE_OSX,ClutterStageOSXClass))
+
+typedef struct _ClutterStageOSX ClutterStageOSX;
+typedef struct _ClutterStageOSXClass ClutterStageOSXClass;
+
+struct _ClutterStageOSX
+{
+ ClutterStage parent;
+
+ ClutterBackend *backend;
+
+ NSWindow *window;
+ NSOpenGLView *view;
+
+ gboolean haveNormalFrame;
+ NSRect normalFrame;
+
+ gint requisition_width;
+ gint requisition_height;
+
+ ClutterStageState stage_state;
+};
+
+struct _ClutterStageOSXClass
+{
+ ClutterStageClass parent_class;
+};
+
+GType clutter_stage_osx_get_type (void) G_GNUC_CONST;
+
+ClutterActor* clutter_stage_osx_new (ClutterBackend *backend);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_STAGE_OSX_H__ */
EGL_CFLAGS="$TSLIB_CFLAGS"
;;
+ osx)
- *) AC_MSG_ERROR([Invalid backend for Clutter: use glx,sdl, eglx or eglnative])
+ CLUTTER_FLAVOUR="osx"
+ AC_DEFINE([HAVE_CLUTTER_OSX], [1], [Have the OSX backend])
+
+ CLUTTER_COGL="gl"
+ AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering])
+
+ OSX_LIBS="-framework Cocoa -framework OpenGL"
+ AC_CHECK_HEADERS([OpenGL/gl.h],,
+ [AC_MSG_ERROR([Unable to locate required GL headers])])
+ ;;
+
+ *) AC_MSG_ERROR([Invalid backend for Clutter: use glx,sdl,osx,eglx or eglnative])
;;
esac
AC_SUBST(GCC_FLAGS)
-CLUTTER_CFLAGS="$SDL_CFLAGS $EGL_CFLAGS $GLX_CFLAGS $CLUTTER_DEPS_CFLAGS "
-CLUTTER_LIBS="$SDL_LIBS $EGL_LIBS $GLX_LIBS $CLUTTER_DEPS_LIBS"
+CLUTTER_CFLAGS="$SDL_CFLAGS $EGL_CFLAGS $GLX_CFLAGS $OSX_CFLAGS $CLUTTER_DEPS_CFLAGS "
+CLUTTER_LIBS="$SDL_LIBS $EGL_LIBS $GLX_LIBS $OSX_LIBS $CLUTTER_DEPS_LIBS"
AC_SUBST(CLUTTER_CFLAGS)
AC_SUBST(CLUTTER_LIBS)
clutter/glx/Makefile
clutter/eglx/Makefile
clutter/eglnative/Makefile
+ clutter/osx/Makefile
clutter/sdl/Makefile
clutter/cogl/Makefile
clutter/cogl/gl/Makefile