diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3217aaf30f14e..a196dbba5ce67 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,6 +9,10 @@ endif()
project(client)
+if(APPLE)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum OSX deployment version")
+endif()
+
include(FeatureSummary)
set(CMAKE_XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES)
diff --git a/NEXTCLOUD.cmake b/NEXTCLOUD.cmake
index 40d0f2ff403ca..4b49a32b300b1 100644
--- a/NEXTCLOUD.cmake
+++ b/NEXTCLOUD.cmake
@@ -77,6 +77,6 @@ if(WIN32)
option( BUILD_WIN_TOOLS "Build Win32 migration tools" OFF )
endif()
-if (APPLE)
+if (APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 11.0)
option( BUILD_FILE_PROVIDER_MODULE "Build the macOS virtual files File Provider module" OFF )
endif()
diff --git a/cmake/modules/MacOSXBundleInfo.plist.in b/cmake/modules/MacOSXBundleInfo.plist.in
index e0dba2ef62355..8327c22976671 100644
--- a/cmake/modules/MacOSXBundleInfo.plist.in
+++ b/cmake/modules/MacOSXBundleInfo.plist.in
@@ -5,7 +5,7 @@
NSPrincipalClass
NSApplication
LSMinimumSystemVersion
- 12.0.0
+ 10.13.0
LSUIElement
CFBundleDevelopmentRegion
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 1968683e23415..85115b0a9c9de 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -282,7 +282,11 @@ endif()
IF( APPLE )
list(APPEND client_SRCS cocoainitializer_mac.mm)
- list(APPEND client_SRCS systray.mm)
+ list(APPEND client_SRCS systray_mac_common.mm)
+
+ if (CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.14)
+ list(APPEND client_SRCS systray_mac_usernotifications.mm)
+ endif()
if (BUILD_FILE_PROVIDER_MODULE)
list(APPEND client_SRCS
@@ -678,8 +682,10 @@ if (APPLE)
if (BUILD_FILE_PROVIDER_MODULE)
target_link_libraries(nextcloudCore PUBLIC Qt5::MacExtras "-framework UserNotifications -framework FileProvider")
- else()
+ elseif(CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.14)
target_link_libraries(nextcloudCore PUBLIC Qt5::MacExtras "-framework UserNotifications")
+ else()
+ target_link_libraries(nextcloudCore PUBLIC Qt5::MacExtras)
endif()
endif()
diff --git a/src/gui/systray.cpp b/src/gui/systray.cpp
index 510435ebf1b02..5529964341b52 100644
--- a/src/gui/systray.cpp
+++ b/src/gui/systray.cpp
@@ -74,7 +74,7 @@ void Systray::setTrayEngine(QQmlApplicationEngine *trayEngine)
Systray::Systray()
: QSystemTrayIcon(nullptr)
{
-#if defined(Q_OS_MACOS) && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
+#if defined(Q_OS_MACOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
setUserNotificationCenterDelegate();
checkNotificationAuth(MacNotificationAuthorizationOptions::Default); // No provisional auth, ask user explicitly first time
registerNotificationCategories(QString(tr("Download")));
@@ -517,7 +517,7 @@ void Systray::showMessage(const QString &title, const QString &message, MessageI
QDBusConnection::sessionBus().asyncCall(method);
} else
#endif
-#if defined(Q_OS_MACOS) && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
+#if defined(Q_OS_MACOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
if (canOsXSendUserNotification()) {
sendOsXUserNotification(title, message);
} else
@@ -529,7 +529,7 @@ void Systray::showMessage(const QString &title, const QString &message, MessageI
void Systray::showUpdateMessage(const QString &title, const QString &message, const QUrl &webUrl)
{
-#if defined(Q_OS_MACOS) && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
+#if defined(Q_OS_MACOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
sendOsXUpdateNotification(title, message, webUrl);
#else // TODO: Implement custom notifications (i.e. actionable) for other OSes
Q_UNUSED(webUrl);
@@ -539,7 +539,7 @@ void Systray::showUpdateMessage(const QString &title, const QString &message, co
void Systray::showTalkMessage(const QString &title, const QString &message, const QString &token, const QString &replyTo, const AccountStatePtr &accountState)
{
-#if defined(Q_OS_MACOS) && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
+#if defined(Q_OS_MACOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
sendOsXTalkNotification(title, message, token, replyTo, accountState);
#else // TODO: Implement custom notifications (i.e. actionable) for other OSes
Q_UNUSED(replyTo)
diff --git a/src/gui/systray.h b/src/gui/systray.h
index 87592e935dc4d..2056b7175eee7 100644
--- a/src/gui/systray.h
+++ b/src/gui/systray.h
@@ -40,6 +40,7 @@ class AccessManagerFactory : public QQmlNetworkAccessManagerFactory
};
#ifdef Q_OS_MACOS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14
enum MacNotificationAuthorizationOptions {
Default = 0,
Provisional
@@ -52,6 +53,7 @@ bool canOsXSendUserNotification();
void sendOsXUserNotification(const QString &title, const QString &message);
void sendOsXUpdateNotification(const QString &title, const QString &message, const QUrl &webUrl);
void sendOsXTalkNotification(const QString &title, const QString &message, const QString &token, const QString &replyTo, const AccountStatePtr accountState);
+#endif
void setTrayWindowLevelAndVisibleOnAllSpaces(QWindow *window);
double menuBarThickness();
#endif
diff --git a/src/gui/systray_mac_common.mm b/src/gui/systray_mac_common.mm
new file mode 100644
index 0000000000000..8189acd10951e
--- /dev/null
+++ b/src/gui/systray_mac_common.mm
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 by Claudio Cambra
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * for more details.
+ */
+
+#include
+
+#import
+
+#include "systray.h"
+
+Q_LOGGING_CATEGORY(lcMacSystrayCommon, "nextcloud.gui.macsystraycommon")
+
+namespace OCC {
+
+double menuBarThickness()
+{
+ NSMenu * const mainMenu = [[NSApplication sharedApplication] mainMenu];
+
+ if (mainMenu == nil) {
+ // Return this educated guess if something goes wrong.
+ // As of macOS 12.4 this will always return 22, even on notched Macbooks.
+ qCWarning(lcMacSystrayCommon) << "Got nil for main menu. "
+ << "Going with reasonable menu bar height guess.";
+ return NSStatusBar.systemStatusBar.thickness;
+ }
+
+ return mainMenu.menuBarHeight;
+}
+
+void setTrayWindowLevelAndVisibleOnAllSpaces(QWindow *const window)
+{
+ NSView * const nativeView = (NSView *)window->winId();
+ NSWindow * const nativeWindow = (NSWindow *)(nativeView.window);
+ [nativeWindow setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorIgnoresCycle |
+ NSWindowCollectionBehaviorTransient];
+ [nativeWindow setLevel:NSMainMenuWindowLevel];
+}
+
+bool osXInDarkMode()
+{
+ NSString * const osxMode = [NSUserDefaults.standardUserDefaults stringForKey:@"AppleInterfaceStyle"];
+ return [osxMode containsString:@"Dark"];
+}
+
+}
diff --git a/src/gui/systray.mm b/src/gui/systray_mac_usernotifications.mm
similarity index 78%
rename from src/gui/systray.mm
rename to src/gui/systray_mac_usernotifications.mm
index 707e3269fd429..3d02272c6b312 100644
--- a/src/gui/systray.mm
+++ b/src/gui/systray_mac_usernotifications.mm
@@ -1,18 +1,32 @@
-#include "QtCore/qurl.h"
+/*
+ * Copyright (C) 2023 by Claudio Cambra
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * for more details.
+ */
+
+#include
+#include
+#include
+
+#import
+#import
+
#include "account.h"
#include "accountstate.h"
#include "accountmanager.h"
#include "config.h"
#include "systray.h"
#include "tray/talkreply.h"
-#include
-#include
-#include
-
-#import
-#import
-Q_LOGGING_CATEGORY(lcMacSystray, "nextcloud.gui.macsystray")
+Q_LOGGING_CATEGORY(lcMacSystrayUserNotifications, "nextcloud.gui.macsystrayusernotifications")
/************************* Private utility functions *************************/
@@ -21,16 +35,16 @@
void sendTalkReply(UNNotificationResponse *response, UNNotificationContent* content)
{
if (!response || !content) {
- qCWarning(lcMacSystray()) << "Invalid notification response or content."
- << "Can't send talk reply.";
+ qCWarning(lcMacSystrayUserNotifications) << "Invalid notification response or content."
+ << "Can't send talk reply.";
return;
}
UNTextInputNotificationResponse * const textInputResponse = (UNTextInputNotificationResponse*)response;
if (!textInputResponse) {
- qCWarning(lcMacSystray()) << "Notification response was not a text input response."
- << "Can't send talk reply.";
+ qCWarning(lcMacSystrayUserNotifications) << "Notification response was not a text input response."
+ << "Can't send talk reply.";
return;
}
@@ -47,16 +61,16 @@ void sendTalkReply(UNNotificationResponse *response, UNNotificationContent* cont
const auto accountState = OCC::AccountManager::instance()->accountFromUserId(qAccount);
if (!accountState) {
- qCWarning(lcMacSystray()) << "Could not find account matching" << qAccount
- << "Can't send talk reply.";
+ qCWarning(lcMacSystrayUserNotifications) << "Could not find account matching" << qAccount
+ << "Can't send talk reply.";
return;
}
- qCDebug(lcMacSystray()) << "Sending talk reply from macOS notification."
- << "Reply is:" << qReply
- << "Replying to:" << qReplyTo
- << "Token:" << qToken
- << "Account:" << qAccount;
+ qCDebug(lcMacSystrayUserNotifications) << "Sending talk reply from macOS notification."
+ << "Reply is:" << qReply
+ << "Replying to:" << qReplyTo
+ << "Token:" << qToken
+ << "Account:" << qAccount;
// OCC::TalkReply deletes itself once it's done, fire and forget
const auto talkReply = new OCC::TalkReply(accountState.data(), OCC::Systray::instance());
@@ -76,7 +90,7 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 110000
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_11_0
completionHandler(UNNotificationPresentationOptionSound + UNNotificationPresentationOptionBanner);
#else
completionHandler(UNNotificationPresentationOptionSound + UNNotificationPresentationOptionAlert);
@@ -87,13 +101,16 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
- qCDebug(lcMacSystray()) << "Received notification with category identifier:" << response.notification.request.content.categoryIdentifier
- << "and action identifier" << response.actionIdentifier;
+ qCDebug(lcMacSystrayUserNotifications) << "Received notification with category identifier:"
+ << response.notification.request.content.categoryIdentifier
+ << "and action identifier"
+ << response.actionIdentifier;
+
UNNotificationContent * const content = response.notification.request.content;
if ([content.categoryIdentifier isEqualToString:@"UPDATE"]) {
if ([response.actionIdentifier isEqualToString:@"DOWNLOAD_ACTION"] || [response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) {
- qCDebug(lcMacSystray()) << "Opening update download url in browser.";
+ qCDebug(lcMacSystrayUserNotifications) << "Opening update download url in browser.";
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[content.userInfo objectForKey:@"webUrl"]]];
}
} else if ([content.categoryIdentifier isEqualToString:@"TALK_MESSAGE"]) {
@@ -111,20 +128,6 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
namespace OCC {
-double menuBarThickness()
-{
- NSMenu * const mainMenu = [[NSApplication sharedApplication] mainMenu];
-
- if (mainMenu == nil) {
- // Return this educated guess if something goes wrong.
- // As of macOS 12.4 this will always return 22, even on notched Macbooks.
- qCWarning(lcMacSystray) << "Got nil for main menu. Going with reasonable menu bar height guess.";
- return NSStatusBar.systemStatusBar.thickness;
- }
-
- return mainMenu.menuBarHeight;
-}
-
// TODO: Get this to actually check for permissions
bool canOsXSendUserNotification()
{
@@ -181,12 +184,12 @@ void checkNotificationAuth(MacNotificationAuthorizationOptions additionalAuthOpt
[center requestAuthorizationWithOptions:(authOptions) completionHandler:^(BOOL granted, NSError * _Nullable error) {
// Enable or disable features based on authorization.
if (granted) {
- qCDebug(lcMacSystray) << "Authorization for notifications has been granted, can display notifications.";
+ qCDebug(lcMacSystrayUserNotifications) << "Authorization for notifications has been granted, can display notifications.";
} else {
- qCDebug(lcMacSystray) << "Authorization for notifications not granted.";
+ qCDebug(lcMacSystrayUserNotifications) << "Authorization for notifications not granted.";
if (error) {
const auto errorDescription = QString::fromNSString(error.localizedDescription);
- qCDebug(lcMacSystray) << "Error from notification center: " << errorDescription;
+ qCDebug(lcMacSystrayUserNotifications) << "Error from notification center: " << errorDescription;
}
}
}];
@@ -266,19 +269,4 @@ void sendOsXTalkNotification(const QString &title, const QString &message, const
[center addNotificationRequest:request withCompletionHandler:nil];
}
-void setTrayWindowLevelAndVisibleOnAllSpaces(QWindow *window)
-{
- NSView * const nativeView = (NSView *)window->winId();
- NSWindow * const nativeWindow = (NSWindow *)(nativeView.window);
- [nativeWindow setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorIgnoresCycle |
- NSWindowCollectionBehaviorTransient];
- [nativeWindow setLevel:NSMainMenuWindowLevel];
-}
-
-bool osXInDarkMode()
-{
- NSString * const osxMode = [NSUserDefaults.standardUserDefaults stringForKey:@"AppleInterfaceStyle"];
- return [osxMode containsString:@"Dark"];
-}
-
} // OCC namespace