gl/cocoa: Call UI related API from the application main thread

This commit is contained in:
Sebastian Dröge 2014-09-26 14:21:46 +03:00
parent 2173d34462
commit 66cb4166d3
2 changed files with 106 additions and 116 deletions

View file

@ -85,7 +85,7 @@ gst_gl_window_cocoa_nsapp_iteration (gpointer data)
if ([NSThread isMainThread]) { if ([NSThread isMainThread]) {
while ((event = ([NSApp nextEventMatchingMask:NSAnyEventMask while ((event = ([NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate dateWithTimeIntervalSinceNow:0.5] untilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]
inMode:NSDefaultRunLoopMode dequeue:YES])) != nil) { inMode:NSDefaultRunLoopMode dequeue:YES])) != nil) {
[NSApp sendEvent:event]; [NSApp sendEvent:event];
@ -135,7 +135,7 @@ gst_gl_context_cocoa_class_init (GstGLContextCocoaClass * klass)
if ([NSThread isMainThread]) { if ([NSThread isMainThread]) {
/* In the main thread so just do the call now */ /* In the main thread so just do the call now */
/* The sharedApplication class method initializes /* The sharedApplication class method initializes
* the display environment and connects your program * the display environment and connects your program
* to the window server and the display server * to the window server and the display server
@ -201,17 +201,11 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
GstGLContextCocoaPrivate *priv = context_cocoa->priv; GstGLContextCocoaPrivate *priv = context_cocoa->priv;
GstGLWindow *window = gst_gl_context_get_window (context); GstGLWindow *window = gst_gl_context_get_window (context);
GstGLWindowCocoa *window_cocoa = GST_GL_WINDOW_COCOA (window); GstGLWindowCocoa *window_cocoa = GST_GL_WINDOW_COCOA (window);
GstGLNSView *glView = nil; __block NSOpenGLContext *glContext = nil;
NSWindow *window_handle;
NSRect rect; #ifndef GNUSTEP
NSAutoreleasePool *pool; priv->source_id = g_timeout_add (200, gst_gl_window_cocoa_nsapp_iteration, NULL);
NSOpenGLPixelFormat *fmt = nil; #endif
NSOpenGLContext *glContext = nil;
NSOpenGLPixelFormatAttribute attribs[] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAAccumSize, 32,
0
};
priv->gl_context = nil; priv->gl_context = nil;
if (other_context) if (other_context)
@ -219,52 +213,64 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
else else
priv->external_gl_context = NULL; priv->external_gl_context = NULL;
#ifdef GNUSTEP dispatch_sync (dispatch_get_main_queue (), ^{
GSRegisterCurrentThread(); NSAutoreleasePool *pool;
#endif NSOpenGLPixelFormat *fmt = nil;
GstGLNSView *glView = nil;
NSOpenGLPixelFormatAttribute attribs[] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAAccumSize, 32,
0
};
NSRect rect;
NSWindow *window_handle;
pool = [[NSAutoreleasePool alloc] init]; pool = [[NSAutoreleasePool alloc] init];
#ifdef GNUSTEP #ifdef GNUSTEP
[NSApplication sharedApplication]; [NSApplication sharedApplication];
#endif #endif
rect.origin.x = 0;
rect.origin.y = 0;
rect.size.width = 320;
rect.size.height = 240;
rect.origin.x = 0; gst_gl_window_cocoa_create_window (window_cocoa, rect);
rect.origin.y = 0; window_handle = (NSWindow *) gst_gl_window_get_window_handle (window);
rect.size.width = 320;
rect.size.height = 240;
gst_gl_window_cocoa_create_window (window_cocoa, rect); fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
window_handle = (NSWindow *) gst_gl_window_get_window_handle (window); if (!fmt) {
gst_object_unref (window);
GST_WARNING ("cannot create NSOpenGLPixelFormat");
return;
}
glView = [GstGLNSView alloc]; glView = [[GstGLNSView alloc] initWithFrame:window_cocoa rect:rect];
fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; [window_handle setContentView:glView];
if (!fmt) {
gst_object_unref (window);
GST_WARNING ("cannot create NSOpenGLPixelFormat");
return FALSE;
}
glView = [glView initWithFrame:window_cocoa rect:rect];
[window_handle setContentView:glView];
#ifndef GNUSTEP #ifndef GNUSTEP
glContext = [[NSOpenGLContext alloc] initWithFormat:fmt glContext = [[NSOpenGLContext alloc] initWithFormat:fmt
shareContext:context_cocoa->priv->external_gl_context]; shareContext:context_cocoa->priv->external_gl_context];
GST_DEBUG ("NSOpenGL context created: %"G_GUINTPTR_FORMAT, (guintptr) glContext); GST_DEBUG ("NSOpenGL context created: %"G_GUINTPTR_FORMAT, (guintptr) glContext);
context_cocoa->priv->gl_context = glContext; context_cocoa->priv->gl_context = glContext;
[glContext setView:glView]; [glContext setView:glView];
#else #else
/* FIXME try to make context sharing work in GNUstep */ /* FIXME try to make context sharing work in GNUstep */
context_cocoa->priv->gl_context = glContext; context_cocoa->priv->gl_context = glContext;
#endif #endif
[pool release];
});
if (!glContext) {
g_source_remove (priv->source_id);
priv->source_id = 0;
return FALSE;
}
/* OpenGL context is made current only one time threre. /* OpenGL context is made current only one time threre.
* Indeed, all OpenGL calls are made in only one thread, * Indeed, all OpenGL calls are made in only one thread,
@ -290,14 +296,7 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
} }
NS_ENDHANDLER NS_ENDHANDLER
GST_DEBUG ("opengl GstGLNSWindow initialized: %d x %d\n", GST_DEBUG ("opengl GstGLNSWindow initialized");
(gint) rect.size.width, (gint) rect.size.height);
[pool release];
#ifndef GNUSTEP
priv->source_id = g_timeout_add_seconds (1, gst_gl_window_cocoa_nsapp_iteration, NULL);
#endif
gst_object_unref (window); gst_object_unref (window);
@ -307,6 +306,14 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
static void static void
gst_gl_context_cocoa_destroy_context (GstGLContext *context) gst_gl_context_cocoa_destroy_context (GstGLContext *context)
{ {
GstGLContextCocoa *context_cocoa = GST_GL_CONTEXT_COCOA (context);
GstGLContextCocoaPrivate *priv = context_cocoa->priv;
/* FIXME: Need to release context and other things? */
if (priv->source_id) {
g_source_remove (priv->source_id);
priv->source_id = 0;
}
} }
static guintptr static guintptr

View file

@ -123,20 +123,20 @@ gst_gl_window_cocoa_new (void)
return window; return window;
} }
/* Must be called from the main thread */
gboolean gboolean
gst_gl_window_cocoa_create_window (GstGLWindowCocoa *window_cocoa, NSRect rect) gst_gl_window_cocoa_create_window (GstGLWindowCocoa *window_cocoa, NSRect rect)
{ {
GstGLWindowCocoaPrivate *priv = window_cocoa->priv; GstGLWindowCocoaPrivate *priv = window_cocoa->priv;
/* FIXME: This should probably be done in the application main thread */
priv->internal_win_id = [[GstGLNSWindow alloc] initWithContentRect:rect styleMask: priv->internal_win_id = [[GstGLNSWindow alloc] initWithContentRect:rect styleMask:
(NSTitledWindowMask | NSClosableWindowMask | (NSTitledWindowMask | NSClosableWindowMask |
NSResizableWindowMask | NSMiniaturizableWindowMask) NSResizableWindowMask | NSMiniaturizableWindowMask)
backing: NSBackingStoreBuffered defer: NO screen: nil gstWin: window_cocoa]; backing: NSBackingStoreBuffered defer: NO screen: nil gstWin: window_cocoa];
GST_DEBUG ("NSWindow id: %"G_GUINTPTR_FORMAT, (guintptr) priv->internal_win_id); GST_DEBUG ("NSWindow id: %"G_GUINTPTR_FORMAT, (guintptr) priv->internal_win_id);
[NSApp setDelegate: priv->internal_win_id]; [NSApp setDelegate: priv->internal_win_id];
return TRUE; return TRUE;
} }
@ -175,21 +175,6 @@ gst_gl_window_cocoa_get_window_handle (GstGLWindow *window)
return (guintptr) GST_GL_WINDOW_COCOA (window)->priv->internal_win_id; return (guintptr) GST_GL_WINDOW_COCOA (window)->priv->internal_win_id;
} }
static void
set_window_handle_cb (gpointer data)
{
GstGLWindowCocoa * window_cocoa = data;
NSView *view = [window_cocoa->priv->internal_win_id contentView];
/* FIXME: This should probably be in the application main thread! */
[window_cocoa->priv->internal_win_id orderOut:window_cocoa->priv->internal_win_id];
[window_cocoa->priv->external_view addSubview: view];
[view setFrame: [window_cocoa->priv->external_view bounds]];
[view setAutoresizingMask: NSViewWidthSizable|NSViewHeightSizable];
}
static void static void
gst_gl_window_cocoa_set_window_handle (GstGLWindow * window, guintptr handle) gst_gl_window_cocoa_set_window_handle (GstGLWindow * window, guintptr handle)
{ {
@ -200,16 +185,6 @@ gst_gl_window_cocoa_set_window_handle (GstGLWindow * window, guintptr handle)
priv = window_cocoa->priv; priv = window_cocoa->priv;
if (priv->internal_win_id) { if (priv->internal_win_id) {
GstGLContextCocoa *context = (GstGLContextCocoa *) gst_gl_window_get_context (window);
if (context) {
if (context->priv->source_id) {
g_source_remove (context->priv->source_id);
context->priv->source_id = 0;
}
gst_object_unref (context);
}
if (handle) { if (handle) {
priv->external_view = (NSView *) handle; priv->external_view = (NSView *) handle;
priv->visible = TRUE; priv->visible = TRUE;
@ -220,7 +195,15 @@ gst_gl_window_cocoa_set_window_handle (GstGLWindow * window, guintptr handle)
} }
gst_gl_window_send_message (window, (GstGLWindowCB) set_window_handle_cb, window_cocoa); dispatch_async (dispatch_get_main_queue (), ^{
NSView *view = [window_cocoa->priv->internal_win_id contentView];
[window_cocoa->priv->internal_win_id orderOut:window_cocoa->priv->internal_win_id];
[window_cocoa->priv->external_view addSubview: view];
[view setFrame: [window_cocoa->priv->external_view bounds]];
[view setAutoresizingMask: NSViewWidthSizable|NSViewHeightSizable];
});
} else { } else {
/* no internal window yet so delay it to the next drawing */ /* no internal window yet so delay it to the next drawing */
priv->external_view = (NSView*) handle; priv->external_view = (NSView*) handle;
@ -250,39 +233,38 @@ draw_cb (gpointer data)
} }
if (!priv->external_view && !priv->visible) { if (!priv->external_view && !priv->visible) {
gint x = 0; dispatch_sync (dispatch_get_main_queue (), ^{
gint y = 0; NSRect mainRect = [[NSScreen mainScreen] visibleFrame];
NSRect windowRect = [priv->internal_win_id frame];
gint x = 0;
gint y = 0;
/* FIXME: This should probably be done from the application main thread */ GST_DEBUG ("main screen rect: %d %d %d %d\n", (int) mainRect.origin.x,
(int) mainRect.origin.y, (int) mainRect.size.width,
(int) mainRect.size.height);
NSRect mainRect = [[NSScreen mainScreen] visibleFrame]; windowRect.origin.x += x;
NSRect windowRect = [priv->internal_win_id frame]; windowRect.origin.y += mainRect.size.height > y ? (mainRect.size.height - y) * 0.5 : y;
windowRect.size.width = draw_data->width;
windowRect.size.height = draw_data->height;
GST_DEBUG ("main screen rect: %d %d %d %d\n", (int) mainRect.origin.x, GST_DEBUG ("window rect: %d %d %d %d\n", (int) windowRect.origin.x,
(int) mainRect.origin.y, (int) mainRect.size.width, (int) windowRect.origin.y, (int) windowRect.size.width,
(int) mainRect.size.height); (int) windowRect.size.height);
windowRect.origin.x += x; x += 20;
windowRect.origin.y += mainRect.size.height > y ? (mainRect.size.height - y) * 0.5 : y; y += 20;
windowRect.size.width = draw_data->width;
windowRect.size.height = draw_data->height;
GST_DEBUG ("window rect: %d %d %d %d\n", (int) windowRect.origin.x,
(int) windowRect.origin.y, (int) windowRect.size.width,
(int) windowRect.size.height);
x += 20;
y += 20;
#ifndef GNUSTEP #ifndef GNUSTEP
[priv->internal_win_id setFrame:windowRect display:NO]; [priv->internal_win_id setFrame:windowRect display:NO];
GST_DEBUG ("make the window available\n"); GST_DEBUG ("make the window available\n");
[priv->internal_win_id makeMainWindow]; [priv->internal_win_id makeMainWindow];
#endif #endif
[priv->internal_win_id orderFrontRegardless]; [priv->internal_win_id orderFrontRegardless];
/*[priv->internal_win_id setViewsNeedDisplay:YES]; */ [priv->internal_win_id setViewsNeedDisplay:YES];
});
priv->visible = TRUE; priv->visible = TRUE;
} }
@ -383,6 +365,7 @@ gst_gl_window_cocoa_send_message_async (GstGLWindow * window,
/* */ /* */
/* =============================================================*/ /* =============================================================*/
/* Must be called from the main thread */
@implementation GstGLNSWindow @implementation GstGLNSWindow
- (id) initWithContentRect: (NSRect) contentRect - (id) initWithContentRect: (NSRect) contentRect
@ -446,7 +429,6 @@ close_window_cb (gpointer data)
window = GST_GL_WINDOW (window_cocoa); window = GST_GL_WINDOW (window_cocoa);
[window_cocoa->priv->internal_win_id setClosed];
if (window->close) { if (window->close) {
window->close (window->close_data); window->close (window->close_data);
} }
@ -456,7 +438,8 @@ close_window_cb (gpointer data)
- (BOOL) windowShouldClose:(id)sender { - (BOOL) windowShouldClose:(id)sender {
GST_DEBUG ("user clicked the close button\n"); GST_DEBUG ("user clicked the close button\n");
gst_gl_window_send_message (GST_GL_WINDOW (window_cocoa), (GstGLWindowCB) close_window_cb, window_cocoa); [window_cocoa->priv->internal_win_id setClosed];
gst_gl_window_send_message_async (GST_GL_WINDOW (window_cocoa), (GstGLWindowCB) close_window_cb, gst_object_ref (window_cocoa), (GDestroyNotify) gst_object_unref);
return YES; return YES;
} }
@ -496,9 +479,9 @@ close_window_cb (gpointer data)
@implementation GstGLNSView @implementation GstGLNSView
/* Must be called from the application main thread */
- (id)initWithFrame:(GstGLWindowCocoa *)window rect:(NSRect)contentRect { - (id)initWithFrame:(GstGLWindowCocoa *)window rect:(NSRect)contentRect {
/* FIXME: This should probably be done from the application main thread */
self = [super initWithFrame: contentRect]; self = [super initWithFrame: contentRect];
window_cocoa = window; window_cocoa = window;
@ -556,7 +539,7 @@ resize_cb (gpointer data)
NSRect bounds = [self bounds]; NSRect bounds = [self bounds];
NSRect visibleRect = [self visibleRect]; NSRect visibleRect = [self visibleRect];
NSSize frameSize = [self frame].size; NSSize frameSize = [self frame].size;
struct resize resize_data; struct resize *resize_data = g_new (struct resize, 1);
GST_DEBUG_OBJECT (window, "Window resized: bounds %lf %lf %lf %lf, " GST_DEBUG_OBJECT (window, "Window resized: bounds %lf %lf %lf %lf, "
"visibleRect %lf %lf %lf %lf, frame size %lf %lf", "visibleRect %lf %lf %lf %lf, frame size %lf %lf",
@ -566,12 +549,12 @@ resize_cb (gpointer data)
visibleRect.size.width, visibleRect.size.height, visibleRect.size.width, visibleRect.size.height,
frameSize.width, frameSize.height); frameSize.width, frameSize.height);
resize_data.window = window_cocoa; resize_data->window = window_cocoa;
resize_data.bounds = bounds; resize_data->bounds = bounds;
resize_data.visibleRect = visibleRect; resize_data->visibleRect = visibleRect;
resize_data.frameSize = frameSize; resize_data->frameSize = frameSize;
gst_gl_window_send_message (GST_GL_WINDOW (window_cocoa), (GstGLWindowCB) resize_cb, &resize_data); gst_gl_window_send_message_async (GST_GL_WINDOW (window_cocoa), (GstGLWindowCB) resize_cb, resize_data, (GDestroyNotify) g_free);
} }
} }