mac/apphub: migrate remaining events functionality to new AppHub

add new app_bridge objc file for bridging between mpv core and app
functionality. replace old EventsResponder singleton with AppHub.

another step to clean up all App functionality and have one central
place for it.
This commit is contained in:
der richter 2024-03-23 20:09:15 +01:00
parent deb9d30e90
commit 7e07e1a087
14 changed files with 167 additions and 224 deletions

View File

@ -50,7 +50,7 @@
#include "common/common.h" #include "common/common.h"
#if HAVE_COCOA #if HAVE_COCOA
#include "osdep/mac/events.h" #include "osdep/mac/app_bridge.h"
#endif #endif
#define input_lock(ictx) mp_mutex_lock(&ictx->mutex) #define input_lock(ictx) mp_mutex_lock(&ictx->mutex)

View File

@ -400,7 +400,7 @@ if features['cocoa']
'osdep/path-mac.m', 'osdep/path-mac.m',
'osdep/utils-mac.c', 'osdep/utils-mac.c',
'osdep/mac/application.m', 'osdep/mac/application.m',
'osdep/mac/events.m') 'osdep/mac/app_bridge.m')
main_fn_source = files('osdep/main-fn-mac.c') main_fn_source = files('osdep/main-fn-mac.c')
endif endif
@ -1517,9 +1517,10 @@ features += {'swift': swift.allowed()}
swift_sources = [] swift_sources = []
if features['cocoa'] and features['swift'] if features['cocoa'] and features['swift']
swift_sources += files('osdep/mac/libmpv_helper.swift', swift_sources += files('osdep/mac/app_hub.swift',
'osdep/mac/event_helper.swift', 'osdep/mac/event_helper.swift',
'osdep/mac/input_helper.swift', 'osdep/mac/input_helper.swift',
'osdep/mac/libmpv_helper.swift',
'osdep/mac/log_helper.swift', 'osdep/mac/log_helper.swift',
'osdep/mac/menu_bar.swift', 'osdep/mac/menu_bar.swift',
'osdep/mac/option_helper.swift', 'osdep/mac/option_helper.swift',

View File

@ -20,12 +20,10 @@
#ifndef MAC_EVENTS #ifndef MAC_EVENTS
#define MAC_EVENTS #define MAC_EVENTS
struct input_ctx; #include "input/input.h"
struct mpv_handle;
void cocoa_init_media_keys(void); void cocoa_init_media_keys(void);
void cocoa_uninit_media_keys(void); void cocoa_uninit_media_keys(void);
void cocoa_set_input_context(struct input_ctx *input_context); void cocoa_set_input_context(struct input_ctx *input_context);
void cocoa_set_mpv_handle(struct mpv_handle *ctx); void cocoa_set_mpv_handle(struct mpv_handle *ctx);
void cocoa_init_cocoa_cb(void); void cocoa_init_cocoa_cb(void);

View File

@ -17,19 +17,34 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>. * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/ */
#import <Cocoa/Cocoa.h> #include "config.h"
#include "osdep/mac/events.h"
@class RemoteCommandCenter; #include "osdep/mac/app_bridge.h"
@class InputHelper; #if HAVE_SWIFT
struct input_ctx; #include "osdep/mac/swift.h"
#endif
@interface EventsResponder : NSObject void cocoa_init_media_keys(void)
{
[[AppHub shared] startRemote];
}
+ (EventsResponder *)sharedInstance; void cocoa_uninit_media_keys(void)
- (void)setIsApplication:(BOOL)isApplication; {
[[AppHub shared] stopRemote];
}
@property(nonatomic, retain) RemoteCommandCenter *remoteCommandCenter; void cocoa_set_input_context(struct input_ctx *input_context)
@property(nonatomic, retain) InputHelper *inputHelper; {
[[AppHub shared] initInput:input_context];
}
@end void cocoa_set_mpv_handle(struct mpv_handle *ctx)
{
[[AppHub shared] initMpv:ctx];
}
void cocoa_init_cocoa_cb(void)
{
[[AppHub shared] initCocoaCb];
}

109
osdep/mac/app_hub.swift Normal file
View File

@ -0,0 +1,109 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
class AppHub: NSObject {
@objc static let shared = AppHub()
var mpv: OpaquePointer?
@objc var input: InputHelper
#if HAVE_MACOS_MEDIA_PLAYER
var remote: RemoteCommandCenter?
#endif
var isApplication: Bool { get { NSApp is Application } }
private override init() {
input = InputHelper()
}
@objc func initMpv(_ mpv: OpaquePointer) {
if isApplication {
self.mpv = mpv
mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE)
mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE)
mpv_observe_property(mpv, 0, "speed", MPV_FORMAT_DOUBLE)
mpv_observe_property(mpv, 0, "pause", MPV_FORMAT_FLAG)
mpv_observe_property(mpv, 0, "media-title", MPV_FORMAT_STRING)
mpv_observe_property(mpv, 0, "chapter-metadata/title", MPV_FORMAT_STRING)
mpv_observe_property(mpv, 0, "metadata/by-key/album", MPV_FORMAT_STRING)
mpv_observe_property(mpv, 0, "metadata/by-key/artist", MPV_FORMAT_STRING)
mpv_set_wakeup_callback(mpv, wakeup, TypeHelper.bridge(obj: self))
return
}
mpv_destroy(mpv)
}
@objc func initInput(_ input: OpaquePointer?) {
self.input.signal(input: input)
}
@objc func initCocoaCb() {
guard let app = NSApp as? Application else { return }
DispatchQueue.main.sync { app.initCocoaCb(mpv) }
}
@objc func startRemote() {
#if HAVE_MACOS_MEDIA_PLAYER
if remote == nil { remote = RemoteCommandCenter() }
remote?.start()
#endif
}
@objc func stopRemote() {
#if HAVE_MACOS_MEDIA_PLAYER
remote?.stop()
#endif
}
let wakeup: EventHelper.wakeup_cb = { ( ctx ) in
let event = unsafeBitCast(ctx, to: AppHub.self)
DispatchQueue.main.async { event.eventLoop() }
}
func eventLoop() {
while let mpv = mpv, let event = mpv_wait_event(mpv, 0) {
if event.pointee.event_id == MPV_EVENT_NONE { break }
handle(event: event)
}
}
func handle(event: UnsafeMutablePointer<mpv_event>) {
if let app = NSApp as? Application {
app.processEvent(event)
}
#if HAVE_MACOS_MEDIA_PLAYER
if let remote = remote {
remote.processEvent(event)
}
#endif
switch event.pointee.event_id {
case MPV_EVENT_SHUTDOWN:
#if HAVE_MACOS_COCOA_CB
if let app = NSApp as? Application, app.cocoaCB?.isShuttingDown ?? false {
mpv = nil;
return
}
#endif
mpv_destroy(mpv)
mpv = nil
default: break
}
}
}

