mirror of https://github.com/mpv-player/mpv
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.
This commit is contained in:
parent
afdc9c4ae2
commit
134f3e97bf
|
@ -3803,33 +3803,6 @@ static void run_playloop(struct MPContext *mpctx)
|
||||||
execute_queued_seek(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)
|
static int read_keys(void *ctx, int fd)
|
||||||
{
|
{
|
||||||
if (getch2(ctx))
|
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);
|
mp_input_add_key_fd(mpctx->input, 0, 1, read_keys, NULL, mpctx->key_fifo);
|
||||||
// Set the libstream interrupt callback
|
// Set the libstream interrupt callback
|
||||||
stream_set_interrupt_callback(mp_input_check_interrupt, mpctx->input);
|
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)
|
static void open_subtitles_from_options(struct MPContext *mpctx)
|
||||||
|
@ -4432,7 +4409,8 @@ goto_enable_cache: ;
|
||||||
if (mpctx->opts.pause)
|
if (mpctx->opts.pause)
|
||||||
pause_player(mpctx);
|
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);
|
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);
|
GetCpuCaps(&gCpuCaps);
|
||||||
|
|
||||||
#ifdef CONFIG_COCOA
|
|
||||||
init_cocoa_application();
|
|
||||||
macosx_finder_args_preinit(p_argc, p_argv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
mp_get_converted_argv(p_argc, p_argv);
|
mp_get_converted_argv(p_argc, p_argv);
|
||||||
#endif
|
#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
|
/* This preprocessor directive is a hack to generate a mplayer-nomain.o object
|
||||||
* file for some tools to link against. */
|
* file for some tools to link against. */
|
||||||
#ifndef DISABLE_MAIN
|
#ifndef DISABLE_MAIN
|
||||||
int main(int argc, char *argv[])
|
static int mpv_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
osdep_preinit(&argc, &argv);
|
osdep_preinit(&argc, &argv);
|
||||||
|
|
||||||
|
@ -4747,4 +4720,14 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
return 1;
|
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 */
|
#endif /* DISABLE_MAIN */
|
||||||
|
|
|
@ -22,9 +22,7 @@
|
||||||
struct input_ctx;
|
struct input_ctx;
|
||||||
struct mp_fifo;
|
struct mp_fifo;
|
||||||
|
|
||||||
// Playloop callback function pointer
|
typedef int (*mpv_main_fn)(int, char**);
|
||||||
typedef void(*play_loop_callback)(void *);
|
|
||||||
typedef int(*should_stop_callback)(void *);
|
|
||||||
|
|
||||||
// Menu Keys identifing menu items
|
// Menu Keys identifing menu items
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -35,22 +33,23 @@ typedef enum {
|
||||||
MPM_ZOOM,
|
MPM_ZOOM,
|
||||||
} MPMenuKey;
|
} 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);
|
void cocoa_register_menu_item_action(MPMenuKey key, void* action);
|
||||||
|
|
||||||
// initializes Cocoa application
|
// initializes Cocoa application
|
||||||
void init_cocoa_application(void);
|
void init_cocoa_application(void);
|
||||||
void terminate_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
|
// Runs the Cocoa Main Event Loop
|
||||||
void cocoa_run_runloop(void);
|
void cocoa_run_runloop(void);
|
||||||
|
void cocoa_stop_runloop(void);
|
||||||
void cocoa_post_fake_event(void);
|
void cocoa_post_fake_event(void);
|
||||||
|
|
||||||
// Adds play_loop as a timer of the Main Cocoa Event Loop
|
void cocoa_set_state(struct input_ctx *input_context, struct mp_fifo *key_fifo);
|
||||||
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 macosx_finder_args_preinit(int *argc, char ***argv);
|
void macosx_finder_args_preinit(int *argc, char ***argv);
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
#include "talloc.h"
|
#include "talloc.h"
|
||||||
|
|
||||||
|
#include "core/mp_msg.h"
|
||||||
#include "core/mp_fifo.h"
|
#include "core/mp_fifo.h"
|
||||||
#include "core/input/input.h"
|
#include "core/input/input.h"
|
||||||
#include "core/input/keycodes.h"
|
#include "core/input/keycodes.h"
|
||||||
|
@ -25,10 +27,9 @@
|
||||||
#include "osdep/macosx_application_objc.h"
|
#include "osdep/macosx_application_objc.h"
|
||||||
#include "video/out/osx_common.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 Application *app;
|
||||||
|
static NSAutoreleasePool *pool;
|
||||||
|
static pthread_t playback_thread_id;
|
||||||
|
|
||||||
@interface Application (PrivateMethods)
|
@interface Application (PrivateMethods)
|
||||||
- (NSMenuItem *)menuItemWithParent:(NSMenu *)parent
|
- (NSMenuItem *)menuItemWithParent:(NSMenu *)parent
|
||||||
|
@ -54,12 +55,8 @@ static Application *app;
|
||||||
@synthesize argumentsList = _arguments_list;
|
@synthesize argumentsList = _arguments_list;
|
||||||
@synthesize willStopOnOpenEvent = _will_stop_on_open_event;
|
@synthesize willStopOnOpenEvent = _will_stop_on_open_event;
|
||||||
|
|
||||||
@synthesize callback = _callback;
|
|
||||||
@synthesize shouldStopPlayback = _should_stop_playback;
|
|
||||||
@synthesize context = _context;
|
|
||||||
@synthesize inputContext = _input_context;
|
@synthesize inputContext = _input_context;
|
||||||
@synthesize keyFIFO = _key_fifo;
|
@synthesize keyFIFO = _key_fifo;
|
||||||
@synthesize callbackTimer = _callback_timer;
|
|
||||||
@synthesize menuItems = _menu_items;
|
@synthesize menuItems = _menu_items;
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
|
@ -119,32 +116,6 @@ static Application *app;
|
||||||
|
|
||||||
#undef _R
|
#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
|
- (void)stopPlayback
|
||||||
{
|
{
|
||||||
mplayer_put_key(app.keyFIFO, MP_KEY_CLOSE_WIN);
|
mplayer_put_key(app.keyFIFO, MP_KEY_CLOSE_WIN);
|
||||||
|
@ -216,7 +187,8 @@ static Application *app;
|
||||||
|
|
||||||
self.files = [filesToOpen sortedArrayUsingSelector:@selector(compare:)];
|
self.files = [filesToOpen sortedArrayUsingSelector:@selector(compare:)];
|
||||||
if (self.willStopOnOpenEvent) {
|
if (self.willStopOnOpenEvent) {
|
||||||
[NSApp stop:nil];
|
self.willStopOnOpenEvent = NO;
|
||||||
|
cocoa_stop_runloop();
|
||||||
} else {
|
} else {
|
||||||
[self handleFiles];
|
[self handleFiles];
|
||||||
}
|
}
|
||||||
|
@ -236,6 +208,41 @@ static Application *app;
|
||||||
}
|
}
|
||||||
@end
|
@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)
|
void cocoa_register_menu_item_action(MPMenuKey key, void* action)
|
||||||
{
|
{
|
||||||
[app registerSelector:(SEL)action forKey:key];
|
[app registerSelector:(SEL)action forKey:key];
|
||||||
|
@ -256,26 +263,38 @@ void terminate_cocoa_application(void)
|
||||||
[NSApp terminate:app];
|
[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];
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||||
[NSApp run];
|
[NSApp run];
|
||||||
[pool drain];
|
[pool drain];
|
||||||
}
|
}
|
||||||
|
|
||||||
void cocoa_run_loop_schedule(play_loop_callback callback,
|
void cocoa_stop_runloop(void)
|
||||||
should_stop_callback stop_query,
|
{
|
||||||
void *context,
|
[NSApp performSelectorOnMainThread:@selector(stop:)
|
||||||
struct input_ctx *input_context,
|
withObject:nil
|
||||||
|
waitUntilDone:true];
|
||||||
|
cocoa_post_fake_event();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cocoa_set_state(struct input_ctx *input_context,
|
||||||
struct mp_fifo *key_fifo)
|
struct mp_fifo *key_fifo)
|
||||||
{
|
{
|
||||||
[NSApp setDelegate:app];
|
[NSApp setDelegate:app];
|
||||||
app.callback = callback;
|
|
||||||
app.context = context;
|
|
||||||
app.shouldStopPlayback = stop_query;
|
|
||||||
app.inputContext = input_context;
|
app.inputContext = input_context;
|
||||||
app.keyFIFO = key_fifo;
|
app.keyFIFO = key_fifo;
|
||||||
[app schedule_timer];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cocoa_post_fake_event(void)
|
void cocoa_post_fake_event(void)
|
||||||
|
|
|
@ -22,16 +22,10 @@
|
||||||
@interface Application : NSObject<NSApplicationDelegate>
|
@interface Application : NSObject<NSApplicationDelegate>
|
||||||
- (void)initialize_menu;
|
- (void)initialize_menu;
|
||||||
- (void)registerSelector:(SEL)selector forKey:(MPMenuKey)key;
|
- (void)registerSelector:(SEL)selector forKey:(MPMenuKey)key;
|
||||||
- (void)call_callback;
|
|
||||||
- (void)schedule_timer;
|
|
||||||
- (void)stopPlayback;
|
- (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 input_ctx *inputContext;
|
||||||
@property(nonatomic, assign) struct mp_fifo *keyFIFO;
|
@property(nonatomic, assign) struct mp_fifo *keyFIFO;
|
||||||
@property(nonatomic, retain) NSTimer *callbackTimer;
|
|
||||||
@property(nonatomic, retain) NSMutableDictionary *menuItems;
|
@property(nonatomic, retain) NSMutableDictionary *menuItems;
|
||||||
@property(nonatomic, retain) NSArray *files;
|
@property(nonatomic, retain) NSArray *files;
|
||||||
@property(nonatomic, retain) NSMutableArray *argumentsList;
|
@property(nonatomic, retain) NSMutableArray *argumentsList;
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
struct vo_cocoa_state;
|
struct vo_cocoa_state;
|
||||||
|
|
||||||
bool vo_cocoa_gui_running(void);
|
|
||||||
void *vo_cocoa_glgetaddr(const char *s);
|
void *vo_cocoa_glgetaddr(const char *s);
|
||||||
|
|
||||||
int vo_cocoa_init(struct vo *vo);
|
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,
|
uint32_t d_height, uint32_t flags,
|
||||||
int gl3profile);
|
int gl3profile);
|
||||||
|
|
||||||
|
void vo_cocoa_set_current_context(struct vo *vo, bool current);
|
||||||
void vo_cocoa_swap_buffers(struct vo *vo);
|
void vo_cocoa_swap_buffers(struct vo *vo);
|
||||||
int vo_cocoa_check_events(struct vo *vo);
|
int vo_cocoa_check_events(struct vo *vo);
|
||||||
void vo_cocoa_fullscreen(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_pause(struct vo *vo);
|
||||||
void vo_cocoa_resume(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
|
// returns an int to conform to the gl extensions from other platforms
|
||||||
int vo_cocoa_swap_interval(int enabled);
|
int vo_cocoa_swap_interval(int enabled);
|
||||||
|
|
||||||
|
|
|
@ -85,10 +85,7 @@ static bool RightAltPressed(NSEvent *event)
|
||||||
CFSTR("PreventUserIdleDisplaySleep")
|
CFSTR("PreventUserIdleDisplaySleep")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@interface GLMPlayerWindow : NSWindow <NSWindowDelegate> {
|
@interface GLMPlayerWindow : NSWindow <NSWindowDelegate>
|
||||||
struct vo *_vo;
|
|
||||||
}
|
|
||||||
- (void)setVideoOutput:(struct vo *)vo;
|
|
||||||
- (BOOL)canBecomeKeyWindow;
|
- (BOOL)canBecomeKeyWindow;
|
||||||
- (BOOL)canBecomeMainWindow;
|
- (BOOL)canBecomeMainWindow;
|
||||||
- (void)fullscreen;
|
- (void)fullscreen;
|
||||||
|
@ -97,11 +94,54 @@ static bool RightAltPressed(NSEvent *event)
|
||||||
- (int)titleHeight;
|
- (int)titleHeight;
|
||||||
- (NSRect)clipFrame:(NSRect)frame withContentAspect:(NSSize) aspect;
|
- (NSRect)clipFrame:(NSRect)frame withContentAspect:(NSSize) aspect;
|
||||||
- (void)setContentSize:(NSSize)newSize keepCentered:(BOOL)keepCentered;
|
- (void)setContentSize:(NSSize)newSize keepCentered:(BOOL)keepCentered;
|
||||||
|
@property(nonatomic, assign) struct vo *videoOutput;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface GLMPlayerOpenGLView : NSView
|
@interface GLMPlayerOpenGLView : NSView
|
||||||
@end
|
@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 {
|
struct vo_cocoa_state {
|
||||||
GLMPlayerWindow *window;
|
GLMPlayerWindow *window;
|
||||||
NSOpenGLContext *glContext;
|
NSOpenGLContext *glContext;
|
||||||
|
@ -123,25 +163,32 @@ struct vo_cocoa_state {
|
||||||
|
|
||||||
NSInteger window_level;
|
NSInteger window_level;
|
||||||
|
|
||||||
|
struct aspect_data aspdat;
|
||||||
|
|
||||||
int display_cursor;
|
int display_cursor;
|
||||||
int cursor_timer;
|
int cursor_timer;
|
||||||
int vo_cursor_autohide_delay;
|
int vo_cursor_autohide_delay;
|
||||||
|
|
||||||
bool did_resize;
|
bool did_resize;
|
||||||
|
bool did_async_resize;
|
||||||
bool out_fs_resize;
|
bool out_fs_resize;
|
||||||
|
|
||||||
IOPMAssertionID power_mgmt_assertion;
|
IOPMAssertionID power_mgmt_assertion;
|
||||||
|
|
||||||
CGFloat accumulated_scroll;
|
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)
|
static struct vo_cocoa_state *vo_cocoa_init_state(struct vo *vo)
|
||||||
{
|
{
|
||||||
struct vo_cocoa_state *s = talloc_ptrtype(vo, s);
|
struct vo_cocoa_state *s = talloc_ptrtype(vo, s);
|
||||||
*s = (struct vo_cocoa_state){
|
*s = (struct vo_cocoa_state){
|
||||||
.did_resize = NO,
|
.did_resize = NO,
|
||||||
|
.did_async_resize = NO,
|
||||||
.current_video_size = {0,0},
|
.current_video_size = {0,0},
|
||||||
.previous_video_size = {0,0},
|
.previous_video_size = {0,0},
|
||||||
.windowed_mask = NSTitledWindowMask|NSClosableWindowMask|
|
.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,
|
.vo_cursor_autohide_delay = vo->opts->cursor_autohide_delay,
|
||||||
.power_mgmt_assertion = kIOPMNullAssertionID,
|
.power_mgmt_assertion = kIOPMNullAssertionID,
|
||||||
.accumulated_scroll = 0,
|
.accumulated_scroll = 0,
|
||||||
|
.lock = [[NSRecursiveLock alloc] init],
|
||||||
|
.input_queue = vo_cocoa_input_queue_init(s),
|
||||||
};
|
};
|
||||||
if (!vo->opts->border) s->windowed_mask = NSBorderlessWindowMask;
|
if (!vo->opts->border) s->windowed_mask = NSBorderlessWindowMask;
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,9 +215,16 @@ static bool supports_hidpi(NSView *view)
|
||||||
[view respondsToSelector:hdpi_selector];
|
[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)
|
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->cocoa = vo_cocoa_init_state(vo);
|
||||||
vo->wakeup_period = 0.02;
|
vo->wakeup_period = 0.02;
|
||||||
_instances++;
|
|
||||||
disable_power_management(vo);
|
disable_power_management(vo);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -216,6 +272,7 @@ int vo_cocoa_init(struct vo *vo)
|
||||||
|
|
||||||
void vo_cocoa_uninit(struct vo *vo)
|
void vo_cocoa_uninit(struct vo *vo)
|
||||||
{
|
{
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||||
struct vo_cocoa_state *s = vo->cocoa;
|
struct vo_cocoa_state *s = vo->cocoa;
|
||||||
CGDisplayShowCursor(kCGDirectMainDisplay);
|
CGDisplayShowCursor(kCGDirectMainDisplay);
|
||||||
enable_power_management(vo);
|
enable_power_management(vo);
|
||||||
|
@ -225,8 +282,7 @@ void vo_cocoa_uninit(struct vo *vo)
|
||||||
s->window = nil;
|
s->window = nil;
|
||||||
[s->glContext release];
|
[s->glContext release];
|
||||||
s->glContext = nil;
|
s->glContext = nil;
|
||||||
|
});
|
||||||
_instances--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vo_cocoa_pause(struct vo *vo)
|
void vo_cocoa_pause(struct vo *vo)
|
||||||
|
@ -239,6 +295,13 @@ void vo_cocoa_resume(struct vo *vo)
|
||||||
disable_power_management(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)
|
static int current_screen_has_dock_or_menubar(struct vo *vo)
|
||||||
{
|
{
|
||||||
struct vo_cocoa_state *s = vo->cocoa;
|
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;
|
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)
|
static void resize_window(struct vo *vo)
|
||||||
{
|
{
|
||||||
struct vo_cocoa_state *s = vo->cocoa;
|
struct vo_cocoa_state *s = vo->cocoa;
|
||||||
NSView *view = [s->window contentView];
|
NSView *view = [s->window contentView];
|
||||||
NSRect frame;
|
NSRect frame = to_pixels(vo, [view frame]);
|
||||||
|
|
||||||
if (supports_hidpi(view)) {
|
|
||||||
frame = [view convertRectToBacking: [view frame]];
|
|
||||||
} else {
|
|
||||||
frame = [view frame];
|
|
||||||
}
|
|
||||||
|
|
||||||
vo->dwidth = frame.size.width;
|
vo->dwidth = frame.size.width;
|
||||||
vo->dheight = frame.size.height;
|
vo->dheight = frame.size.height;
|
||||||
[s->glContext update];
|
[s->glContext update];
|
||||||
|
@ -402,8 +453,7 @@ static int create_window(struct vo *vo, uint32_t d_width, uint32_t d_height,
|
||||||
[glView release];
|
[glView release];
|
||||||
[s->window setAcceptsMouseMovedEvents:YES];
|
[s->window setAcceptsMouseMovedEvents:YES];
|
||||||
[s->glContext setView:glView];
|
[s->glContext setView:glView];
|
||||||
[s->glContext makeCurrentContext];
|
s->window.videoOutput = vo;
|
||||||
[s->window setVideoOutput:vo];
|
|
||||||
|
|
||||||
[s->window setDelegate:s->window];
|
[s->window setDelegate:s->window];
|
||||||
[s->window makeMainWindow];
|
[s->window makeMainWindow];
|
||||||
|
@ -433,10 +483,25 @@ 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,
|
int vo_cocoa_config_window(struct vo *vo, uint32_t d_width,
|
||||||
uint32_t d_height, uint32_t flags,
|
uint32_t d_height, uint32_t flags,
|
||||||
int gl3profile)
|
int gl3profile)
|
||||||
{
|
{
|
||||||
|
__block int rv = 0;
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||||
struct vo_cocoa_state *s = vo->cocoa;
|
struct vo_cocoa_state *s = vo->cocoa;
|
||||||
struct mp_vo_opts *opts = vo->opts;
|
struct mp_vo_opts *opts = vo->opts;
|
||||||
|
|
||||||
|
@ -446,11 +511,12 @@ int vo_cocoa_config_window(struct vo *vo, uint32_t d_width,
|
||||||
vo->dy = origin.y;
|
vo->dy = origin.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->aspdat = vo->aspdat;
|
||||||
update_state_sizes(s, d_width, d_height);
|
update_state_sizes(s, d_width, d_height);
|
||||||
|
|
||||||
if (!(s->window || s->glContext)) {
|
if (!(s->window || s->glContext)) {
|
||||||
if (create_window(vo, d_width, d_height, flags, gl3profile) < 0)
|
if (create_window(vo, d_width, d_height, flags, gl3profile) < 0)
|
||||||
return -1;
|
rv = -1;
|
||||||
} else {
|
} else {
|
||||||
update_window(vo);
|
update_window(vo);
|
||||||
}
|
}
|
||||||
|
@ -477,14 +543,43 @@ int vo_cocoa_config_window(struct vo *vo, uint32_t d_width,
|
||||||
s->window_title =
|
s->window_title =
|
||||||
[[NSString alloc] initWithUTF8String:vo_get_window_title(vo)];
|
[[NSString alloc] initWithUTF8String:vo_get_window_title(vo)];
|
||||||
[s->window setTitle: s->window_title];
|
[s->window setTitle: s->window_title];
|
||||||
|
});
|
||||||
|
|
||||||
return 0;
|
[vo->cocoa->glContext makeCurrentContext];
|
||||||
|
|
||||||
|
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)
|
void vo_cocoa_swap_buffers(struct vo *vo)
|
||||||
{
|
{
|
||||||
struct vo_cocoa_state *s = vo->cocoa;
|
struct vo_cocoa_state *s = vo->cocoa;
|
||||||
|
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];
|
[s->glContext flushBuffer];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vo_cocoa_display_cursor(struct vo *vo, int requested_state)
|
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;
|
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) {
|
if (s->did_resize) {
|
||||||
s->did_resize = NO;
|
s->did_resize = NO;
|
||||||
resize_window(vo);
|
resize_window(vo);
|
||||||
|
@ -527,9 +625,17 @@ int vo_cocoa_check_events(struct vo *vo)
|
||||||
|
|
||||||
void vo_cocoa_fullscreen(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;
|
struct vo_cocoa_state *s = vo->cocoa;
|
||||||
[s->window fullscreen];
|
[s->window performSelectorOnMainThread:@selector(fullscreen)
|
||||||
resize_window(vo);
|
withObject:nil
|
||||||
|
waitUntilDone:YES];
|
||||||
|
|
||||||
|
// Now lock again!
|
||||||
|
vo_cocoa_set_current_context(vo, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int vo_cocoa_swap_interval(int enabled)
|
int vo_cocoa_swap_interval(int enabled)
|
||||||
|
@ -567,34 +673,30 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation GLMPlayerWindow
|
@implementation GLMPlayerWindow
|
||||||
- (void)setVideoOutput:(struct vo *)vo
|
@synthesize videoOutput = _video_output;
|
||||||
{
|
|
||||||
_vo = vo;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)windowDidResize:(NSNotification *) notification
|
- (void)windowDidResize:(NSNotification *) notification
|
||||||
{
|
{
|
||||||
if (_vo) {
|
if (self.videoOutput) {
|
||||||
struct vo_cocoa_state *s = _vo->cocoa;
|
struct vo_cocoa_state *s = self.videoOutput->cocoa;
|
||||||
s->did_resize = YES;
|
s->did_resize = YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)fullscreen
|
- (void)fullscreen
|
||||||
{
|
{
|
||||||
struct vo_cocoa_state *s = _vo->cocoa;
|
struct vo_cocoa_state *s = self.videoOutput->cocoa;
|
||||||
struct mp_vo_opts *opts = _vo->opts;
|
struct mp_vo_opts *opts = self.videoOutput->opts;
|
||||||
|
|
||||||
if (!opts->fs) {
|
if (!opts->fs) {
|
||||||
update_screen_info(_vo);
|
update_screen_info(self.videoOutput);
|
||||||
if (current_screen_has_dock_or_menubar(_vo))
|
if (current_screen_has_dock_or_menubar(self.videoOutput))
|
||||||
[NSApp setPresentationOptions:NSApplicationPresentationHideDock|
|
[NSApp setPresentationOptions:NSApplicationPresentationHideDock|
|
||||||
NSApplicationPresentationHideMenuBar];
|
NSApplicationPresentationHideMenuBar];
|
||||||
s->windowed_frame = [self frame];
|
s->windowed_frame = [self frame];
|
||||||
[self setHasShadow:NO];
|
[self setHasShadow:NO];
|
||||||
[self setStyleMask:s->fullscreen_mask];
|
[self setStyleMask:s->fullscreen_mask];
|
||||||
[self setFrame:s->fsscreen_frame display:YES animate:NO];
|
[self setFrame:s->fsscreen_frame display:YES animate:NO];
|
||||||
opts->fs = true;
|
opts->fs = VO_TRUE;
|
||||||
vo_cocoa_display_cursor(_vo, 0);
|
vo_cocoa_display_cursor(self.videoOutput, 0);
|
||||||
[self setMovableByWindowBackground: NO];
|
[self setMovableByWindowBackground: NO];
|
||||||
} else {
|
} else {
|
||||||
[NSApp setPresentationOptions:NSApplicationPresentationDefault];
|
[NSApp setPresentationOptions:NSApplicationPresentationDefault];
|
||||||
|
@ -608,9 +710,11 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
|
||||||
}
|
}
|
||||||
[self setContentAspectRatio:s->current_video_size];
|
[self setContentAspectRatio:s->current_video_size];
|
||||||
opts->fs = false;
|
opts->fs = false;
|
||||||
vo_cocoa_display_cursor(_vo, 1);
|
vo_cocoa_display_cursor(self.videoOutput, 1);
|
||||||
[self setMovableByWindowBackground: YES];
|
[self setMovableByWindowBackground: YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resize_window(self.videoOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)canBecomeMainWindow { return YES; }
|
- (BOOL)canBecomeMainWindow { return YES; }
|
||||||
|
@ -620,7 +724,8 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
|
||||||
- (BOOL)resignFirstResponder { return YES; }
|
- (BOOL)resignFirstResponder { return YES; }
|
||||||
- (BOOL)windowShouldClose:(id)sender
|
- (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,
|
// We have to wait for MPlayer to handle this,
|
||||||
// otherwise we are in trouble if the
|
// otherwise we are in trouble if the
|
||||||
// MP_KEY_CLOSE_WIN handler is disabled
|
// 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
|
// this is only valid as a starting value. it will be rewritten in the
|
||||||
// -fullscreen method.
|
// -fullscreen method.
|
||||||
if (_vo) {
|
if (self.videoOutput) {
|
||||||
return !_vo->opts->fs;
|
return !self.videoOutput->opts->fs;
|
||||||
} else {
|
} else {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
@ -640,6 +745,7 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
|
||||||
|
|
||||||
- (void)keyDown:(NSEvent *)theEvent
|
- (void)keyDown:(NSEvent *)theEvent
|
||||||
{
|
{
|
||||||
|
struct vo_cocoa_state *s = self.videoOutput->cocoa;
|
||||||
NSString *chars;
|
NSString *chars;
|
||||||
|
|
||||||
if (RightAltPressed(theEvent))
|
if (RightAltPressed(theEvent))
|
||||||
|
@ -658,14 +764,15 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
|
||||||
key |= MP_KEY_MODIFIER_ALT;
|
key |= MP_KEY_MODIFIER_ALT;
|
||||||
if ([theEvent modifierFlags] & NSCommandKeyMask)
|
if ([theEvent modifierFlags] & NSCommandKeyMask)
|
||||||
key |= MP_KEY_MODIFIER_META;
|
key |= MP_KEY_MODIFIER_META;
|
||||||
mplayer_put_key(_vo->key_fifo, key);
|
|
||||||
|
cocoa_async_put_key(s->input_queue, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseMoved: (NSEvent *) theEvent
|
- (void)mouseMoved: (NSEvent *) theEvent
|
||||||
{
|
{
|
||||||
if (_vo->opts->fs)
|
if (self.videoOutput->opts->fs)
|
||||||
vo_cocoa_display_cursor(_vo, 1);
|
vo_cocoa_display_cursor(self.videoOutput, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDragged:(NSEvent *)theEvent
|
- (void)mouseDragged:(NSEvent *)theEvent
|
||||||
|
@ -705,7 +812,7 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
|
||||||
|
|
||||||
- (void)scrollWheel:(NSEvent *)theEvent
|
- (void)scrollWheel:(NSEvent *)theEvent
|
||||||
{
|
{
|
||||||
struct vo_cocoa_state *s = _vo->cocoa;
|
struct vo_cocoa_state *s = self.videoOutput->cocoa;
|
||||||
|
|
||||||
CGFloat delta;
|
CGFloat delta;
|
||||||
// Use the dimention with the most delta as the scrolling one
|
// 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;
|
static const CGFloat threshold = 10;
|
||||||
while (s->accumulated_scroll >= threshold) {
|
while (s->accumulated_scroll >= threshold) {
|
||||||
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) {
|
while (s->accumulated_scroll <= -threshold) {
|
||||||
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 {
|
} else {
|
||||||
if (delta > 0)
|
if (delta > 0)
|
||||||
mplayer_put_key(_vo->key_fifo, MP_MOUSE_BTN3);
|
cocoa_async_put_key(s->input_queue, MP_MOUSE_BTN3);
|
||||||
else
|
else
|
||||||
mplayer_put_key(_vo->key_fifo, MP_MOUSE_BTN4);
|
cocoa_async_put_key(s->input_queue, MP_MOUSE_BTN4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseEvent:(NSEvent *)theEvent
|
- (void)mouseEvent:(NSEvent *)theEvent
|
||||||
{
|
{
|
||||||
if ([theEvent buttonNumber] >= 0 && [theEvent buttonNumber] <= 9) {
|
if ([theEvent buttonNumber] >= 0 && [theEvent buttonNumber] <= 9) {
|
||||||
|
struct vo_cocoa_state *s = self.videoOutput->cocoa;
|
||||||
int buttonNumber = [theEvent buttonNumber];
|
int buttonNumber = [theEvent buttonNumber];
|
||||||
// Fix to mplayer defined button order: left, middle, right
|
// Fix to mplayer defined button order: left, middle, right
|
||||||
if (buttonNumber == 1) buttonNumber = 2;
|
if (buttonNumber == 1) buttonNumber = 2;
|
||||||
|
@ -746,18 +854,21 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
|
||||||
case NSLeftMouseDown:
|
case NSLeftMouseDown:
|
||||||
case NSRightMouseDown:
|
case NSRightMouseDown:
|
||||||
case NSOtherMouseDown:
|
case NSOtherMouseDown:
|
||||||
mplayer_put_key(_vo->key_fifo,
|
cocoa_async_put_key(
|
||||||
|
s->input_queue,
|
||||||
(MP_MOUSE_BTN0 + buttonNumber) | MP_KEY_STATE_DOWN);
|
(MP_MOUSE_BTN0 + buttonNumber) | MP_KEY_STATE_DOWN);
|
||||||
// Looks like Cocoa doesn't create MouseUp events when we are
|
// Looks like Cocoa doesn't create MouseUp events when we are
|
||||||
// doing the second click in a double click. Put in the key_fifo
|
// doing the second click in a double click. Put in the key_fifo
|
||||||
// the key that would be put from the MouseUp handling code.
|
// the key that would be put from the MouseUp handling code.
|
||||||
if([theEvent clickCount] == 2)
|
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;
|
break;
|
||||||
case NSLeftMouseUp:
|
case NSLeftMouseUp:
|
||||||
case NSRightMouseUp:
|
case NSRightMouseUp:
|
||||||
case NSOtherMouseUp:
|
case NSOtherMouseUp:
|
||||||
mplayer_put_key(_vo->key_fifo, MP_MOUSE_BTN0 + buttonNumber);
|
cocoa_async_put_key(s->input_queue,
|
||||||
|
MP_MOUSE_BTN0 + buttonNumber);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -771,10 +882,10 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
|
||||||
|
|
||||||
- (void)mulSize:(float)multiplier
|
- (void)mulSize:(float)multiplier
|
||||||
{
|
{
|
||||||
if (!_vo->opts->fs) {
|
if (!self.videoOutput->opts->fs) {
|
||||||
NSSize size = {
|
NSSize size = {
|
||||||
.width = _vo->aspdat.prew * multiplier,
|
.width = self.videoOutput->cocoa->aspdat.prew * multiplier,
|
||||||
.height = _vo->aspdat.preh * multiplier
|
.height = self.videoOutput->cocoa->aspdat.preh * multiplier
|
||||||
};
|
};
|
||||||
[self setContentSize:size keepCentered:YES];
|
[self setContentSize:size keepCentered:YES];
|
||||||
}
|
}
|
||||||
|
@ -847,7 +958,14 @@ int vo_cocoa_cgl_color_size(struct vo *vo)
|
||||||
@implementation GLMPlayerOpenGLView
|
@implementation GLMPlayerOpenGLView
|
||||||
- (void)drawRect: (NSRect)rect
|
- (void)drawRect: (NSRect)rect
|
||||||
{
|
{
|
||||||
|
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];
|
[[NSColor clearColor] set];
|
||||||
NSRectFill([self bounds]);
|
NSRectFill([self bounds]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -51,6 +51,11 @@ static void swapGlBuffers_cocoa(MPGLContext *ctx)
|
||||||
vo_cocoa_swap_buffers(ctx->vo);
|
vo_cocoa_swap_buffers(ctx->vo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_current_cocoa(MPGLContext *ctx, bool current)
|
||||||
|
{
|
||||||
|
vo_cocoa_set_current_context(ctx->vo, current);
|
||||||
|
}
|
||||||
|
|
||||||
void mpgl_set_backend_cocoa(MPGLContext *ctx)
|
void mpgl_set_backend_cocoa(MPGLContext *ctx)
|
||||||
{
|
{
|
||||||
ctx->config_window = config_window_cocoa;
|
ctx->config_window = config_window_cocoa;
|
||||||
|
@ -63,5 +68,8 @@ void mpgl_set_backend_cocoa(MPGLContext *ctx)
|
||||||
ctx->vo_init = vo_cocoa_init;
|
ctx->vo_init = vo_cocoa_init;
|
||||||
ctx->pause = vo_cocoa_pause;
|
ctx->pause = vo_cocoa_pause;
|
||||||
ctx->resume = vo_cocoa_resume;
|
ctx->resume = vo_cocoa_resume;
|
||||||
|
ctx->register_resize_callback = vo_cocoa_register_resize_callback;
|
||||||
ctx->vo_uninit = vo_cocoa_uninit;
|
ctx->vo_uninit = vo_cocoa_uninit;
|
||||||
|
ctx->set_current = set_current_cocoa;
|
||||||
|
ctx->set_current = set_current_cocoa;
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,13 @@ typedef struct MPGLContext {
|
||||||
void (*border)(struct vo *vo);
|
void (*border)(struct vo *vo);
|
||||||
void (*update_xinerama_info)(struct vo *vo);
|
void (*update_xinerama_info)(struct vo *vo);
|
||||||
|
|
||||||
|
// An optional function to register a resize callback in the backend that
|
||||||
|
// can be called on separate thread to handle resize events immediately
|
||||||
|
// (without waiting for vo_check_events, which will come later for the
|
||||||
|
// proper resize)
|
||||||
|
void (*register_resize_callback)(struct vo *vo,
|
||||||
|
void (*cb)(struct vo *vo, int w, int h));
|
||||||
|
|
||||||
// For free use by the backend.
|
// For free use by the backend.
|
||||||
void *priv;
|
void *priv;
|
||||||
} MPGLContext;
|
} MPGLContext;
|
||||||
|
|
|
@ -156,6 +156,13 @@ static bool config_window(struct gl_priv *p, uint32_t d_width,
|
||||||
return mpgl_config_window(p->glctx, mpgl_caps, d_width, d_height, flags);
|
return mpgl_config_window(p->glctx, mpgl_caps, d_width, d_height, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void video_resize_redraw_callback(struct vo *vo, int w, int h)
|
||||||
|
{
|
||||||
|
struct gl_priv *p = vo->priv;
|
||||||
|
gl_video_resize_redraw(p->renderer, w, h);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static int config(struct vo *vo, uint32_t width, uint32_t height,
|
static int config(struct vo *vo, uint32_t width, uint32_t height,
|
||||||
uint32_t d_width, uint32_t d_height, uint32_t flags,
|
uint32_t d_width, uint32_t d_height, uint32_t flags,
|
||||||
uint32_t format)
|
uint32_t format)
|
||||||
|
@ -169,6 +176,10 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p->glctx->register_resize_callback) {
|
||||||
|
p->glctx->register_resize_callback(vo, video_resize_redraw_callback);
|
||||||
|
}
|
||||||
|
|
||||||
gl_video_config(p->renderer, format, width, height,
|
gl_video_config(p->renderer, format, width, height,
|
||||||
p->vo->aspdat.prew, p->vo->aspdat.preh);
|
p->vo->aspdat.prew, p->vo->aspdat.preh);
|
||||||
|
|
||||||
|
@ -353,6 +364,8 @@ static int preinit(struct vo *vo, const char *arg)
|
||||||
if (!config_window(p, 320, 200, VOFLAG_HIDDEN))
|
if (!config_window(p, 320, 200, VOFLAG_HIDDEN))
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
|
mpgl_set_context(p->glctx);
|
||||||
|
|
||||||
if (p->gl->SwapInterval)
|
if (p->gl->SwapInterval)
|
||||||
p->gl->SwapInterval(p->swap_interval);
|
p->gl->SwapInterval(p->swap_interval);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue