Skip to content
Snippets Groups Projects
Commit 98f8356b authored by Felix Paul Kühne's avatar Felix Paul Kühne
Browse files

notify: update macOS plugin to use the new playlist

parent 3cfc957b
No related branches found
No related tags found
No related merge requests found
......@@ -4,11 +4,11 @@
* This plugin provides support for macOS notifications on current playlist
* item changes.
*****************************************************************************
* Copyright © 2008, 2011, 2012, 2015, 2018 the VideoLAN team
* Copyright © 2008, 2011, 2012, 2015, 2018, 2019 the VideoLAN team
*
* Authors: Rafaël Carré <funman@videolanorg>
* Felix Paul Kühne <fkuehne@videolan.org
* Marvin Scholz <epirat07@gmail.com>
* Authors: Marvin Scholz <epirat07@gmail.com>
* Felix Paul Kühne <fkuehne # videolan.org>
* Rafaël Carré <funman@videolanorg>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -31,14 +31,12 @@
# include "config.h"
#endif
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_playlist_legacy.h>
#include <vlc_input.h>
#include <vlc_meta.h>
#include <vlc_playlist.h>
#include <vlc_player.h>
#include <vlc_interface.h>
#include <vlc_url.h>
......@@ -46,14 +44,14 @@
#pragma mark Class interfaces
@interface VLCNotificationDelegate : NSObject <NSUserNotificationCenterDelegate>
{
/** Interface thread, required for skipping to the next item */
intf_thread_t * _Nonnull interfaceThread;
/** Holds the last notification so it can be cleared when the next one is delivered */
NSUserNotification * _Nullable lastNotification;
/** Indicates if VLC is in foreground */
BOOL isInForeground;
NSUserNotification * _Nullable _lastNotification;
/* the playlist reference */
vlc_playlist_t *_p_playlist;
/* the listener ID for playlist notifications */
vlc_playlist_listener_id *_playlistListenerID;
}
/**
......@@ -62,23 +60,43 @@
- (instancetype)initWithInterfaceThread:(intf_thread_t * _Nonnull)intf_thread;
/**
* Delegate method called when the current input changed
* Delegate method called when the current playlist item changed
*/
- (void)currentInputDidChanged:(input_thread_t * _Nonnull)input;
- (void)currentPlaylistItemChanged:(size_t)index;
@end
#pragma mark -
#pragma mark Local prototypes
struct intf_sys_t
{
void *vlcNotificationDelegate;
};
static int InputCurrent(vlc_object_t *, const char *,
vlc_value_t, vlc_value_t, void *);
#pragma mark -
#pragma mark callback
static void
cb_playlist_current_item_changed(vlc_playlist_t *playlist,
ssize_t index,
void *p_data)
{
dispatch_async(dispatch_get_main_queue(), ^{
VLCNotificationDelegate *notificationDelegate = (__bridge VLCNotificationDelegate *)p_data;
[notificationDelegate currentPlaylistItemChanged:index];
});
}
static const struct vlc_playlist_callbacks playlist_callbacks = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
cb_playlist_current_item_changed,
NULL,
NULL,
};
#pragma mark -
#pragma mark C module functions
......@@ -88,7 +106,6 @@ static int InputCurrent(vlc_object_t *, const char *,
static int Open(vlc_object_t *p_this)
{
intf_thread_t *p_intf = (intf_thread_t *)p_this;
playlist_t *p_playlist = pl_Get(p_intf);
intf_sys_t *p_sys = p_intf->p_sys = calloc(1, sizeof(intf_sys_t));
if (!p_sys)
......@@ -106,8 +123,6 @@ static int Open(vlc_object_t *p_this)
p_sys->vlcNotificationDelegate = (__bridge_retained void*)notificationDelegate;
}
var_AddCallback(p_playlist, "input-current", InputCurrent, p_intf);
return VLC_SUCCESS;
}
......@@ -117,12 +132,7 @@ static int Open(vlc_object_t *p_this)
static void Close(vlc_object_t *p_this)
{
intf_thread_t *p_intf = (intf_thread_t *)p_this;
playlist_t *p_playlist = pl_Get(p_intf);
intf_sys_t *p_sys = p_intf->p_sys;
// Remove the callback, this must be done here, before deallocating the
// notification delegate object
var_DelCallback(p_playlist, "input-current", InputCurrent, p_intf);
@autoreleasepool {
// Transfer ownership of notification delegate object back to ARC
......@@ -136,27 +146,6 @@ static void Close(vlc_object_t *p_this)
free(p_sys);
}
/*
* Callback invoked on playlist item change
*/
static int InputCurrent(vlc_object_t *p_this, const char *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *param)
{
intf_thread_t *p_intf = (intf_thread_t *)param;
intf_sys_t *p_sys = p_intf->p_sys;
input_thread_t *p_input = newval.p_address;
VLC_UNUSED(oldval);
@autoreleasepool {
VLCNotificationDelegate *notificationDelegate =
(__bridge VLCNotificationDelegate*)p_sys->vlcNotificationDelegate;
[notificationDelegate currentInputDidChanged:(input_thread_t *)p_input];
}
return VLC_SUCCESS;
}
/**
* Transfers a null-terminated UTF-8 C "string" to a NSString
* in a way that the NSString takes ownership of it.
......@@ -192,18 +181,13 @@ static inline NSString* CharsToNSString(char * _Nullable cStr)
self = [super init];
if (self) {
interfaceThread = intf_thread;
// Subscribe to notifications to determine if VLC is in foreground or not
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationActiveChange:)
name:NSApplicationDidBecomeActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationActiveChange:)
name:NSApplicationDidResignActiveNotification
object:nil];
_p_playlist = vlc_intf_GetMainPlaylist(intf_thread);
vlc_playlist_Lock(_p_playlist);
_playlistListenerID = vlc_playlist_AddListener(_p_playlist,
&playlist_callbacks,
(__bridge void *)self,
YES);
vlc_playlist_Unlock(_p_playlist);
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
}
......@@ -211,36 +195,58 @@ static inline NSString* CharsToNSString(char * _Nullable cStr)
return self;
}
- (void)currentInputDidChanged:(input_thread_t *)input
- (void)dealloc
{
if (!input)
return;
input_item_t *item = input_GetItem(input);
if (!item)
[[NSNotificationCenter defaultCenter] removeObserver:self];
// Clear a remaining lastNotification in Notification Center, if any
if (_lastNotification) {
[[NSUserNotificationCenter defaultUserNotificationCenter]
removeDeliveredNotification:_lastNotification];
_lastNotification = nil;
}
if (_p_playlist) {
if (_playlistListenerID) {
vlc_playlist_Lock(_p_playlist);
vlc_playlist_RemoveListener(_p_playlist, _playlistListenerID);
vlc_playlist_Unlock(_p_playlist);
}
}
}
- (void)currentPlaylistItemChanged:(size_t)index
{
vlc_player_t *player = vlc_playlist_GetPlayer(_p_playlist);
vlc_player_Lock(player);
input_item_t *inputItem = vlc_player_HoldCurrentMedia(player);
vlc_player_Unlock(player);
if (inputItem == NULL) {
return;
}
// Get title, first try now playing
NSString *title = CharsToNSString(input_item_GetNowPlayingFb(item));
NSString *title = CharsToNSString(input_item_GetNowPlayingFb(inputItem));
// Fallback to item title or name
if ([title length] == 0)
title = CharsToNSString(input_item_GetTitleFbName(item));
title = CharsToNSString(input_item_GetTitleFbName(inputItem));
// If there is still not title, do not notify
if (unlikely([title length] == 0))
if (unlikely([title length] == 0)) {
return;
}
// Get artist name
NSString *artist = CharsToNSString(input_item_GetArtist(item));
NSString *artist = CharsToNSString(input_item_GetArtist(inputItem));
// Get album name
NSString *album = CharsToNSString(input_item_GetAlbum(item));
NSString *album = CharsToNSString(input_item_GetAlbum(inputItem));
// Get coverart path
NSString *artPath = nil;
char *psz_arturl = input_item_GetArtURL(item);
char *psz_arturl = input_item_GetArtURL(inputItem);
if (psz_arturl) {
artPath = CharsToNSString(vlc_uri2path(psz_arturl));
free(psz_arturl);
......@@ -259,16 +265,6 @@ static inline NSString* CharsToNSString(char * _Nullable cStr)
[self notifyWithTitle:title description:desc imagePath:artPath];
}
/*
* Called when the applications activity status changes
*/
- (void)applicationActiveChange:(NSNotification *)n {
if (n.name == NSApplicationDidBecomeActiveNotification)
isInForeground = YES;
else if (n.name == NSApplicationDidResignActiveNotification)
isInForeground = NO;
}
/*
* Called when the user interacts with a notification
*/
......@@ -278,7 +274,9 @@ static inline NSString* CharsToNSString(char * _Nullable cStr)
// Check if notification button ("Skip") was clicked
if (notification.activationType == NSUserNotificationActivationTypeActionButtonClicked) {
// Skip to next song
playlist_Next(pl_Get(interfaceThread));
vlc_playlist_Lock(_p_playlist);
vlc_playlist_Next(_p_playlist);
vlc_playlist_Unlock(_p_playlist);
}
}
......@@ -289,10 +287,10 @@ static inline NSString* CharsToNSString(char * _Nullable cStr)
didDeliverNotification:(NSUserNotification *)notification
{
// Only keep the most recent notification in the Notification Center
if (lastNotification)
[center removeDeliveredNotification:lastNotification];
if (_lastNotification)
[center removeDeliveredNotification:_lastNotification];
lastNotification = notification;
_lastNotification = notification;
}
/*
......@@ -335,21 +333,6 @@ static inline NSString* CharsToNSString(char * _Nullable cStr)
deliverNotification:notification];
}
/*
* Cleanup
*/
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
// Clear a remaining lastNotification in Notification Center, if any
if (lastNotification) {
[[NSUserNotificationCenter defaultUserNotificationCenter]
removeDeliveredNotification:lastNotification];
lastNotification = nil;
}
}
@end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment