[317/906] implement gstglwindow for Cocoa (MacOS and GNUstep)
authorJulien Isorce <julien.isorce@gmail.com>
Thu, 26 Feb 2009 00:06:58 +0000 (01:06 +0100)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:31:21 +0000 (19:31 +0000)
gst-libs/gst/gl/GNUmakefile
gst-libs/gst/gl/gstglwindow.h
gst-libs/gst/gl/gstglwindow_cocoa.m [new file with mode: 0644]

index 409841b..a9e9700 100644 (file)
@@ -2,15 +2,13 @@ include $(GNUSTEP_MAKEFILES)/common.make
 
 SUBPROJECT_NAME = gstlibsgstgl
 
-#gstglwindow_win32.c will be replaced by gstglwindow_cocoa.m
 gstlibsgstgl_C_FILES = \
-  gstglwindow_win32.c \
   gstgldisplay.c \
   gstglbuffer.c \
   gstglfilter.c \
   gstglshader.c
 
-#gstlibsgstgl_OBJC_FILES = gstglwindow_cocoa.m
+gstlibsgstgl_OBJC_FILES = gstglwindow_cocoa.m
 
 ifeq ($(GNUSTEP_TARGET_OS), mingw32)
 gstlibsgstgl_INCLUDE_DIRS = \
index 9dd1d92..10cdd90 100644 (file)
 #ifndef __GST_GL_WINDOW_H__
 #define __GST_GL_WINDOW_H__
 
-
+#if (!GNUSTEP && MACOS)
+#include <OpenGL/glew.h>
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/gl.h>
+#else
 #include <GL/glew.h>
 #include <GL/gl.h>
+#endif
+
 #include <gst/gst.h>
 
 G_BEGIN_DECLS
