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)
This commit is contained in:
parent
b7b7c60e5f
commit
737ac37f27
23
ChangeLog
23
ChangeLog
@ -1,3 +1,26 @@
|
||||
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
|
||||
|
@ -2,7 +2,7 @@ NULL =
|
||||
|
||||
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)
|
||||
|
||||
|
@ -90,7 +90,7 @@ struct _ClutterTexturePrivate
|
||||
ClutterTextureTileDimension *y_tiles;
|
||||
gint n_x_tiles;
|
||||
gint n_y_tiles;
|
||||
guint *tiles;
|
||||
COGLuint *tiles;
|
||||
};
|
||||
|
||||
enum
|
||||
@ -440,7 +440,7 @@ texture_upload_data (ClutterTexture *texture,
|
||||
/* Single Texture */
|
||||
if (!priv->tiles)
|
||||
{
|
||||
priv->tiles = g_new (guint, 1);
|
||||
priv->tiles = g_new (COGLuint, 1);
|
||||
glGenTextures (1, priv->tiles);
|
||||
create_textures = TRUE;
|
||||
}
|
||||
@ -511,7 +511,7 @@ texture_upload_data (ClutterTexture *texture,
|
||||
|
||||
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;
|
||||
}
|
||||
@ -1423,7 +1423,7 @@ clutter_texture_set_from_yuv_data (ClutterTexture *texture,
|
||||
|
||||
if (!priv->tiles)
|
||||
{
|
||||
priv->tiles = g_new (guint, 1);
|
||||
priv->tiles = g_new (COGLuint, 1);
|
||||
glGenTextures (1, priv->tiles);
|
||||
}
|
||||
|
||||
|
@ -43,10 +43,7 @@
|
||||
#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"
|
||||
|
||||
@ -133,13 +130,13 @@ cogl_texture_quad (gint x1,
|
||||
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,
|
||||
|
@ -27,16 +27,25 @@
|
||||
#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 */
|
||||
|
||||
|
@ -29,12 +29,6 @@
|
||||
|
||||
#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
|
||||
@ -333,7 +327,7 @@ cogl_texture_can_size (COGLenum target,
|
||||
#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) );
|
||||
|
||||
@ -381,19 +375,19 @@ cogl_texture_quad (gint x1,
|
||||
}
|
||||
|
||||
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) );
|
||||
}
|
||||
@ -696,12 +690,25 @@ cogl_get_viewport (ClutterFixed v[4])
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -439,6 +439,7 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef GLenum COGLenum;
|
||||
typedef GLint COGLint;
|
||||
typedef GLuint COGLuint;
|
||||
|
||||
/* extras */
|
||||
|
||||
|
@ -323,19 +323,19 @@ cogl_texture_quad (gint x1,
|
||||
}
|
||||
|
||||
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) );
|
||||
}
|
||||
|
24
clutter/osx/Makefile.am
Normal file
24
clutter/osx/Makefile.am
Normal file
@ -0,0 +1,24 @@
|
||||
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
|
182
clutter/osx/clutter-backend-osx.c
Normal file
182
clutter/osx/clutter-backend-osx.c
Normal file
@ -0,0 +1,182 @@
|
||||
/* 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 ();
|
||||
}
|
60
clutter/osx/clutter-backend-osx.h
Normal file
60
clutter/osx/clutter-backend-osx.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* 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__ */
|
387
clutter/osx/clutter-event-osx.c
Normal file
387
clutter/osx/clutter-event-osx.c
Normal file
@ -0,0 +1,387 @@
|
||||
/* 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;
|
||||
}
|
||||
}
|
41
clutter/osx/clutter-osx.h
Normal file
41
clutter/osx/clutter-osx.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* 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__ */
|
496
clutter/osx/clutter-stage-osx.c
Normal file
496
clutter/osx/clutter-stage-osx.c
Normal file
@ -0,0 +1,496 @@
|
||||
/* 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;
|
||||
}
|
73
clutter/osx/clutter-stage-osx.h
Normal file
73
clutter/osx/clutter-stage-osx.h
Normal file
@ -0,0 +1,73 @@
|
||||
/* 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__ */
|
19
configure.ac
19
configure.ac
@ -258,8 +258,20 @@ case $clutterbackend in
|
||||
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
|
||||
@ -351,8 +363,8 @@ dnl ========================================================================
|
||||
|
||||
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)
|
||||
@ -364,6 +376,7 @@ AC_CONFIG_FILES([
|
||||
clutter/glx/Makefile
|
||||
clutter/eglx/Makefile
|
||||
clutter/eglnative/Makefile
|
||||
clutter/osx/Makefile
|
||||
clutter/sdl/Makefile
|
||||
clutter/cogl/Makefile
|
||||
clutter/cogl/gl/Makefile
|
||||
|
Loading…
Reference in New Issue
Block a user