| /* |
| * GStreamer |
| * Copyright (C) 2015 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., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <Cocoa/Cocoa.h> |
| |
| #include <gst/gl/cocoa/gstgldisplay_cocoa.h> |
| |
| GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug); |
| #define GST_CAT_DEFAULT gst_gl_display_debug |
| |
| G_DEFINE_TYPE (GstGLDisplayCocoa, gst_gl_display_cocoa, GST_TYPE_GL_DISPLAY); |
| |
| static void gst_gl_display_cocoa_finalize (GObject * object); |
| static guintptr gst_gl_display_cocoa_get_handle (GstGLDisplay * display); |
| |
| #if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 |
| #define NSEventMaskAny NSAnyEventMask |
| #endif |
| |
| /* Define this if the GLib patch from |
| * https://bugzilla.gnome.org/show_bug.cgi?id=741450 |
| * is used |
| */ |
| #ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION |
| |
| static GstGLDisplayCocoa *singleton = NULL; |
| static gint nsapp_source_id = 0; |
| static GMutex nsapp_lock; |
| static GCond nsapp_cond; |
| |
| static gboolean |
| gst_gl_display_cocoa_nsapp_iteration (gpointer data) |
| { |
| NSEvent *event = nil; |
| |
| if (![NSThread isMainThread]) { |
| GST_WARNING ("NSApp iteration not running in the main thread"); |
| return FALSE; |
| } |
| |
| |
| while ((event = ([NSApp nextEventMatchingMask:NSEventMaskAny |
| untilDate:[NSDate dateWithTimeIntervalSinceNow:0.05] |
| inMode:NSDefaultRunLoopMode dequeue:YES])) != nil) { |
| [NSApp sendEvent:event]; |
| } |
| |
| return TRUE; |
| } |
| |
| static void |
| gst_gl_display_cocoa_open_and_attach_source (gpointer data) |
| { |
| if ([NSThread isMainThread]) { |
| /* The sharedApplication class method initializes |
| * the display environment and connects your program |
| * to the window server and the display server. |
| * It has to be done in the main thread. |
| */ |
| [NSApplication sharedApplication]; |
| |
| GST_DEBUG ("Custom NSApp initialization done"); |
| |
| nsapp_source_id = g_timeout_add (60, gst_gl_display_cocoa_nsapp_iteration, |
| NULL); |
| |
| GST_DEBUG ("NSApp iteration loop attached, id %d", nsapp_source_id); |
| } |
| } |
| |
| static gboolean |
| gst_gl_display_cocoa_init_nsapp (gpointer data) |
| { |
| g_mutex_lock (&nsapp_lock); |
| |
| gst_gl_display_cocoa_open_and_attach_source (data); |
| |
| g_cond_signal (&nsapp_cond); |
| g_mutex_unlock (&nsapp_lock); |
| |
| return FALSE; |
| } |
| |
| static GstGLDisplayCocoa * |
| gst_gl_display_cocoa_setup_nsapp (gpointer data) |
| { |
| GMainContext *context = g_main_context_default (); |
| gint delta_ms = 0; |
| |
| g_mutex_lock (&nsapp_lock); |
| |
| if (singleton) { |
| GST_DEBUG ("Get existing display"); |
| singleton = gst_object_ref (singleton); |
| g_mutex_unlock (&nsapp_lock); |
| return singleton; |
| } |
| |
| if (NSApp != nil && !singleton) { |
| GstGLDisplayCocoa *ret = g_object_new (GST_TYPE_GL_DISPLAY_COCOA, NULL); |
| gst_object_ref_sink (ret); |
| g_mutex_unlock (&nsapp_lock); |
| return ret; |
| } |
| |
| /* All application have to start with [NSApplication sharedApplication] |
| * so if NSApp is nil here let's assume this is a debugging application |
| * that runs a glib main loop. */ |
| g_assert (NSApp == nil); |
| |
| GST_DEBUG ("The application has not initialized NSApp"); |
| |
| if ([NSThread isMainThread]) { |
| |
| GST_DEBUG ("Setting up NSApp from the main thread"); |
| if (g_main_context_is_owner (context)) { |
| GST_DEBUG ("The main thread own the context"); |
| gst_gl_display_cocoa_open_and_attach_source (data); |
| } else if (g_main_context_acquire (context)) { |
| GST_DEBUG ("The main loop should be shortly running in the main thread"); |
| gst_gl_display_cocoa_open_and_attach_source (data); |
| g_main_context_release (context); |
| } else { |
| GST_WARNING ("Main loop running in another thread"); |
| } |
| } else { |
| |
| GST_DEBUG ("Setting up NSApp not from the main thread"); |
| |
| if (g_main_context_is_owner (context)) { |
| GST_WARNING ("Default context not own by the main thread"); |
| delta_ms = -1; |
| } else if (g_main_context_acquire (context)) { |
| GST_DEBUG ("The main loop should be shortly running in the main thread"); |
| delta_ms = 1000; |
| g_main_context_release (context); |
| } else { |
| GST_DEBUG ("Main loop running in main thread"); |
| delta_ms = 500; |
| } |
| |
| if (delta_ms > 0) { |
| gint64 end_time = g_get_monotonic_time () + delta_ms * 1000;; |
| g_idle_add_full (G_PRIORITY_HIGH, gst_gl_display_cocoa_init_nsapp, data, NULL); |
| g_cond_wait_until (&nsapp_cond, &nsapp_lock, end_time); |
| } |
| } |
| |
| if (NSApp == nil) { |
| GST_ERROR ("Custom NSApp initialization failed"); |
| } else { |
| GST_DEBUG ("Create display"); |
| singleton = g_object_new (GST_TYPE_GL_DISPLAY_COCOA, NULL); |
| gst_object_ref_sink (singleton); |
| } |
| |
| g_mutex_unlock (&nsapp_lock); |
| |
| return singleton; |
| } |
| |
| #endif |
| |
| static void |
| gst_gl_display_cocoa_class_init (GstGLDisplayCocoaClass * klass) |
| { |
| GST_GL_DISPLAY_CLASS (klass)->get_handle = |
| GST_DEBUG_FUNCPTR (gst_gl_display_cocoa_get_handle); |
| |
| G_OBJECT_CLASS (klass)->finalize = gst_gl_display_cocoa_finalize; |
| } |
| |
| static void |
| gst_gl_display_cocoa_init (GstGLDisplayCocoa * display_cocoa) |
| { |
| GstGLDisplay *display = (GstGLDisplay *) display_cocoa; |
| display->type = GST_GL_DISPLAY_TYPE_COCOA; |
| } |
| |
| static void |
| gst_gl_display_cocoa_finalize (GObject * object) |
| { |
| #ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION |
| g_mutex_lock (&nsapp_lock); |
| if (singleton) { |
| GST_DEBUG ("Destroy display"); |
| singleton = NULL; |
| if (nsapp_source_id) { |
| GST_DEBUG ("Remove NSApp loop iteration, id %d", nsapp_source_id); |
| g_source_remove (nsapp_source_id); |
| } |
| nsapp_source_id = 0; |
| g_mutex_unlock (&nsapp_lock); |
| } |
| g_mutex_unlock (&nsapp_lock); |
| #endif |
| |
| G_OBJECT_CLASS (gst_gl_display_cocoa_parent_class)->finalize (object); |
| } |
| |
| /** |
| * gst_gl_display_cocoa_new: |
| * |
| * Create a new #GstGLDisplayCocoa. |
| * |
| * Returns: (transfer full): a new #GstGLDisplayCocoa or %NULL |
| */ |
| GstGLDisplayCocoa * |
| gst_gl_display_cocoa_new (void) |
| { |
| GstGLDisplayCocoa *display; |
| |
| GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay"); |
| |
| #ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION |
| display = gst_gl_display_cocoa_setup_nsapp (NULL); |
| #else |
| display = g_object_new (GST_TYPE_GL_DISPLAY_COCOA, NULL); |
| gst_object_ref_sink (display); |
| #endif |
| |
| return display; |
| } |
| |
| static guintptr |
| gst_gl_display_cocoa_get_handle (GstGLDisplay * display) |
| { |
| return (guintptr) NSApp; |
| } |