summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefano Pigozzi <stefano.pigozzi@gmail.com>2013-03-04 14:23:06 +0100
committerStefano Pigozzi <stefano.pigozzi@gmail.com>2013-05-12 15:27:54 +0200
commit134f3e97bf482b75c0eccbe5ac943a2a1d5a4ad6 (patch)
tree98bac431df2697072238864e48a0380d3b1745ff
parentafdc9c4ae2e69a9ced6c3c6580df19edfedea36a (diff)
downloadmpv-134f3e97bf482b75c0eccbe5ac943a2a1d5a4ad6.tar.bz2
mpv-134f3e97bf482b75c0eccbe5ac943a2a1d5a4ad6.tar.xz
OSX: run native event loop in a separate thread
This commit is a followup on the previous one and uses a solution I like more since it totally decouples the Cocoa code from mpv's core and tries to emulate a generic Cocoa application's lifecycle as much as possible without fighting the framework. mpv's main is executed in a pthread while the main thread runs the native cocoa event loop. All of the thread safety is mainly accomplished with additional logic in cocoa_common as to not increase complexity on the crossplatform parts of the code.
-rw-r--r--core/mplayer.c51
-rw-r--r--osdep/macosx_application.h17
-rw-r--r--osdep/macosx_application.m107
-rw-r--r--osdep/macosx_application_objc.h6
-rw-r--r--video/out/cocoa_common.h5
-rw-r--r--video/out/cocoa_common.m324
-rw-r--r--video/out/gl_cocoa.c8
-rw-r--r--video/out/gl_common.h7
-rw-r--r--video/out/vo_opengl.c13
9 files changed, 341 insertions, 197 deletions
diff --git a/core/mplayer.c b/core/mplayer.c
index 2e79e80c14..89d463daa1 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -3803,33 +3803,6 @@ static void run_playloop(struct MPContext *mpctx)
execute_queued_seek(mpctx);
}
-static void run_playloop_opaque_callback(void *context)
-{
- run_playloop((struct MPContext *)context);
-}
-
-static int check_stop_play(void *context)
-{
- struct MPContext *mpctx = context;
- return mpctx->stop_play;
-}
-
-static void schedule_run_playloop(struct MPContext *mpctx)
-{
-
- #ifdef CONFIG_COCOA
- cocoa_run_loop_schedule(run_playloop_opaque_callback,
- check_stop_play,
- mpctx, // passed in as opaque type
- mpctx->input,
- mpctx->key_fifo);
- cocoa_run_runloop();
- #else
- while (!check_stop_play(mpctx))
- run_playloop(mpctx);
- #endif
-}
-
static int read_keys(void *ctx, int fd)
{
if (getch2(ctx))
@@ -3953,6 +3926,10 @@ static void init_input(struct MPContext *mpctx)
mp_input_add_key_fd(mpctx->input, 0, 1, read_keys, NULL, mpctx->key_fifo);
// Set the libstream interrupt callback
stream_set_interrupt_callback(mp_input_check_interrupt, mpctx->input);
+
+#ifdef CONFIG_COCOA
+ cocoa_set_state(mpctx->input, mpctx->key_fifo);
+#endif
}
static void open_subtitles_from_options(struct MPContext *mpctx)
@@ -4432,7 +4409,8 @@ goto_enable_cache: ;
if (mpctx->opts.pause)
pause_player(mpctx);
- schedule_run_playloop(mpctx);
+ while (!mpctx->stop_play)
+ run_playloop(mpctx);
mp_msg(MSGT_GLOBAL, MSGL_V, "EOF code: %d \n", mpctx->stop_play);
@@ -4621,11 +4599,6 @@ static void osdep_preinit(int *p_argc, char ***p_argv)
GetCpuCaps(&gCpuCaps);
-#ifdef CONFIG_COCOA
- init_cocoa_application();
- macosx_finder_args_preinit(p_argc, p_argv);
-#endif
-
#ifdef __MINGW32__
mp_get_converted_argv(p_argc, p_argv);
#endif
@@ -4654,7 +4627,7 @@ static void osdep_preinit(int *p_argc, char ***p_argv)
/* This preprocessor directive is a hack to generate a mplayer-nomain.o object
* file for some tools to link against. */
#ifndef DISABLE_MAIN
-int main(int argc, char *argv[])
+static int mpv_main(int argc, char *argv[])
{
osdep_preinit(&argc, &argv);
@@ -4747,4 +4720,14 @@ int main(int argc, char *argv[])
return 1;
}
+
+int main(int argc, char *argv[])
+{
+#ifdef CONFIG_COCOA
+ cocoa_main(mpv_main, argc, argv);
+#else
+ mpv_main(argc, argv);
+#endif
+}
+
#endif /* DISABLE_MAIN */
diff --git a/osdep/macosx_application.h b/osdep/macosx_application.h
index c2227ae05d..b0f7944512 100644
--- a/osdep/macosx_application.h
+++ b/osdep/macosx_application.h
@@ -22,9 +22,7 @@
struct input_ctx;
struct mp_fifo;
-// Playloop callback function pointer
-typedef void(*play_loop_callback)(void *);
-typedef int(*should_stop_callback)(void *);
+typedef int (*mpv_main_fn)(int, char**);
// Menu Keys identifing menu items
typedef enum {
@@ -35,22 +33,23 @@ typedef enum {
MPM_ZOOM,
} MPMenuKey;
+// multithreaded wrapper for mpv_main
+int cocoa_main(mpv_main_fn mpv_main, int argc, char *argv[]);
+
void cocoa_register_menu_item_action(MPMenuKey key, void* action);
// initializes Cocoa application
void init_cocoa_application(void);
void terminate_cocoa_application(void);
+void cocoa_autorelease_pool_alloc(void);
+void cocoa_autorelease_pool_drain(void);
// Runs the Cocoa Main Event Loop
void cocoa_run_runloop(void);
+void cocoa_stop_runloop(void);
void cocoa_post_fake_event(void);
-// Adds play_loop as a timer of the Main Cocoa Event Loop
-void cocoa_run_loop_schedule(play_loop_callback callback,
- should_stop_callback playback_stopped,
- void *context,
- struct input_ctx *input_context,
- struct mp_fifo *key_fifo);
+void cocoa_set_state(struct input_ctx *input_context, struct mp_fifo *key_fifo);
void macosx_finder_args_preinit(int *argc, char ***argv);
diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m
index 39439e9fde..206313d294 100644
--- a/osdep/macosx_application.m
+++ b/osdep/macosx_application.m
@@ -16,8 +16,10 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <pthread.h>
#include "talloc.h"
+#include "core/mp_msg.h"
#include "core/mp_fifo.h"
#include "core/input/input.h"
#include "core/input/keycodes.h"
@@ -25,10 +27,9 @@
#include "osdep/macosx_application_objc.h"
#include "video/out/osx_common.h"
-// 0.0001 seems too much and 0.01 too low, no idea why this works so well
-#define COCOA_MAGIC_TIMER_DELAY 0.001
-
static Application *app;
+static NSAutoreleasePool *pool;
+static pthread_t playback_thread_id;
@interface Application (PrivateMethods)
- (NSMenuItem *)menuItemWithParent:(NSMenu *)parent
@@ -54,12 +55,8 @@ static Application *app;
@synthesize argumentsList = _arguments_list;
@synthesize willStopOnOpenEvent = _will_stop_on_open_event;
-@synthesize callback = _callback;
-@synthesize shouldStopPlayback = _should_stop_playback;
-@synthesize context = _context;
@synthesize inputContext = _input_context;
@synthesize keyFIFO = _key_fifo;
-@synthesize callbackTimer = _callback_timer;
@synthesize menuItems = _menu_items;
- (id)init
@@ -119,32 +116,6 @@ static Application *app;
#undef _R
-- (void)call_callback
-{
- if (self.shouldStopPlayback(self.context)) {
- [NSApp stop:nil];
- cocoa_post_fake_event();
- } else {
- self.callback(self.context);
- }
-}
-
-- (void)schedule_timer
-{
- self.callbackTimer =
- [NSTimer timerWithTimeInterval:COCOA_MAGIC_TIMER_DELAY
- target:self
- selector:@selector(call_callback)
- userInfo:nil
- repeats:YES];
-
- [[NSRunLoop currentRunLoop] addTimer:self.callbackTimer
- forMode:NSDefaultRunLoopMode];
-
- [[NSRunLoop currentRunLoop] addTimer:self.callbackTimer
- forMode:NSEventTrackingRunLoopMode];
-}
-
- (void)stopPlayback
{
mplayer_put_key(app.keyFIFO, MP_KEY_CLOSE_WIN);
@@ -216,7 +187,8 @@ static Application *app;
self.files = [filesToOpen sortedArrayUsingSelector:@selector(compare:)];
if (self.willStopOnOpenEvent) {
- [NSApp stop:nil];
+ self.willStopOnOpenEvent = NO;
+ cocoa_stop_runloop();
} else {
[self handleFiles];
}
@@ -236,6 +208,41 @@ static Application *app;
}
@end
+struct playback_thread_ctx {
+ mpv_main_fn mpv_main;
+ int *argc;
+ char ***argv;
+};
+
+static void *playback_thread(void *ctx_obj)
+{
+ struct playback_thread_ctx *ctx = (struct playback_thread_ctx*) ctx_obj;
+ ctx->mpv_main(*ctx->argc, *ctx->argv);
+ cocoa_stop_runloop();
+ pthread_exit(NULL);
+}
+
+int cocoa_main(mpv_main_fn mpv_main, int argc, char *argv[])
+{
+ struct playback_thread_ctx ctx = {0};
+ ctx.mpv_main = mpv_main;
+ ctx.argc = &argc;
+ ctx.argv = &argv;
+
+ init_cocoa_application();
+ macosx_finder_args_preinit(&argc, &argv);
+ pthread_create(&playback_thread_id, NULL, playback_thread, &ctx);
+ cocoa_run_runloop();
+
+ // This should never be reached: cocoa_run_runloop blocks until the process
+ // is quit
+ mp_msg(MSGT_CPLAYER, MSGL_ERR, "There was either a problem initializing "
+ "Cocoa or the Runloop was stopped unexpectedly. Please report this "
+ "issues to a developer.\n");
+ pthread_join(playback_thread_id, NULL);
+ return 1;
+}
+
void cocoa_register_menu_item_action(MPMenuKey key, void* action)
{
[app registerSelector:(SEL)action forKey:key];
@@ -256,26 +263,38 @@ void terminate_cocoa_application(void)
[NSApp terminate:app];
}
-void cocoa_run_runloop(void)
+void cocoa_autorelease_pool_alloc(void)
+{
+ pool = [[NSAutoreleasePool alloc] init];
+}
+
+void cocoa_autorelease_pool_drain(void)
+{
+ [pool drain];
+}
+
+
+void cocoa_run_runloop()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSApp run];
[pool drain];
}
-void cocoa_run_loop_schedule(play_loop_callback callback,
- should_stop_callback stop_query,
- void *context,
- struct input_ctx *input_context,
- struct mp_fifo *key_fifo)
+void cocoa_stop_runloop(void)
+{
+ [NSApp performSelectorOnMainThread:@selector(stop:)
+ withObject:nil
+ waitUntilDone:true];
+ cocoa_post_fake_event();
+}
+
+void cocoa_set_state(struct input_ctx *input_context,
+ struct mp_fifo *key_fifo)
{
[NSApp setDelegate:app];
- app.callback = callback;
- app.context = context;
- app.shouldStopPlayback = stop_query;
app.inputContext = input_context;
app.keyFIFO = key_fifo;
- [app schedule_timer];
}
void cocoa_post_fake_event(void)
diff --git a/osdep/macosx_application_objc.h b/osdep/macosx_application_objc.h
index 340b2a9b1c..b569d60f25 100644
--- a/osdep/macosx_application_objc.h
+++ b/osdep/macosx_application_objc.h
@@ -22,16 +22,10 @@
@interface Application : NSObject<NSApplicationDelegate>
- (void)initialize_menu;
- (void)registerSelector:(SEL)selector forKey:(MPMenuKey)key;
-- (void)call_callback;
-- (void)schedule_timer;
- (void)stopPlayback;
-@property(nonatomic, assign) play_loop_callback callback;
-@property(nonatomic, assign) should_stop_callback shouldStopPlayback;
-@property(nonatomic, assign) void *context;
@property(nonatomic, assign) struct input_ctx *inputContext;
@property(nonatomic, assign) struct mp_fifo *keyFIFO;
-@property(nonatomic, retain) NSTimer *callbackTimer;
@property(nonatomic, retain) NSMutableDictionary *menuItems;
@property(nonatomic, retain) NSArray *files;
@property(nonatomic, retain) NSMutableArray *argumentsList;
diff --git a/video/out/cocoa_common.h b/video/out/cocoa_common.h
index 3450ebd547..823325ad15 100644
--- a/video/out/cocoa_common.h
+++ b/video/out/cocoa_common.h
@@ -24,7 +24,6 @@
struct vo_cocoa_state;
-bool vo_cocoa_gui_running(void);
void *vo_cocoa_glgetaddr(const char *s);
int vo_cocoa_init(struct vo *vo);
@@ -37,6 +36,7 @@ int vo_cocoa_config_window(struct vo *vo, uint32_t d_width,
uint32_t d_height, uint32_t flags,
int gl3profile);
+void vo_cocoa_set_current_context(struct vo *vo, bool current);
void vo_cocoa_swap_buffers(struct vo *vo);
int vo_cocoa_check_events(struct vo *vo);
void vo_cocoa_fullscreen(struct vo *vo);
@@ -44,6 +44,9 @@ void vo_cocoa_ontop(struct vo *vo);
void vo_cocoa_pause(struct vo *vo);
void vo_cocoa_resume(struct vo *vo);
+void vo_cocoa_register_resize_callback(struct vo *vo,
+ void (*cb)(struct vo *vo, int w, int h));
+
// returns an int to conform to the gl extensions from other platforms
int vo_cocoa_swap_interval(int enabled);
diff --git a/video/out/cocoa_common.m b/video/out/cocoa_common.m
index fba906c9b2..cc8f69bc1d 100644
--- a/video/out/cocoa_common.m
+++ b/video/out/cocoa_common.m
@@ -85,10 +85,7 @@ static bool RightAltPressed(NSEvent *event)
CFSTR("PreventUserIdleDisplaySleep")
#endif
-@interface GLMPlayerWindow : NSWindow <NSWindowDelegate> {
- struct vo *_vo;
-}
-- (void)setVideoOutput:(struct vo *)vo;
+@interface GLMPlayerWindow : NSWindow <NSWindowDelegate>
- (BOOL)canBecomeKeyWindow;
- (BOOL)canBecomeMainWindow;
- (void)fullscreen;
@@ -97,11 +94,54 @@ static bool RightAltPressed(NSEvent *event)
- (int)titleHeight;
- (NSRect)clipFrame:(NSRect)frame withContentAspect:(NSSize) aspect;
- (void)setContentSize:(NSSize)newSize keepCentered:(BOOL)keepCentered;
+@property(nonatomic, assign) struct vo *videoOutput;
@end
@interface GLMPlayerOpenGLView : NSView
@end
+struct vo_cocoa_input_queue {
+ NSMutableArray *fifo;
+};
+
+static int vo_cocoa_input_queue_free(void *ptr)
+{
+ struct vo_cocoa_input_queue *iq = ptr;
+ [iq->fifo release];
+ return 0;
+}
+
+static struct vo_cocoa_input_queue *vo_cocoa_input_queue_init(void *talloc_ctx)
+{
+ struct vo_cocoa_input_queue *iq = talloc_ptrtype(talloc_ctx, iq);
+ *iq = (struct vo_cocoa_input_queue) {
+ .fifo = [[NSMutableArray alloc] init],
+ };
+ talloc_set_destructor(iq, vo_cocoa_input_queue_free);
+ return iq;
+}
+
+static void cocoa_async_put_key(struct vo_cocoa_input_queue *iq, int key)
+{
+ @synchronized (iq->fifo) {
+ [iq->fifo addObject:[NSNumber numberWithInt:key]];
+ }
+}
+
+static int cocoa_sync_get_key(struct vo_cocoa_input_queue *iq)
+{
+ int r = -1;
+
+ @synchronized (iq->fifo) {
+ if ([iq->fifo count] > 0) {
+ r = [[iq->fifo objectAtIndex:0] intValue];
+ [iq->fifo removeObjectAtIndex:0];
+ }
+ }
+
+ return r;
+}
+
struct vo_cocoa_state {
GLMPlayerWindow *window;
NSOpenGLContext *glContext;
@@ -123,25 +163,32 @@ struct vo_cocoa_state {
NSInteger window_level;
+ struct aspect_data aspdat;
+
int display_cursor;
int cursor_timer;
int vo_cursor_autohide_delay;
bool did_resize;
+ bool did_async_resize;
bool out_fs_resize;
IOPMAssertionID power_mgmt_assertion;
CGFloat accumulated_scroll;
-};
-static int _instances = 0;
+ NSRecursiveLock *lock;
+ void (*resize_redraw)(struct vo *vo, int w, int h);
+
+ struct vo_cocoa_input_queue *input_queue;
+};
static struct vo_cocoa_state *vo_cocoa_init_state(struct vo *vo)
{
struct vo_cocoa_state *s = talloc_ptrtype(vo, s);
*s = (struct vo_cocoa_state){
.did_resize = NO,
+ .did_async_resize = NO,
.current_video_size = {0,0},
.previous_video_size = {0,0},
.windowed_mask = NSTitledWindowMask|NSClosableWindowMask|
@@ -153,8 +200,11 @@ static struct vo_cocoa_state *vo_cocoa_init_state(struct vo *vo)
.vo_cursor_autohide_delay = vo->opts->cursor_autohide_delay,
.power_mgmt_assertion = kIOPMNullAssertionID,
.accumulated_scroll = 0,
+ .lock = [[NSRecursiveLock alloc] init],
+ .input_queue = vo_cocoa_input_queue_init(s),
};
if (!vo->opts->border) s->windowed_mask = NSBorderlessWindowMask;
+
return s;
}
@@ -165,9 +215,16 @@ static bool supports_hidpi(NSView *view)
[view respondsToSelector:hdpi_selector];
}
-bool vo_cocoa_gui_running(void)
+static NSRect to_pixels(struct vo *vo, NSRect frame)
{
- return _instances > 0;
+ struct vo_cocoa_state *s = vo->cocoa;
+ NSView *view = [s->window contentView];
+
+ if (supports_hidpi(view)) {
+ return [view convertRectToBacking: frame];
+ } else {
+ return frame;
+ }
}
void *vo_cocoa_glgetaddr(const char *s)
@@ -208,7 +265,6 @@ int vo_cocoa_init(struct vo *vo)
{
vo->cocoa = vo_cocoa_init_state(vo);
vo->wakeup_period = 0.02;
- _instances++;
disable_power_management(vo);
return 1;
@@ -216,17 +272,17 @@ int vo_cocoa_init(struct vo *vo)
void vo_cocoa_uninit(struct vo *vo)
{
- struct vo_cocoa_state *s = vo->cocoa;
- CGDisplayShowCursor(kCGDirectMainDisplay);
- enable_power_management(vo);
- [NSApp setPresentationOptions:NSApplicationPresentationDefault];
-
- [s->window release];
- s->window = nil;
- [s->glContext release];
- s->glContext = nil;
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ struct vo_cocoa_state *s = vo->cocoa;
+ CGDisplayShowCursor(kCGDirectMainDisplay);
+ enable_power_management(vo);
+ [NSApp setPresentationOptions:NSApplicationPresentationDefault];
- _instances--;
+ [s->window release];
+ s->window = nil;
+ [s->glContext release];
+ s->glContext = nil;
+ });
}
void vo_cocoa_pause(struct vo *vo)
@@ -239,6 +295,13 @@ void vo_cocoa_resume(struct vo *vo)
disable_power_management(vo);
}
+void vo_cocoa_register_resize_callback(struct vo *vo,
+ void (*cb)(struct vo *vo, int w, int h))
+{
+ struct vo_cocoa_state *s = vo->cocoa;
+ s->resize_redraw = cb;
+}
+
static int current_screen_has_dock_or_menubar(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
@@ -296,23 +359,11 @@ void vo_cocoa_update_xinerama_info(struct vo *vo)
vo->xinerama_y = s->screen_frame.origin.y;
}
-int vo_cocoa_change_attributes(struct vo *vo)
-{
- return 0;
-}
-
static void resize_window(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
NSView *view = [s->window contentView];
- NSRect frame;
-
- if (supports_hidpi(view)) {
- frame = [view convertRectToBacking: [view frame]];
- } else {
- frame = [view frame];
- }
-
+ NSRect frame = to_pixels(vo, [view frame]);
vo->dwidth = frame.size.width;
vo->dheight = frame.size.height;
[s->glContext update];
@@ -402,8 +453,7 @@ static int create_window(struct vo *vo, uint32_t d_width, uint32_t d_height,
[glView release];
[s->window setAcceptsMouseMovedEvents:YES];
[s->glContext setView:glView];
- [s->glContext makeCurrentContext];
- [s->window setVideoOutput:vo];
+ s->window.videoOutput = vo;
[s->window setDelegate:s->window];
[s->window makeMainWindow];
@@ -433,58 +483,103 @@ static void update_window(struct vo *vo)
}
}
+static void resize_redraw(struct vo *vo, int width, int height)
+{
+ struct vo_cocoa_state *s = vo->cocoa;
+ if (s->resize_redraw) {
+ vo_cocoa_set_current_context(vo, true);
+ [s->glContext update];
+ s->resize_redraw(vo, width, height);
+ [s->glContext flushBuffer];
+ s->did_async_resize = YES;
+ vo_cocoa_set_current_context(vo, false);
+ }
+}
+
int vo_cocoa_config_window(struct vo *vo, uint32_t d_width,
uint32_t d_height, uint32_t flags,
int gl3profile)
{
- struct vo_cocoa_state *s = vo->cocoa;
- struct mp_vo_opts *opts = vo->opts;
+ __block int rv = 0;
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ struct vo_cocoa_state *s = vo->cocoa;
+ struct mp_vo_opts *opts = vo->opts;
- if (vo->config_count > 0) {
- NSPoint origin = [s->window frame].origin;
- vo->dx = origin.x;
- vo->dy = origin.y;
- }
+ if (vo->config_count > 0) {
+ NSPoint origin = [s->window frame].origin;
+ vo->dx = origin.x;
+ vo->dy = origin.y;
+ }
- update_state_sizes(s, d_width, d_height);
+ s->aspdat = vo->aspdat;
+ update_state_sizes(s, d_width, d_height);
- if (!(s->window || s->glContext)) {
- if (create_window(vo, d_width, d_height, flags, gl3profile) < 0)
- return -1;
- } else {
- update_window(vo);
- }
+ if (!(s->window || s->glContext)) {
+ if (create_window(vo, d_width, d_height, flags, gl3profile) < 0)
+ rv = -1;
+ } else {
+ update_window(vo);
+ }
- [s->window setFrameOrigin:NSMakePoint(vo->dx, vo->dy)];
+ [s->window setFrameOrigin:NSMakePoint(vo->dx, vo->dy)];
- if (flags & VOFLAG_HIDDEN) {
- [s->window orderOut:nil];
- } else {
- [s->window makeKeyAndOrderFront:nil];
- [NSApp activateIgnoringOtherApps:YES];
- }
+ if (flags & VOFLAG_HIDDEN) {
+ [s->window orderOut:nil];
+ } else {
+ [s->window makeKeyAndOrderFront:nil];
+ [NSApp activateIgnoringOtherApps:YES];
+ }
- if (flags & VOFLAG_FULLSCREEN && !vo->opts->fs)
- vo_cocoa_fullscreen(vo);
+ if (flags & VOFLAG_FULLSCREEN && !vo->opts->fs)
+ vo_cocoa_fullscreen(vo);
- vo_set_level(vo, opts->ontop);
+ vo_set_level(vo, opts->ontop);
+
+ resize_window(vo);
- resize_window(vo);
+ if (s->window_title)
+ [s->window_title release];
- if (s->window_title)
- [s->window_title release];
+ s->window_title =
+ [[NSString alloc] initWithUTF8String:vo_get_window_title(vo)];
+ [s->window setTitle: s->window_title];
+ });
- s->window_title =
- [[NSString alloc] initWithUTF8String:vo_get_window_title(vo)];
- [s->window setTitle: s->window_title];
+ [vo->cocoa->glContext makeCurrentContext];
- return 0;
+ return rv;
+}
+
+static bool resize_callback_registered(struct vo *vo)
+{
+ struct vo_cocoa_state *s = vo->cocoa;
+ return s->resize_redraw;
+}
+
+void vo_cocoa_set_current_context(struct vo *vo, bool current)
+{
+ struct vo_cocoa_state *s = vo->cocoa;
+ if (current) {
+ [s->lock lock];
+ [s->glContext makeCurrentContext];
+ } else {
+ [NSOpenGLContext clearCurrentContext];
+ [s->lock unlock];
+ }
}
void vo_cocoa_swap_buffers(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
- [s->glContext flushBuffer];
+ if (s->did_async_resize && resize_callback_registered(vo)) {
+ // when in live resize the GL view asynchronously updates itself from
+ // it's drawRect: implementation and calls flushBuffer. This means the
+ // backbuffer is probably in an inconsistent state, so we skip one
+ // flushBuffer call here on the playloop thread.
+ s->did_async_resize = NO;
+ } else {
+ [s->glContext flushBuffer];
+ }
}
static void vo_cocoa_display_cursor(struct vo *vo, int requested_state)
@@ -516,6 +611,9 @@ int vo_cocoa_check_events(struct vo *vo)
s->cursor_timer = ms_time;
}
+ int key = cocoa_sync_get_key(s->input_queue);
+ if (key >= 0) mplayer_put_key(vo->key_fifo, key);
+
if (s->did_resize) {
s->did_resize = NO;
resize_window(vo);
@@ -527,9 +625,17 @@ int vo_cocoa_check_events(struct vo *vo)
void vo_cocoa_fullscreen(struct vo *vo)
{
+ // This is the secondary thread, unlock since we are going to invoke a
+ // method synchronously on the GUI thread using Cocoa.
+ vo_cocoa_set_current_context(vo, false);
+
struct vo_cocoa_state *s = vo->cocoa;
- [s->window fullscreen];
- resize_window(vo);
+ [s->window performSelectorOnMainThread:@selector(fullscreen)
+ withObject:nil
+ waitUntilDone:YES];
+
+ // Now lock again!
+ vo_cocoa_set_current_context(vo, true);
}
int vo_cocoa_swap_interval(int enabled)
@@ -567,34 +673,30 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
}
@implementation GLMPlayerWindow
-- (void)setVideoOutput:(struct vo *)vo
-{
- _vo = vo;
-}
-
+@synthesize videoOutput = _video_output;
- (void)windowDidResize:(NSNotification *) notification
{
- if (_vo) {
- struct vo_cocoa_state *s = _vo->cocoa;
+ if (self.videoOutput) {
+ struct vo_cocoa_state *s = self.videoOutput->cocoa;
s->did_resize = YES;
}
}
-
- (void)fullscreen
{
- struct vo_cocoa_state *s = _vo->cocoa;
- struct mp_vo_opts *opts = _vo->opts;
+ struct vo_cocoa_state *s = self.videoOutput->cocoa;
+ struct mp_vo_opts *opts = self.videoOutput->opts;
+
if (!opts->fs) {
- update_screen_info(_vo);
- if (current_screen_has_dock_or_menubar(_vo))
+ update_screen_info(self.videoOutput);
+ if (current_screen_has_dock_or_menubar(self.videoOutput))
[NSApp setPresentationOptions:NSApplicationPresentationHideDock|
NSApplicationPresentationHideMenuBar];
s->windowed_frame = [self frame];
[self setHasShadow:NO];
[self setStyleMask:s->fullscreen_mask];
[self setFrame:s->fsscreen_frame display:YES animate:NO];
- opts->fs = true;
- vo_cocoa_display_cursor(_vo, 0);
+ opts->fs = VO_TRUE;
+ vo_cocoa_display_cursor(self.videoOutput, 0);
[self setMovableByWindowBackground: NO];
} else {
[NSApp setPresentationOptions:NSApplicationPresentationDefault];
@@ -608,9 +710,11 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
}
[self setContentAspectRatio:s->current_video_size];
opts->fs = false;
- vo_cocoa_display_cursor(_vo, 1);
+ vo_cocoa_display_cursor(self.videoOutput, 1);
[self setMovableByWindowBackground: YES];
}
+
+ resize_window(self.videoOutput);
}
- (BOOL)canBecomeMainWindow { return YES; }
@@ -620,7 +724,8 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
- (BOOL)resignFirstResponder { return YES; }
- (BOOL)windowShouldClose:(id)sender
{
- mplayer_put_key(_vo->key_fifo, MP_KEY_CLOSE_WIN);
+ struct vo_cocoa_state *s = self.videoOutput->cocoa;
+ cocoa_async_put_key(s->input_queue, MP_KEY_CLOSE_WIN);
// We have to wait for MPlayer to handle this,
// otherwise we are in trouble if the
// MP_KEY_CLOSE_WIN handler is disabled
@@ -631,8 +736,8 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
{
// this is only valid as a starting value. it will be rewritten in the
// -fullscreen method.
- if (_vo) {
- return !_vo->opts->fs;
+ if (self.videoOutput) {
+ return !self.videoOutput->opts->fs;
} else {
return NO;
}
@@ -640,6 +745,7 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
- (void)keyDown:(NSEvent *)theEvent
{
+ struct vo_cocoa_state *s = self.videoOutput->cocoa;
NSString *chars;
if (RightAltPressed(theEvent))
@@ -658,14 +764,15 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
key |= MP_KEY_MODIFIER_ALT;
if ([theEvent modifierFlags] & NSCommandKeyMask)
key |= MP_KEY_MODIFIER_META;
- mplayer_put_key(_vo->key_fifo, key);
+
+ cocoa_async_put_key(s->input_queue, key);
}
}
- (void)mouseMoved: (NSEvent *) theEvent
{
- if (_vo->opts->fs)
- vo_cocoa_display_cursor(_vo, 1);
+ if (self.videoOutput->opts->fs)
+ vo_cocoa_display_cursor(self.videoOutput, 1);
}
- (void)mouseDragged:(NSEvent *)theEvent
@@ -705,7 +812,7 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
- (void)scrollWheel:(NSEvent *)theEvent
{
- struct vo_cocoa_state *s = _vo->cocoa;
+ struct vo_cocoa_state *s = self.videoOutput->cocoa;
CGFloat delta;
// Use the dimention with the most delta as the scrolling one
@@ -721,23 +828,24 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
static const CGFloat threshold = 10;
while (s->accumulated_scroll >= threshold) {
s->accumulated_scroll -= threshold;
- mplayer_put_key(_vo->key_fifo, MP_MOUSE_BTN3);
+ cocoa_async_put_key(s->input_queue, MP_MOUSE_BTN3);
}
while (s->accumulated_scroll <= -threshold) {
s->accumulated_scroll += threshold;
- mplayer_put_key(_vo->key_fifo, MP_MOUSE_BTN4);
+ cocoa_async_put_key(s->input_queue, MP_MOUSE_BTN4);
}
} else {
if (delta > 0)
- mplayer_put_key(_vo->key_fifo, MP_MOUSE_BTN3);
+ cocoa_async_put_key(s->input_queue, MP_MOUSE_BTN3);
else
- mplayer_put_key(_vo->key_fifo, MP_MOUSE_BTN4);
+ cocoa_async_put_key(s->input_queue, MP_MOUSE_BTN4);
}
}
- (void)mouseEvent:(NSEvent *)theEvent
{
if ([theEvent buttonNumber] >= 0 && [theEvent buttonNumber] <= 9) {
+ struct vo_cocoa_state *s = self.videoOutput->cocoa;
int buttonNumber = [theEvent buttonNumber];
// Fix to mplayer defined button order: left, middle, right
if (buttonNumber == 1) buttonNumber = 2;
@@ -746,18 +854,21 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
case NSLeftMouseDown:
case NSRightMouseDown:
case NSOtherMouseDown:
- mplayer_put_key(_vo->key_fifo,
- (MP_MOUSE_BTN0 + buttonNumber) | MP_KEY_STATE_DOWN);
+ cocoa_async_put_key(
+ s->input_queue,
+ (MP_MOUSE_BTN0 + buttonNumber) | MP_KEY_STATE_DOWN);
// Looks like Cocoa doesn't create MouseUp events when we are
// doing the second click in a double click. Put in the key_fifo
// the key that would be put from the MouseUp handling code.
if([theEvent clickCount] == 2)
- mplayer_put_key(_vo->key_fifo, MP_MOUSE_BTN0 + buttonNumber);
+ cocoa_async_put_key(s->input_queue,
+ MP_MOUSE_BTN0 + buttonNumber);
break;
case NSLeftMouseUp:
case NSRightMouseUp:
case NSOtherMouseUp:
- mplayer_put_key(_vo->key_fifo, MP_MOUSE_BTN0 + buttonNumber);
+ cocoa_async_put_key(s->input_queue,
+ MP_MOUSE_BTN0 + buttonNumber);
break;
}
}
@@ -771,10 +882,10 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
- (void)mulSize:(float)multiplier
{
- if (!_vo->opts->fs) {
+ if (!self.videoOutput->opts->fs) {
NSSize size = {
- .width = _vo->aspdat.prew * multiplier,
- .height = _vo->aspdat.preh * multiplier
+ .width = self.videoOutput->cocoa->aspdat.prew * multiplier,
+ .height = self.videoOutput->cocoa->aspdat.preh * multiplier
};
[self setContentSize:size keepCentered:YES];
}
@@ -847,7 +958,14 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
@implementation GLMPlayerOpenGLView
- (void)drawRect: (NSRect)rect
{
- [[NSColor clearColor] set];
- NSRectFill([self bounds]);
+ GLMPlayerWindow *window = (GLMPlayerWindow *)[self window];
+ struct vo *vo = [window videoOutput];
+ if (vo && resize_callback_registered(vo)) {
+ NSSize size = to_pixels(vo, [self bounds]).size;
+ resize_redraw(vo, size.width, size.height);
+ } else {
+ [[NSColor clearColor] set];
+ NSRectFill([self bounds]);
+ }
}
@end
diff --git a/video/out/gl_cocoa.c b/video/out/gl_cocoa.c
index 81be21da58..dd8b5a865a 100644
--- a/video/out/gl_cocoa.c
+++ b/video/out/gl_cocoa.c
@@ -51,6 +51,11 @@ static void swapGlBuffers_cocoa(MPGLContext *ctx)
vo_cocoa_swap_buffers(ctx->vo);
}