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"
#if HAVE_COCOA
#include "osdep/mac/events.h"
#include "osdep/mac/app_bridge.h"
#endif
#define input_lock(ictx) mp_mutex_lock(&ictx->mutex)

View File

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

View File

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

View File

@ -17,19 +17,34 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#import <Cocoa/Cocoa.h>
#include "osdep/mac/events.h"
#include "config.h"
@class RemoteCommandCenter;
@class InputHelper;
struct input_ctx;
#include "osdep/mac/app_bridge.h"
#if HAVE_SWIFT
#include "osdep/mac/swift.h"
#endif
@interface EventsResponder : NSObject
void cocoa_init_media_keys(void)
{
[[AppHub shared] startRemote];
}
+ (EventsResponder *)sharedInstance;
- (void)setIsApplication:(BOOL)isApplication;
void cocoa_uninit_media_keys(void)
{
[[AppHub shared] stopRemote];
}
@property(nonatomic, retain) RemoteCommandCenter *remoteCommandCenter;
@property(nonatomic, retain) InputHelper *inputHelper;
void cocoa_set_input_context(struct input_ctx *input_context)
{
[[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"
#import "osdep/mac/application_objc.h"
#import "osdep/mac/events_objc.h"
#include "osdep/threads.h"
#include "osdep/main-fn.h"
@ -87,7 +86,7 @@ static mp_thread playback_thread_id;
@interface Application ()
{
EventsResponder *_eventsResponder;
AppHub *_appHub;
}
@end
@ -112,15 +111,15 @@ static void terminate_cocoa_application(void)
- (void)sendEvent:(NSEvent *)event
{
if ([self modalWindow] || ![_eventsResponder.inputHelper processKeyWithEvent:event])
if ([self modalWindow] || ![_appHub.input processKeyWithEvent:event])
[super sendEvent:event];
[_eventsResponder.inputHelper wakeup];
[_appHub.input wakeup];
}
- (id)init
{
if (self = [super init]) {
_eventsResponder = [EventsResponder sharedInstance];
_appHub = [AppHub shared];
NSAppleEventManager *em = [NSAppleEventManager sharedAppleEventManager];
[em setEventHandler:self
@ -203,7 +202,7 @@ static const char mac_icon[] =
- (void)handleQuitEvent:(NSAppleEventDescriptor *)event
withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
if (![_eventsResponder.inputHelper command:@"quit"])
if (![_appHub.input command:@"quit"])
terminate_cocoa_application();
}
@ -219,7 +218,7 @@ static const char mac_icon[] =
range:NSMakeRange(0, [MPV_PROTOCOL length])];
url = [url stringByRemovingPercentEncoding];
[_eventsResponder.inputHelper openWithFiles:@[url]];
[_appHub.input openWithFiles:@[url]];
}
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
@ -231,7 +230,7 @@ static const char mac_icon[] =
SEL cmpsel = @selector(localizedStandardCompare:);
NSArray *files = [filenames sortedArrayUsingSelector:cmpsel];
[_eventsResponder.inputHelper openWithFiles:files];
[_appHub.input openWithFiles:files];
}
@end
@ -315,7 +314,6 @@ int cocoa_main(int argc, char *argv[])
{
@autoreleasepool {
application_instantiated = true;
[[EventsResponder sharedInstance] setIsApplication:YES];
struct playback_thread_ctx ctx = {0};
ctx.argc = &argc;
@ -332,7 +330,7 @@ int cocoa_main(int argc, char *argv[])
}
mp_thread_create(&playback_thread_id, playback_thread, &ctx);
[[EventsResponder sharedInstance].inputHelper wait];
[[AppHub shared].input wait];
cocoa_run_runloop();
// 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) {
guard let menuConfig = menuItem.config else { return }
EventsResponder.sharedInstance().inputHelper.command(menuConfig.command)
AppHub.shared.input.command(menuConfig.command)
}
@objc func openFiles() {
@ -327,7 +327,7 @@ class MenuBar: NSObject {
panel.canChooseDirectories = true
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()
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 {
EventsResponder.sharedInstance().inputHelper.open(files: [input.stringValue])
AppHub.shared.input.open(files: [input.stringValue])
}
}
@objc func command(_ menuItem: MenuItem) {
guard let menuConfig = menuItem.config else { return }
EventsResponder.sharedInstance().inputHelper.command(menuConfig.command)
AppHub.shared.input.command(menuConfig.command)
}
@objc func url(_ menuItem: MenuItem) {

View File

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

View File

@ -155,7 +155,7 @@ class RemoteCommandCenter: NSObject {
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
}
@ -166,7 +166,7 @@ class RemoteCommandCenter: NSObject {
}
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>) {

View File

@ -32,7 +32,6 @@
#include "video/out/win_state.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

View File

@ -225,12 +225,12 @@ class TouchBar: NSTouchBar, NSTouchBarDelegate {
@objc func buttonAction(_ button: NSButton) {
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) {
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 {

View File

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

View File

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