View File

@ -26,7 +26,6 @@
#include "options/options.h" #include "options/options.h"
#import "osdep/mac/application_objc.h" #import "osdep/mac/application_objc.h"
#import "osdep/mac/events_objc.h"
#include "osdep/threads.h" #include "osdep/threads.h"
#include "osdep/main-fn.h" #include "osdep/main-fn.h"
@ -87,7 +86,7 @@ static mp_thread playback_thread_id;
@interface Application () @interface Application ()
{ {
EventsResponder *_eventsResponder; AppHub *_appHub;
} }
@end @end
@ -112,15 +111,15 @@ static void terminate_cocoa_application(void)
- (void)sendEvent:(NSEvent *)event - (void)sendEvent:(NSEvent *)event
{ {
if ([self modalWindow] || ![_eventsResponder.inputHelper processKeyWithEvent:event]) if ([self modalWindow] || ![_appHub.input processKeyWithEvent:event])
[super sendEvent:event]; [super sendEvent:event];
[_eventsResponder.inputHelper wakeup]; [_appHub.input wakeup];
} }
- (id)init - (id)init
{ {
if (self = [super init]) { if (self = [super init]) {
_eventsResponder = [EventsResponder sharedInstance]; _appHub = [AppHub shared];
NSAppleEventManager *em = [NSAppleEventManager sharedAppleEventManager]; NSAppleEventManager *em = [NSAppleEventManager sharedAppleEventManager];
[em setEventHandler:self [em setEventHandler:self
@ -203,7 +202,7 @@ static const char mac_icon[] =
- (void)handleQuitEvent:(NSAppleEventDescriptor *)event - (void)handleQuitEvent:(NSAppleEventDescriptor *)event
withReplyEvent:(NSAppleEventDescriptor *)replyEvent withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{ {
if (![_eventsResponder.inputHelper command:@"quit"]) if (![_appHub.input command:@"quit"])
terminate_cocoa_application(); terminate_cocoa_application();
} }
@ -219,7 +218,7 @@ static const char mac_icon[] =
range:NSMakeRange(0, [MPV_PROTOCOL length])]; range:NSMakeRange(0, [MPV_PROTOCOL length])];
url = [url stringByRemovingPercentEncoding]; url = [url stringByRemovingPercentEncoding];
[_eventsResponder.inputHelper openWithFiles:@[url]]; [_appHub.input openWithFiles:@[url]];
} }
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
@ -231,7 +230,7 @@ static const char mac_icon[] =
SEL cmpsel = @selector(localizedStandardCompare:); SEL cmpsel = @selector(localizedStandardCompare:);
NSArray *files = [filenames sortedArrayUsingSelector:cmpsel]; NSArray *files = [filenames sortedArrayUsingSelector:cmpsel];
[_eventsResponder.inputHelper openWithFiles:files]; [_appHub.input openWithFiles:files];
} }
@end @end
@ -315,7 +314,6 @@ int cocoa_main(int argc, char *argv[])
{ {
@autoreleasepool { @autoreleasepool {
application_instantiated = true; application_instantiated = true;
[[EventsResponder sharedInstance] setIsApplication:YES];
struct playback_thread_ctx ctx = {0}; struct playback_thread_ctx ctx = {0};
ctx.argc = &argc; ctx.argc = &argc;
@ -332,7 +330,7 @@ int cocoa_main(int argc, char *argv[])
} }
mp_thread_create(&playback_thread_id, playback_thread, &ctx); mp_thread_create(&playback_thread_id, playback_thread, &ctx);
[[EventsResponder sharedInstance].inputHelper wait]; [[AppHub shared].input wait];
cocoa_run_runloop(); cocoa_run_runloop();
// This should never be reached: cocoa_run_runloop blocks until the // This should never be reached: cocoa_run_runloop blocks until the

View File

@ -1,185 +0,0 @@
/*
* Cocoa Application Event Handling
*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#import <Cocoa/Cocoa.h>
#include "mpv_talloc.h"
#include "input/event.h"
#include "input/input.h"
#include "player/client.h"
#import "osdep/mac/events_objc.h"
#import "osdep/mac/application_objc.h"
#include "config.h"
#if HAVE_SWIFT
#include "osdep/mac/swift.h"
#endif
@interface EventsResponder ()
{
struct mpv_handle *_ctx;
BOOL _is_application;
}
- (BOOL)setMpvHandle:(struct mpv_handle *)ctx;
- (void)initCocoaCb;
- (void)readEvents;
- (void)startMediaKeys;
- (void)stopMediaKeys;
@end
void cocoa_init_media_keys(void)
{
[[EventsResponder sharedInstance] startMediaKeys];
}
void cocoa_uninit_media_keys(void)
{
[[EventsResponder sharedInstance] stopMediaKeys];
}
void cocoa_set_input_context(struct input_ctx *input_context)
{
[[EventsResponder sharedInstance].inputHelper signalWithInput:input_context];
}
static void wakeup(void *context)
{
[[EventsResponder sharedInstance] readEvents];
}
void cocoa_set_mpv_handle(struct mpv_handle *ctx)
{
if ([[EventsResponder sharedInstance] setMpvHandle:ctx]) {
mpv_observe_property(ctx, 0, "duration", MPV_FORMAT_DOUBLE);
mpv_observe_property(ctx, 0, "time-pos", MPV_FORMAT_DOUBLE);
mpv_observe_property(ctx, 0, "speed", MPV_FORMAT_DOUBLE);
mpv_observe_property(ctx, 0, "pause", MPV_FORMAT_FLAG);
mpv_observe_property(ctx, 0, "media-title", MPV_FORMAT_STRING);
mpv_observe_property(ctx, 0, "chapter-metadata/title", MPV_FORMAT_STRING);
mpv_observe_property(ctx, 0, "metadata/by-key/album", MPV_FORMAT_STRING);
mpv_observe_property(ctx, 0, "metadata/by-key/artist", MPV_FORMAT_STRING);
mpv_set_wakeup_callback(ctx, wakeup, NULL);
}
}
void cocoa_init_cocoa_cb(void)
{
[[EventsResponder sharedInstance] initCocoaCb];
}
@implementation EventsResponder
@synthesize remoteCommandCenter = _remoteCommandCenter;
@synthesize inputHelper = _inputHelper;
+ (EventsResponder *)sharedInstance
{
static EventsResponder *responder = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
responder = [EventsResponder new];
responder.inputHelper = [[InputHelper alloc] init: nil :nil];
});
return responder;
}
- (void)setIsApplication:(BOOL)isApplication
{
_is_application = isApplication;
}
- (BOOL)setMpvHandle:(struct mpv_handle *)ctx
{
if (_is_application) {
_ctx = ctx;
return YES;
}
mpv_destroy(ctx);
return NO;
}
- (void)initCocoaCb
{
if (_is_application) {
dispatch_sync(dispatch_get_main_queue(), ^{
[NSApp initCocoaCb:_ctx];
});
}
}
- (void)readEvents
{
dispatch_async(dispatch_get_main_queue(), ^{
while (_ctx) {
mpv_event *event = mpv_wait_event(_ctx, 0);
if (event->event_id == MPV_EVENT_NONE)
break;
[self processEvent:event];
}
});
}
-(void)processEvent:(struct mpv_event *)event
{
if(_is_application) {
[NSApp processEvent:event];
}
if (_remoteCommandCenter) {
[_remoteCommandCenter processEvent:event];
}
switch (event->event_id) {
case MPV_EVENT_SHUTDOWN: {
#if HAVE_MACOS_COCOA_CB
if ([(Application *)NSApp cocoaCB].isShuttingDown) {
_ctx = nil;
return;
}
#endif
mpv_destroy(_ctx);
_ctx = nil;
break;
}
default:
break;
}
}
- (void)startMediaKeys
{
#if HAVE_MACOS_MEDIA_PLAYER
if (_remoteCommandCenter == nil) {
_remoteCommandCenter = [[RemoteCommandCenter alloc] init];
}
#endif
[_remoteCommandCenter start];
}
- (void)stopMediaKeys
{
[_remoteCommandCenter stop];
}
@end

View File

@ -318,7 +318,7 @@ class MenuBar: NSObject {
@objc func quit(_ menuItem: MenuItem) { @objc func quit(_ menuItem: MenuItem) {
guard let menuConfig = menuItem.config else { return } guard let menuConfig = menuItem.config else { return }
EventsResponder.sharedInstance().inputHelper.command(menuConfig.command) AppHub.shared.input.command(menuConfig.command)
} }
@objc func openFiles() { @objc func openFiles() {
@ -327,7 +327,7 @@ class MenuBar: NSObject {
panel.canChooseDirectories = true panel.canChooseDirectories = true
if panel.runModal() == .OK { if panel.runModal() == .OK {
EventsResponder.sharedInstance().inputHelper.open(files: panel.urls.map { $0.path }) AppHub.shared.input.open(files: panel.urls.map { $0.path })
} }
} }
@ -335,7 +335,7 @@ class MenuBar: NSObject {
let panel = NSOpenPanel() let panel = NSOpenPanel()
if panel.runModal() == .OK, let url = panel.urls.first { if panel.runModal() == .OK, let url = panel.urls.first {
EventsResponder.sharedInstance().inputHelper.command("loadlist \"\(url.path)\"") AppHub.shared.input.command("loadlist \"\(url.path)\"")
} }
} }
@ -355,13 +355,13 @@ class MenuBar: NSObject {
} }
if alert.runModal() == .alertFirstButtonReturn && input.stringValue.count > 0 { if alert.runModal() == .alertFirstButtonReturn && input.stringValue.count > 0 {
EventsResponder.sharedInstance().inputHelper.open(files: [input.stringValue]) AppHub.shared.input.open(files: [input.stringValue])
} }
} }
@objc func command(_ menuItem: MenuItem) { @objc func command(_ menuItem: MenuItem) {
guard let menuConfig = menuItem.config else { return } guard let menuConfig = menuItem.config else { return }
EventsResponder.sharedInstance().inputHelper.command(menuConfig.command) AppHub.shared.input.command(menuConfig.command)
} }
@objc func url(_ menuItem: MenuItem) { @objc func url(_ menuItem: MenuItem) {

View File

@ -19,10 +19,18 @@ if get_option('optimization') != '0'
swift_flags += '-O' swift_flags += '-O'
endif endif
if macos_cocoa_cb.allowed()
swift_flags += ['-D', 'HAVE_MACOS_COCOA_CB']
endif
if macos_touchbar.allowed() if macos_touchbar.allowed()
swift_flags += ['-D', 'HAVE_MACOS_TOUCHBAR'] swift_flags += ['-D', 'HAVE_MACOS_TOUCHBAR']
endif endif
if macos_media_player.allowed()
swift_flags += ['-D', 'HAVE_MACOS_MEDIA_PLAYER']
endif
extra_flags = get_option('swift-flags').split() extra_flags = get_option('swift-flags').split()
swift_flags += extra_flags swift_flags += extra_flags

View File

@ -155,7 +155,7 @@ class RemoteCommandCenter: NSObject {
self.configs[event.command]?.state = state self.configs[event.command]?.state = state
} }
EventsResponder.sharedInstance().inputHelper.put(key: config.key | Int32(state)) AppHub.shared.input.put(key: config.key | Int32(state))
return .success return .success
} }
@ -166,7 +166,7 @@ class RemoteCommandCenter: NSObject {
} }
let cmd = String(format: "seek %.02f absolute", posEvent.positionTime) let cmd = String(format: "seek %.02f absolute", posEvent.positionTime)
return EventsResponder.sharedInstance().inputHelper.command(cmd) ? .success : .commandFailed return AppHub.shared.input.command(cmd) ? .success : .commandFailed
} }
@objc func processEvent(_ event: UnsafeMutablePointer<mpv_event>) { @objc func processEvent(_ event: UnsafeMutablePointer<mpv_event>) {

View File

@ -32,7 +32,6 @@
#include "video/out/win_state.h" #include "video/out/win_state.h"
#include "osdep/mac/application_objc.h" #include "osdep/mac/application_objc.h"
#include "osdep/mac/events_objc.h"
// complex macros won't get imported to Swift so we have to reassign them // complex macros won't get imported to Swift so we have to reassign them

View File

@ -225,12 +225,12 @@ class TouchBar: NSTouchBar, NSTouchBarDelegate {
@objc func buttonAction(_ button: NSButton) { @objc func buttonAction(_ button: NSButton) {
guard let identifier = getIdentifierFrom(view: button), let command = configs[identifier]?.command else { return } guard let identifier = getIdentifierFrom(view: button), let command = configs[identifier]?.command else { return }
EventsResponder.sharedInstance().inputHelper.command(command) AppHub.shared.input.command(command)
} }
@objc func seekbarChanged(_ slider: NSSlider) { @objc func seekbarChanged(_ slider: NSSlider) {
guard let identifier = getIdentifierFrom(view: slider), let command = configs[identifier]?.command else { return } guard let identifier = getIdentifierFrom(view: slider), let command = configs[identifier]?.command else { return }
EventsResponder.sharedInstance().inputHelper.command(String(format: command, slider.doubleValue)) AppHub.shared.input.command(String(format: command, slider.doubleValue))
} }
func format(time: Int) -> String { func format(time: Int) -> String {

View File

@ -71,7 +71,7 @@ static const char def_config[] =
; ;
#if HAVE_COCOA #if HAVE_COCOA
#include "osdep/mac/events.h" #include "osdep/mac/app_bridge.h"
#endif #endif
#ifndef FULLCONFIG #ifndef FULLCONFIG

View File

@ -28,7 +28,7 @@
#include "libmpv.h" #include "libmpv.h"
#if HAVE_MACOS_COCOA_CB #if HAVE_MACOS_COCOA_CB
#include "osdep/mac/events.h" #include "osdep/mac/app_bridge.h"
#endif #endif
/* /*