mirror of
https://github.com/mpv-player/mpv
synced 2024-12-27 17:42:17 +00:00
cocoa/libmpv: allow to embed mpv GL view in another window
This is just temporary code but is a good base for future work (and baby steps are required for these changes). The 'final destination' is embedding the video view into any NSView but that requires some more work (the mechanism will be the same: pass the view's pointer casted to int64_t through -wid). For instance we will need to remove as much usage of the window instance as possible, and use nil guards where not possible. For this reason I will remove stuff like the mission control fullscreen feature (it's a cute feature but annoying to support and quite limited, go make your GUIs), and a way to lookup the current screen directly from the NSView absolute coordinates (this is needed for ICC detection mostly, and reporting back the screen to mpv's core). Moreover the current view.m will need to be separated into 2 views: the actual video view that will be embedded, and a parent view that will not be embedded and will be responsibile for tracking events.
This commit is contained in:
parent
3137b7ac5f
commit
c8ed4736ef
@ -8,17 +8,48 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#define EMBED_VIEW 1
|
||||
|
||||
#if EMBED_VIEW
|
||||
@interface CocoaWindow : NSWindow
|
||||
@end
|
||||
|
||||
@implementation CocoaWindow
|
||||
- (BOOL)canBecomeMainWindow { return YES; }
|
||||
- (BOOL)canBecomeKeyWindow { return YES; }
|
||||
@end
|
||||
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||
{
|
||||
mpv_handle *mpv;
|
||||
dispatch_queue_t queue;
|
||||
NSWindow *w;
|
||||
}
|
||||
@end
|
||||
#endif
|
||||
|
||||
static void wakeup(void *);
|
||||
|
||||
#if EMBED_VIEW
|
||||
@implementation AppDelegate
|
||||
|
||||
- (void)createWindow {
|
||||
|
||||
int mask = NSTitledWindowMask|NSClosableWindowMask|
|
||||
NSMiniaturizableWindowMask|NSResizableWindowMask;
|
||||
|
||||
self->w = [[CocoaWindow alloc]
|
||||
initWithContentRect:NSMakeRect(0,0, 1280, 720)
|
||||
styleMask:mask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
|
||||
[self->w setTitle:@"cocoabasic example"];
|
||||
[self->w makeKeyAndOrderFront:nil];
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void) applicationDidFinishLaunching:(NSNotification *)notification {
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
atexit_b(^{
|
||||
@ -36,6 +67,10 @@ static void wakeup(void *);
|
||||
}
|
||||
NSString *filename = args[1];
|
||||
|
||||
#if EMBED_VIEW
|
||||
[self createWindow];
|
||||
#endif
|
||||
|
||||
// Deal with MPV in the background.
|
||||
queue = dispatch_queue_create("mpv", DISPATCH_QUEUE_SERIAL);
|
||||
dispatch_async(queue, ^{
|
||||
@ -46,6 +81,11 @@ static void wakeup(void *);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if EMBED_VIEW
|
||||
uintptr_t wid = (uintptr_t)self->w;
|
||||
check_error(mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid));
|
||||
#endif
|
||||
|
||||
// Maybe set some options here, like default key bindings.
|
||||
// NOTE: Interaction with the window seems to be broken for now.
|
||||
check_error(mpv_set_option_string(mpv, "input-default-bindings", "yes"));
|
||||
@ -99,6 +139,8 @@ static void wakeup(void *context) {
|
||||
- (BOOL) windowShouldClose:(id)sender
|
||||
{
|
||||
[self shutdown];
|
||||
if (self->w)
|
||||
[self->w release];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -111,8 +153,6 @@ static void wakeup(void *context) {
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
// Delete this if you already have a main.m.
|
||||
int main(int argc, const char * argv[]) {
|
||||
@autoreleasepool {
|
||||
|
@ -18,13 +18,17 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "video/out/cocoa/mpvadapter.h"
|
||||
|
||||
@interface MpvVideoWindow : NSWindow <NSWindowDelegate>
|
||||
@property(nonatomic, retain) MpvCocoaAdapter *adapter;
|
||||
@protocol MpvSizing
|
||||
- (void)queueNewVideoSize:(NSSize)newSize;
|
||||
@end
|
||||
|
||||
@protocol MpvFullscreen
|
||||
- (void)setFullScreen:(BOOL)willBeFullscreen;
|
||||
@end
|
||||
|
||||
@interface MpvVideoWindow : NSWindow <NSWindowDelegate, MpvSizing, MpvFullscreen>
|
||||
@property(nonatomic, retain) MpvCocoaAdapter *adapter;
|
||||
- (BOOL)canBecomeKeyWindow;
|
||||
- (BOOL)canBecomeMainWindow;
|
||||
- (void)mulSize:(float)multiplier;
|
||||
- (NSRect)frameRect:(NSRect)frameRect forCenteredContentSize:(NSSize)newSize;
|
||||
- (void)setCenteredContentSize:(NSSize)newSize;
|
||||
- (void)queueNewVideoSize:(NSSize)newSize;
|
||||
@end
|
||||
|
@ -27,6 +27,11 @@
|
||||
|
||||
#include "window.h"
|
||||
|
||||
@interface MpvVideoWindow()
|
||||
- (NSRect)frameRect:(NSRect)frameRect forCenteredContentSize:(NSSize)newSize;
|
||||
- (void)setCenteredContentSize:(NSSize)newSize;
|
||||
@end
|
||||
|
||||
@implementation MpvVideoWindow {
|
||||
NSSize _queued_video_size;
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ static void cocoa_change_profile(struct vo *vo, char **store, NSScreen *screen);
|
||||
static void cocoa_rm_fs_screen_profile_observer(struct vo *vo);
|
||||
|
||||
struct vo_cocoa_state {
|
||||
MpvVideoWindow *window;
|
||||
NSWindow *window;
|
||||
MpvVideoView *view;
|
||||
NSOpenGLContext *gl_ctx;
|
||||
|
||||
@ -98,6 +98,15 @@ static void with_cocoa_lock_on_main_thread(struct vo *vo, void(^block)(void))
|
||||
});
|
||||
}
|
||||
|
||||
static void queue_new_video_size(struct vo *vo, int w, int h)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
if ([s->window conformsToProtocol: @protocol(MpvSizing)]) {
|
||||
id<MpvSizing> win = (id<MpvSizing>) s->window;
|
||||
[win queueNewVideoSize:NSMakeSize(w, h)];
|
||||
}
|
||||
}
|
||||
|
||||
void *vo_cocoa_glgetaddr(const char *s)
|
||||
{
|
||||
void *ret = NULL;
|
||||
@ -233,6 +242,12 @@ static void resize_window(struct vo *vo)
|
||||
static void vo_set_level(struct vo *vo, int ontop)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
|
||||
// completely ignore window level commands when the window is embedded
|
||||
if (opts->WinID >= 0)
|
||||
return;
|
||||
|
||||
if (ontop) {
|
||||
// +1 is not enough as that will show the icon layer on top of the
|
||||
// menubar when the application is not frontmost. so use +2
|
||||
@ -252,28 +267,44 @@ static void vo_cocoa_ontop(struct vo *vo)
|
||||
vo_set_level(vo, opts->ontop);
|
||||
}
|
||||
|
||||
static void create_window(struct vo *vo, struct mp_rect *win, int geo_flags)
|
||||
static MpvVideoWindow *create_window(NSRect rect, NSScreen *s, bool border,
|
||||
MpvCocoaAdapter *adapter)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
|
||||
const NSRect contentRect =
|
||||
NSMakeRect(win->x0, win->y0, win->x1 - win->x0, win->y1 - win->y0);
|
||||
|
||||
int window_mask = 0;
|
||||
if (opts->border) {
|
||||
if (border) {
|
||||
window_mask = NSTitledWindowMask|NSClosableWindowMask|
|
||||
NSMiniaturizableWindowMask|NSResizableWindowMask;
|
||||
} else {
|
||||
window_mask = NSBorderlessWindowMask|NSResizableWindowMask;
|
||||
}
|
||||
|
||||
s->window =
|
||||
[[MpvVideoWindow alloc] initWithContentRect:contentRect
|
||||
MpvVideoWindow *w =
|
||||
[[MpvVideoWindow alloc] initWithContentRect:rect
|
||||
styleMask:window_mask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO
|
||||
screen:s->current_screen];
|
||||
screen:s];
|
||||
w.adapter = adapter;
|
||||
[w setDelegate: w];
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static void create_ui(struct vo *vo, struct mp_rect *win, int geo_flags)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
|
||||
MpvCocoaAdapter *adapter = [[[MpvCocoaAdapter alloc] init] autorelease];
|
||||
const NSRect contentRect =
|
||||
NSMakeRect(win->x0, win->y0, win->x1 - win->x0, win->y1 - win->y0);
|
||||
|
||||
if (opts->WinID >= 0) {
|
||||
s->window = (NSWindow *) opts->WinID;
|
||||
} else {
|
||||
s->window = create_window(contentRect, s->current_screen,
|
||||
opts->border, adapter);
|
||||
}
|
||||
s->view = [[[MpvVideoView alloc] initWithFrame:contentRect] autorelease];
|
||||
|
||||
[s->view setWantsBestResolutionOpenGLSurface:YES];
|
||||
@ -286,20 +317,18 @@ static void create_window(struct vo *vo, struct mp_rect *win, int geo_flags)
|
||||
cocoa_register_menu_item_action(MPM_ZOOM, @selector(performZoom:));
|
||||
#endif
|
||||
|
||||
[s->window setRestorable:NO];
|
||||
[s->window setContentView:s->view];
|
||||
[s->gl_ctx setView:s->view];
|
||||
|
||||
MpvCocoaAdapter *adapter = [[[MpvCocoaAdapter alloc] init] autorelease];
|
||||
adapter.vout = vo;
|
||||
s->view.adapter = adapter;
|
||||
s->window.adapter = adapter;
|
||||
|
||||
[s->window setDelegate:s->window];
|
||||
[s->window makeMainWindow];
|
||||
|
||||
[s->window makeKeyAndOrderFront:nil];
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
if (opts->WinID < 0) {
|
||||
[s->window setRestorable:NO];
|
||||
[s->window makeMainWindow];
|
||||
[s->window makeKeyAndOrderFront:nil];
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
vo_set_level(vo, opts->ontop);
|
||||
|
||||
@ -312,6 +341,10 @@ static void create_window(struct vo *vo, struct mp_rect *win, int geo_flags)
|
||||
static void cocoa_set_window_title(struct vo *vo, const char *title)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
if (opts->WinID >= 0)
|
||||
return;
|
||||
|
||||
void *talloc_ctx = talloc_new(NULL);
|
||||
struct bstr btitle = bstr_sanitize_utf8_latin1(talloc_ctx, bstr0(title));
|
||||
NSString *nstitle = [NSString stringWithUTF8String:btitle.start];
|
||||
@ -381,16 +414,22 @@ int vo_cocoa_config_window(struct vo *vo, uint32_t flags, void *gl_ctx)
|
||||
s->old_dwidth = width;
|
||||
s->old_dheight = height;
|
||||
|
||||
if (!(flags & VOFLAG_HIDDEN) && !s->window)
|
||||
create_window(vo, &geo.win, geo.flags);
|
||||
if (!(flags & VOFLAG_HIDDEN) && !s->window) {
|
||||
create_ui(vo, &geo.win, geo.flags);
|
||||
}
|
||||
|
||||
if (s->window) {
|
||||
if (reset_size)
|
||||
[s->window queueNewVideoSize:NSMakeSize(width, height)];
|
||||
queue_new_video_size(vo, width, height);
|
||||
cocoa_set_window_title(vo, vo_get_window_title(vo));
|
||||
vo_cocoa_fullscreen(vo);
|
||||
cocoa_add_fs_screen_profile_observer(vo);
|
||||
}
|
||||
|
||||
// trigger a resize -> don't set vo->dwidth and vo->dheight directly
|
||||
// since this block is executed asynchrolously to the video
|
||||
// reconfiguration code.
|
||||
s->did_resize = true;
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
@ -460,7 +499,10 @@ static void vo_cocoa_fullscreen(struct vo *vo)
|
||||
vo_cocoa_update_screen_info(vo, NULL);
|
||||
|
||||
if (opts->fs_missioncontrol) {
|
||||
[s->window setFullScreen:opts->fullscreen];
|
||||
if ([s->window conformsToProtocol:@protocol(MpvFullscreen)]) {
|
||||
id<MpvFullscreen> win = (id<MpvFullscreen>) s->window;
|
||||
[win setFullScreen:opts->fullscreen];
|
||||
}
|
||||
} else {
|
||||
draw_changes_after_next_frame(vo);
|
||||
[s->view setFullScreen:opts->fullscreen];
|
||||
@ -606,7 +648,7 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
|
||||
case VOCTRL_SET_UNFS_WINDOW_SIZE: {
|
||||
with_cocoa_lock(vo, ^{
|
||||
int *s = arg;
|
||||
[vo->cocoa->window queueNewVideoSize:NSMakeSize(s[0], s[1])];
|
||||
queue_new_video_size(vo, s[0], s[1]);
|
||||
});
|
||||
return VO_TRUE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user