diff --git a/gst-libs/gst/gl/gstglwindow_cocoa.m b/gst-libs/gst/gl/gstglwindow_cocoa.m
new file mode 100644 (file)
index 0000000..bd77bd0
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglwindow.h"
+
+#import <Cocoa/Cocoa.h>
+
+
+/* ============================================================= */
+/*                                                               */
+/*              GstGLNSWindow declaration                        */
+/*                                                               */
+/* ============================================================= */
+
+@interface GstGLNSWindow: NSWindow {
+  BOOL m_isClosed;
+  GstGLWindowPrivate *m_priv;
+}
+- (id)initWithContentRect:(NSRect)contentRect
+               styleMask: (unsigned int) styleMask
+               backing: (NSBackingStoreType) bufferingType
+               defer: (BOOL) flag screen: (NSScreen *) aScreen
+    gstWin: (GstGLWindowPrivate *) priv;
+@end
+
+
+/* ============================================================= */
+/*                                                               */
+/*               AppThreadPerformer declaration                  */
+/*                                                               */
+/* ============================================================= */
+
+/* Perform actions in the Application thread */
+@interface AppThreadPerformer : NSObject {
+  GstGLWindowPrivate *m_priv;
+  GstGLWindowCB m_callback;
+  gpointer m_data;
+}
+- (id) initWithPrivate : (GstGLWindowPrivate *) priv;
+- (id) initWithCallback : (GstGLWindowCB) callback userData: (gpointer) data;
+- (id) initWithAll: (GstGLWindowCB) callback userData: (gpointer) data private: (GstGLWindowPrivate *) priv;
+- (void) updateWindow;
+- (void) sendToApp;
+- (void) setWindow: (NSWindow *) window;
+- (void) stopApp;
+@end
+
+
+/* ============================================================= */
+/*                                                               */
+/*                         GstGLWindow                           */
+/*                                                               */
+/* ============================================================= */
+
+#ifndef GNUSTEP
+static BOOL GSRegisterCurrentThread() { return TRUE; };
+static GSUnregisterCurrentThread() {};
+#endif
+
+#define GST_GL_WINDOW_GET_PRIVATE(o)  \
+  (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW, GstGLWindowPrivate))
+
+enum
+{
+  PROP_0
+};
+
+struct _GstGLWindowPrivate
+{
+  GstGLNSWindow *internal_win_id;
+  GstGLWindowCB draw_cb;
+  gpointer draw_data;
+  GstGLWindowCB2 resize_cb;
+  gpointer resize_data;
+  GstGLWindowCB close_cb;
+  gpointer close_data;
+  gboolean visible;
+  NSWindow *parent;
+};
+
+G_DEFINE_TYPE (GstGLWindow, gst_gl_window, G_TYPE_OBJECT);
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "GstGLWindow"
+
+gboolean _gst_gl_window_debug = FALSE;
+
+/* Must be called in the gl thread */
+static void
+gst_gl_window_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (gst_gl_window_parent_class)->finalize (object);
+}
+
+static void
+gst_gl_window_log_handler (const gchar * domain, GLogLevelFlags flags,
+    const gchar * message, gpointer user_data)
+{
+  if (_gst_gl_window_debug) {
+    g_log_default_handler (domain, flags, message, user_data);
+  }
+}
+
+static void
+gst_gl_window_class_init (GstGLWindowClass * klass)
+{
+  GObjectClass *obj_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GstGLWindowPrivate));
+
+  obj_class->finalize = gst_gl_window_finalize;
+}
+
+static void
+gst_gl_window_init (GstGLWindow * window)
+{
+  window->priv = GST_GL_WINDOW_GET_PRIVATE (window);
+
+  if (g_getenv ("GST_GL_WINDOW_DEBUG") != NULL)
+    _gst_gl_window_debug = TRUE;
+
+  g_log_set_handler ("GstGLWindow", G_LOG_LEVEL_DEBUG,
+      gst_gl_window_log_handler, NULL);
+}
+
+/* Must be called in the gl thread */
+GstGLWindow *
+gst_gl_window_new (gint width, gint height)
+{
+  GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
+  GstGLWindowPrivate *priv = window->priv;
+
+  NSAutoreleasePool *pool = nil;
+  NSRect rect;
+
+  static gint x = 0;
+  static gint y = 0;
+
+  x += 20;
+  y += 20;
+
+  priv->internal_win_id = nil;
+  priv->draw_cb = NULL;
+  priv->draw_data = NULL;
+  priv->resize_cb = NULL;
+  priv->resize_data = NULL;
+  priv->close_cb = NULL;
+  priv->close_data = NULL;
+  priv->visible = FALSE;
+  priv->parent = nil;
+
+  GSRegisterCurrentThread();
+
+  pool = [[NSAutoreleasePool alloc] init];
+  [NSApplication sharedApplication];
+
+  rect.origin.x = x;
+  rect.origin.y = y;
+  rect.size.width = width;
+  rect.size.height = height;
+
+  priv->internal_win_id =[[GstGLNSWindow alloc] initWithContentRect:rect
+    styleMask: (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask)
+    backing: NSBackingStoreBuffered defer: NO screen: nil gstWin: priv];
+
+  [pool release];
+
+  return window;
+}
+
+GQuark
+gst_gl_window_error_quark (void)
+{
+  return g_quark_from_static_string ("gst-gl-window-error");
+}
+
+void
+gst_gl_window_set_external_window_id (GstGLWindow * window, guint64 id)
+{
+  GstGLWindowPrivate *priv = window->priv;
+
+  if (GSRegisterCurrentThread()) {
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+    AppThreadPerformer* app_thread_performer = [[AppThreadPerformer alloc] initWithPrivate:priv];
+    [app_thread_performer performSelectorOnMainThread:@selector(setWindow) withObject:(NSWindow *)(gulong)id waitUntilDone:YES];
+
+    [pool release];
+
+    GSUnregisterCurrentThread();
+  }
+  else
+    g_debug ("failed to register current thread, cannot set external window id");
+}
+
+void
+gst_gl_window_set_external_gl_context (GstGLWindow * window, guint64 context)
+{
+  g_warning ("gst_gl_window_set_external_gl_context: not implemented\n");
+}
+
+/* Must be called in the gl thread */
+void
+gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback,
+    gpointer data)
+{
+  GstGLWindowPrivate *priv = window->priv;
+
+  priv->draw_cb = callback;
+  priv->draw_data = data;
+}
+
+/* Must be called in the gl thread */
+void
+gst_gl_window_set_resize_callback (GstGLWindow * window,
+    GstGLWindowCB2 callback, gpointer data)
+{
+  GstGLWindowPrivate *priv = window->priv;
+
+  priv->resize_cb = callback;
+  priv->resize_data = data;
+}
+
+/* Must be called in the gl thread */
+void
+gst_gl_window_set_close_callback (GstGLWindow * window, GstGLWindowCB callback,
+    gpointer data)
+{
+  GstGLWindowPrivate *priv = window->priv;
+
+  priv->close_cb = callback;
+  priv->close_data = data;
+}
+
+void
+gst_gl_window_draw_unlocked (GstGLWindow * window)
+{
+  gst_gl_window_draw (window);
+}
+
+/* Thread safe */
+void
+gst_gl_window_draw (GstGLWindow * window)
+{
+  GstGLWindowPrivate *priv = window->priv;
+
+  if (GSRegisterCurrentThread()) {
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+    AppThreadPerformer* app_thread_performer = [[AppThreadPerformer alloc] initWithPrivate:priv];
+    [app_thread_performer performSelectorOnMainThread:@selector(updateWindow) withObject:nil waitUntilDone:YES];
+
+    [pool release];
+
+    GSUnregisterCurrentThread();
+  }
+  else
+    g_debug ("failed to register current thread, cannot draw");
+}
+
+void
+gst_gl_window_run_loop (GstGLWindow * window)
+{
+  GstGLWindowPrivate *priv = window->priv;
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+  g_debug ("begin loop\n");
+
+  if (priv->internal_win_id != nil) {
+    [NSApp setDelegate:priv->internal_win_id];
+    [NSApp run];
+    [priv->internal_win_id release];
+  }
+
+  [pool release];
+
+  g_debug ("end loop\n");
+}
+
+/* Thread safe */
+void
+gst_gl_window_quit_loop (GstGLWindow * window, GstGLWindowCB callback,
+    gpointer data)
+{
+  if (window) {
+    if (GSRegisterCurrentThread()) {
+      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+      AppThreadPerformer* app_thread_performer = [[AppThreadPerformer alloc] initWithCallback:callback userData:data];
+      [app_thread_performer performSelectorOnMainThread:@selector(stopApp) withObject:nil waitUntilDone:YES];
+
+      [pool release];
+
+      GSUnregisterCurrentThread();
+    }
+    else
+      g_debug ("failed to register current thread, application thread is lost");
+  }
+}
+
+/* Thread safe */
+void
+gst_gl_window_send_message (GstGLWindow * window, GstGLWindowCB callback,
+    gpointer data)
+{
+  if (window) {
+    GstGLWindowPrivate *priv = window->priv;
+    if (GSRegisterCurrentThread()) {
+      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+      AppThreadPerformer* app_thread_performer = [[AppThreadPerformer alloc] initWithAll:callback userData:data private:priv];
+      [app_thread_performer performSelectorOnMainThread:@selector(sendToApp) withObject:nil waitUntilDone:YES];
+
+      [pool release];
+
+      GSUnregisterCurrentThread();
+    }
+    else
+      g_debug ("failed to register current thread, cannot send message");
+  }
+}
+
+
+/* ============================================================= */
+/*                                                               */
+/*                 GstGLNSWindow implementation                  */
+/*                                                               */
+/* ============================================================= */
+
+@implementation GstGLNSWindow
+
+- (id) initWithContentRect: (NSRect) contentRect
+               styleMask: (unsigned int) styleMask
+    backing: (NSBackingStoreType) bufferingType
+    defer: (BOOL) flag screen: (NSScreen *) aScreen
+    gstWin: (GstGLWindowPrivate *) priv {
+
+  m_isClosed = NO;
+  m_priv = priv;
+  NSOpenGLView *glView = nil;
+  NSOpenGLPixelFormat *fmt = nil;
+  NSOpenGLContext *glContext = nil;
+  NSOpenGLPixelFormatAttribute attribs[] = {
+    NSOpenGLPFAAccelerated,
+    NSOpenGLPFANoRecovery,
+    NSOpenGLPFADoubleBuffer,
+    NSOpenGLPFAColorSize, 24,
+    NSOpenGLPFAAlphaSize, 8,
+    NSOpenGLPFADepthSize, 24,
+    NSOpenGLPFAWindow,
+    0
+  };
+
+  self = [super initWithContentRect: contentRect
+               styleMask: styleMask backing: bufferingType
+               defer: flag screen:aScreen];
+
+  [self setReleasedWhenClosed:NO];
+
+  g_debug ("initializing GstGLNSWindow");
+
+  glView = [NSOpenGLView alloc];
+
+  [self setContentView:glView];
+
+  fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
+
+  if (!fmt) {
+    g_warning ("cannot create NSOpenGLPixelFormat");
+    return nil;
+  }
+
+  glView = [glView initWithFrame:contentRect pixelFormat:fmt];
+
+  glContext = [glView openGLContext];
+
+  /* OpenGL context is made current only one time threre.
+   * Indeed, all OpenGL calls are made in only one thread,
+   * the Application thread */
+  [glContext makeCurrentContext];
+
+  [glContext update];
+
+  /* Back and front buffers are swapped only during the vertical retrace of the monitor.
+   * Discarded if you configured your driver to Never-use-V-Sync.
+   */
+  NS_DURING {
+    if (glContext) {
+      long swapInterval = 1;
+      [[glView openGLContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
+    }
+  } NS_HANDLER {
+     g_debug ("your back-end does not implement NSOpenglContext::setValues");
+  }
+  NS_ENDHANDLER
+
+  g_debug ("opengl GstGLNSWindow initialized: %d x %d",
+    (int) contentRect.size.width, (int) contentRect.size.height);
+
+  [self setTitle:@"OpenGL renderer"];
+
+  return self;
+}
+
+- (BOOL) isClosed {
+  return m_isClosed;
+}
+
+- (BOOL) windowShouldClose:(id)sender {
+  g_debug ("user clicked the close button");
+  m_isClosed = YES;
+  if (m_priv->close_cb)
+    m_priv->close_cb (m_priv->close_data);
+  m_priv->draw_cb = NULL;
+  m_priv->draw_data = NULL;
+  m_priv->resize_cb = NULL;
+  m_priv->resize_data = NULL;
+  m_priv->close_cb = NULL;
+  m_priv->close_data = NULL;
+  return YES;
+}
+
+- (void) windowDidResize: (NSNotification *) not {
+  NSLog(@"windowDidResize"); //FIXME: seems to be not reached on win32
+  if (m_priv->resize_cb) {
+    NSWindow *window = [not object];
+    NSRect rect = [window frame];
+    m_priv->resize_cb (m_priv->resize_data, rect.size.width, rect.size.height);
+  }
+}
+
+- (void) applicationDidFinishLaunching: (NSNotification *) not {
+}
+
+- (void) applicationWillFinishLaunching: (NSNotification *) not {
+}
+
+- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app {
+  /* the application is manually stopped by calling stopApp on the AppThreadPerformer */
+  return NO;
+}
+
+- (void) applicationWillTerminate:(NSNotification *)aNotification {
+}
+
+@end
+
+
+/* ============================================================= */
+/*                                                               */
+/*               AppThreadPerformer implementation               */
+/*                                                               */
+/* ============================================================= */
+
+@implementation AppThreadPerformer
+
+- (id) initWithPrivate: (GstGLWindowPrivate *) priv {
+  m_priv = priv;
+  m_callback = NULL;
+  m_data = NULL;
+  return self;
+}
+
+- (id) initWithCallback: (GstGLWindowCB) callback userData: (gpointer) data {
+  m_priv = NULL;
+  m_callback = callback;
+  m_data = data;
+  return self;
+}
+
+- (id) initWithAll: (GstGLWindowCB) callback userData: (gpointer) data private: (GstGLWindowPrivate *) priv {
+  m_priv = priv;
+  m_callback = callback;
+  m_data = data;
+  return self;
+}
+
+- (void) updateWindow {
+  if ([NSApp isRunning]) {
+
+    if (![m_priv->internal_win_id isClosed]) {
+      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+      if (!m_priv->visible) {
+          g_debug ("make the window available");
+          [m_priv->internal_win_id makeMainWindow];
+          //[m_priv->internal_win_id center];
+          [m_priv->internal_win_id orderFront:m_priv->internal_win_id];
+          m_priv->visible = TRUE;
+      }
+
+      if (m_priv->parent) {
+        NSRect parent_rect = [[m_priv->internal_win_id parentWindow] frame];
+        NSRect rect = [m_priv->internal_win_id frame];
+
+        if (rect.origin.x != parent_rect.origin.x || rect.origin.y != parent_rect.origin.y ||
+            rect.size.width != parent_rect.size.width || rect.size.height != parent_rect.size.height) {
+
+          [m_priv->internal_win_id setFrame:parent_rect display:YES];
+
+          g_debug ("parent resize:  %d, %d, %d, %d\n",
+            (int) parent_rect.origin.x, (int) parent_rect.origin.y,
+            (int) parent_rect.size.width, (int) parent_rect.size.height);
+        }
+      }
+
+      if ([[m_priv->internal_win_id contentView] lockFocusIfCanDraw]) {
+        /* draw opengl scene in the back buffer */
+        m_priv->draw_cb (m_priv->draw_data);
+        /* Copy the back buffer to the front buffer */
+        [[[m_priv->internal_win_id contentView] openGLContext] flushBuffer];
+        [[m_priv->internal_win_id contentView] unlockFocus];
+      }
+
+      [pool release];
+    }
+  }
+}
+
+- (void) sendToApp {
+  if ([NSApp isRunning]) {
+    if (![m_priv->internal_win_id isClosed]) {
+      m_callback (m_data);
+    }
+  }
+}
+
+- (void) setWindow: (NSWindow *) window {
+  if ([NSApp isRunning]) {
+
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+    [m_priv->internal_win_id setParentWindow:window];
+
+    m_priv->parent = window;
+
+    [m_priv->internal_win_id setFrame:[window frame] display:YES];
+
+    [pool release];
+  }
+}
+
+- (void) stopApp {
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+  if ([NSApp isRunning])
+    [NSApp stop:self];
+
+  [pool release];
+}
+
+@end