From 9a4dd0c4292177afaa6263cd21c385762fd4489a Mon Sep 17 00:00:00 2001
From: Tommi Komulainen <tommi.komulainen@iki.fi>
Date: Sat, 14 Jun 2008 22:27:59 +0100
Subject: [PATCH] OSX: quick hack for clutter-gtk

---
 clutter-gtk/clutter-gtk/gtk-clutter-embed.c |   14 ++++++++-
 clutter-gtk/configure.ac                    |   28 ++++++++---------
 clutter/clutter/osx/clutter-backend-osx.c   |   12 +++++++
 clutter/clutter/osx/clutter-backend-osx.h   |    2 +
 clutter/clutter/osx/clutter-event-osx.c     |    9 +++++
 clutter/clutter/osx/clutter-osx.h           |    6 ++++
 clutter/clutter/osx/clutter-stage-osx.c     |   43 +++++++++++++++++++++++++-
 clutter/clutter/osx/clutter-stage-osx.h     |    1 +
 8 files changed, 97 insertions(+), 18 deletions(-)

diff --git a/clutter-gtk/clutter-gtk/gtk-clutter-embed.c b/clutter-gtk/clutter-gtk/gtk-clutter-embed.c
index b7b7ac7..6fb73e3 100644
--- a/clutter-gtk/clutter-gtk/gtk-clutter-embed.c
+++ b/clutter-gtk/clutter-gtk/gtk-clutter-embed.c
@@ -59,7 +59,14 @@
 #include <clutter/clutter-win32.h>
 #include <gdk/gdkwin32.h>
 
-#endif /* HAVE_CLUTTER_GTK_{X11,WIN32} */
+#elif defined(HAVE_CLUTTER_GTK_OSX)
+
+#include <clutter/clutter-osx.h>
+#include <gdk/gdkquartz.h>
+
+#else
+#error "clutter-gtk has not been ported for this platform yet"
+#endif /* HAVE_CLUTTER_GTK_{X11,WIN32,OSX} */
 
 #include "gtk-clutter-embed.h"
 
@@ -178,6 +185,9 @@ gtk_clutter_embed_realize (GtkWidget *widget)
 #elif defined(HAVE_CLUTTER_GTK_WIN32)
   clutter_win32_set_stage_foreign (CLUTTER_STAGE (priv->stage), 
 				   GDK_WINDOW_HWND (widget->window));
+#elif defined(HAVE_CLUTTER_GTK_OSX)
+  clutter_osx_set_stage_foreign (CLUTTER_STAGE (priv->stage), 
+                                 gdk_quartz_window_get_nsview (widget->window));
 #endif /* HAVE_CLUTTER_GTK_{X11,WIN32} */
 
   clutter_redraw (CLUTTER_STAGE (priv->stage));
@@ -489,6 +499,8 @@ gtk_clutter_init (int    *argc,
   clutter_x11_disable_event_retrieval ();
 #elif defined(HAVE_CLUTTER_GTK_WIN32)
   clutter_win32_disable_event_retrieval ();
+#elif defined(HAVE_CLUTTER_GTK_OSX)
+  clutter_osx_disable_event_retrieval ();
 #endif /* HAVE_CLUTTER_GTK_{X11,WIN32} */
 
   return clutter_init (argc, argv);
diff --git a/clutter-gtk/configure.ac b/clutter-gtk/configure.ac
index 8a53670..2f3b803 100644
--- a/clutter-gtk/configure.ac
+++ b/clutter-gtk/configure.ac
@@ -69,33 +69,31 @@ AC_CHECK_FUNCS([memset munmap strcasecmp strdup])
 
 CLUTTER_REQUIRED=0.7.0
 
-cluttergtkflavour=x11
-AC_ARG_WITH([flavour],
-            AC_HELP_STRING([--with-flavour=@<:@x11/win32@:>@],
-                           [Select the Clutter backend]),
-            cluttergtkflavour=$with_flavour)
+PKG_CHECK_MODULES(CLUTTER, clutter-0.7 >= $CLUTTER_REQUIRED)
+cluttergtkflavour="`$PKG_CONFIG --variable=backend clutter-0.7`"
 
-case $cluttergtkflavour in
+PKG_CHECK_MODULES(GTK, gtk+-2.0)
+gtkflavour="`$PKG_CONFIG --variable=target gtk+-2.0`"
 
-  x11)
+case "$cluttergtkflavour,$gtkflavour" in
+  x11,x11)
     AC_DEFINE([HAVE_CLUTTER_GTK_X11], 1, [Using the X11 flavour])
-    PKG_CHECK_MODULES(CLUTTER, clutter-x11-0.7 >= $CLUTTER_REQUIRED)
     ;;
-    
-  win32)
+  win32,win32)
     AC_DEFINE([HAVE_CLUTTER_GTK_WIN32], 1, [Using the Win32 flavour])
-    PKG_CHECK_MODULES(CLUTTER, clutter-win32-0.7 >= $CLUTTER_REQUIRED)
     ;;
-    
-  *)
-    AC_MSG_ERROR([Invalid flavour for Clutter-GTK: use x11 or win32])
+  osx,quartz)
+    AC_DEFINE([HAVE_CLUTTER_GTK_OSX], 1, [Using the OSX flavour])
+    CLUTTER_CFLAGS="$CLUTTER_CFLAGS -xobjective-c"
+    CLUTTER_LIBS="$CLUTTER_LIBS -framework Cocoa"
     ;;
+  *)
+    AC_MSG_ERROR([Invalid flavours: Clutter/$cluttergtkflavour and GTK/$gtkflavour])
 esac
 
 AC_SUBST(CLUTTER_CFLAGS)
 AC_SUBST(CLUTTER_LIBS)
 
-PKG_CHECK_MODULES(GTK, gtk+-2.0)
 AC_SUBST(GTK_CFLAGS)
 AC_SUBST(GTK_LIBS)
 
diff --git a/clutter/clutter/osx/clutter-backend-osx.c b/clutter/clutter/osx/clutter-backend-osx.c
index 9c84c23..874cc8a 100644
--- a/clutter/clutter/osx/clutter-backend-osx.c
+++ b/clutter/clutter/osx/clutter-backend-osx.c
@@ -211,3 +211,15 @@ _clutter_backend_impl_get_type (void)
 {
   return clutter_backend_osx_get_type ();
 }
+
+void
+clutter_osx_disable_event_retrieval (void)
+{
+  ClutterMainContext *context;
+  ClutterBackendOSX *backend_osx;
+
+  context = clutter_context_get_default ();
+  backend_osx = CLUTTER_BACKEND_OSX (context->backend);
+
+  backend_osx->no_event_retrieval = TRUE;
+}
diff --git a/clutter/clutter/osx/clutter-backend-osx.h b/clutter/clutter/osx/clutter-backend-osx.h
index b47b889..1f5a8b8 100644
--- a/clutter/clutter/osx/clutter-backend-osx.h
+++ b/clutter/clutter/osx/clutter-backend-osx.h
@@ -44,6 +44,8 @@ struct _ClutterBackendOSX
 
   NSOpenGLPixelFormat *pixel_format;
   NSOpenGLContext     *context;
+
+  gboolean no_event_retrieval;
 };
 
 struct _ClutterBackendOSXClass
diff --git a/clutter/clutter/osx/clutter-event-osx.c b/clutter/clutter/osx/clutter-event-osx.c
index 8a12817..b04dd47 100644
--- a/clutter/clutter/osx/clutter-event-osx.c
+++ b/clutter/clutter/osx/clutter-event-osx.c
@@ -23,6 +23,7 @@
 
 #include "clutter-osx.h"
 #include "clutter-stage-osx.h"
+#include "clutter-backend-osx.h"
 
 #import <AppKit/AppKit.h>
 #include <glib/gmain.h>
@@ -373,8 +374,16 @@ clutter_event_osx_poll_func (GPollFD *ufds, guint nfds, gint timeout)
 void
 _clutter_events_osx_init (void)
 {
+  ClutterMainContext *context;
+  ClutterBackendOSX *backend_osx;
+
   g_assert (old_poll_func == NULL);
 
+  context = clutter_context_get_default ();
+  backend_osx = CLUTTER_BACKEND_OSX (context->backend);
+  if (backend_osx->no_event_retrieval)
+    return;
+
   old_poll_func = g_main_context_get_poll_func (NULL);
   g_main_context_set_poll_func (NULL, clutter_event_osx_poll_func);
 }
diff --git a/clutter/clutter/osx/clutter-osx.h b/clutter/clutter/osx/clutter-osx.h
index 3c4fc9c..f4e84c1 100644
--- a/clutter/clutter/osx/clutter-osx.h
+++ b/clutter/clutter/osx/clutter-osx.h
@@ -25,6 +25,7 @@
 #include <clutter/clutter-stage.h>
 
 @class NSEvent;
+@class NSView;
 
 G_BEGIN_DECLS
 
@@ -36,6 +37,11 @@ void _clutter_events_osx_uninit (void);
 
 void _clutter_event_osx_put     (NSEvent *nsevent, ClutterStage *wrapper);
 
+void clutter_osx_disable_event_retrieval (void);
+
+void clutter_osx_set_stage_foreign (ClutterStage *wrapper,
+				    NSView *view);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_OSX_H__ */
diff --git a/clutter/clutter/osx/clutter-stage-osx.c b/clutter/clutter/osx/clutter-stage-osx.c
index cb60b36..ee8ab75 100644
--- a/clutter/clutter/osx/clutter-stage-osx.c
+++ b/clutter/clutter/osx/clutter-stage-osx.c
@@ -35,6 +35,8 @@ G_DEFINE_TYPE_WITH_CODE (ClutterStageOSX, clutter_stage_osx, CLUTTER_TYPE_ACTOR,
                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
                                                 clutter_stage_window_iface_init))
 
+#define CLUTTER_STAGE_OSX_IS_FOREIGN(stage) (stage->parent_view != NULL)
+
 /* FIXME: this should be in clutter-stage.c */
 static void
 clutter_stage_osx_state_update (ClutterStageOSX   *self,
@@ -285,10 +287,19 @@ clutter_stage_osx_realize (ClutterActor *actor)
                         stage: self];
   [self->view setOpenGLContext:backend_osx->context];
 
+  if (CLUTTER_STAGE_OSX_IS_FOREIGN (self))
+    {
+      CLUTTER_NOTE (BACKEND, "foreign: addSubview");
+      [self->parent_view addSubview: self->view];
+    }
+  else
+    {
+      CLUTTER_NOTE (BACKEND, "not foreign: create window");
   self->window = [[ClutterGLWindow alloc]
                   initWithView: self->view
                      UTF8Title: clutter_stage_get_title (CLUTTER_STAGE (self->wrapper))
                          stage: self];
+    }
 
   /* looks better than positioning to 0,0 (bottom right) */
   [self->window center];
@@ -310,10 +321,14 @@ clutter_stage_osx_unrealize (ClutterActor *actor)
   CLUTTER_NOTE (BACKEND, "[%p] unrealize", self);
 
   /* ensure we get realize+unrealize properly paired */
-  g_return_if_fail (self->view != NULL && self->window != NULL);
+  g_return_if_fail (self->view != NULL &&
+                    (self->window != NULL || self->parent_view != NULL));
 
   CLUTTER_OSX_POOL_ALLOC();
 
+  if (CLUTTER_STAGE_OSX_IS_FOREIGN (self))
+    [self->view removeFromSuperview];
+
   [self->view release];
   [self->window close];
 
@@ -339,7 +354,8 @@ clutter_stage_osx_show (ClutterActor *actor)
 
   CLUTTER_OSX_POOL_ALLOC();
 
-  clutter_stage_osx_set_frame (self);
+  if (!CLUTTER_STAGE_OSX_IS_FOREIGN (self))
+    clutter_stage_osx_set_frame (self);
 
   [self->window makeKeyAndOrderFront: nil];
 
@@ -570,3 +586,26 @@ clutter_stage_osx_class_init (ClutterStageOSXClass *klass)
   actor_class->get_preferred_width  = clutter_stage_osx_get_preferred_width;
   actor_class->get_preferred_height = clutter_stage_osx_get_preferred_height;
 }
+
+void
+clutter_osx_set_stage_foreign (ClutterStage *wrapper,
+                               NSView *parent_view)
+{
+  ClutterStageWindow *impl = _clutter_stage_get_window (wrapper);
+  ClutterStageOSX *stage_osx;
+
+  g_return_if_fail ([parent_view isKindOfClass:[NSView class]]);
+
+  g_assert (CLUTTER_IS_STAGE_OSX (impl));
+  stage_osx = CLUTTER_STAGE_OSX (impl);
+
+  gboolean was_realized = CLUTTER_ACTOR_IS_REALIZED (stage_osx);
+
+  clutter_actor_unrealize (CLUTTER_ACTOR (stage_osx));
+  g_assert (stage_osx->window == NULL);
+
+  stage_osx->parent_view = [parent_view retain];
+
+  if (was_realized)
+    clutter_actor_realize (CLUTTER_ACTOR (stage_osx));
+}
diff --git a/clutter/clutter/osx/clutter-stage-osx.h b/clutter/clutter/osx/clutter-stage-osx.h
index e24acfa..1859a36 100644
--- a/clutter/clutter/osx/clutter-stage-osx.h
+++ b/clutter/clutter/osx/clutter-stage-osx.h
@@ -57,6 +57,7 @@ struct _ClutterStageOSX
 
   NSWindow *window;
   NSOpenGLView *view;
+  NSView *parent_view;
 
   gboolean haveNormalFrame;
   NSRect normalFrame;
-- 
1.5.5.3

