diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9f357a752..2447627dd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -805,6 +805,7 @@ jobs:
-DICU_ROOT="${{env.prefix_path}}"
-DAPPLE_DEVELOPER_ID=$(test '${{github.repository}}' = 'strawberrymusicplayer/strawberry' && test '${{github.event.pull_request.base.repo.full_name}}' = '${{github.event.pull_request.head.repo.full_name}}' && echo "383J84DVB6" || echo "")
-DENABLE_SPOTIFY=$(test -f "${{env.prefix_path}}/lib/gstreamer-1.0/libgstspotify.dylib" && echo "ON" || echo "OFF")
+ -DARCH="${{env.arch}}"
- name: Build
run: cmake --build build --config Release --parallel 4
@@ -944,6 +945,7 @@ jobs:
-DICU_ROOT="${{env.prefix_path}}"
-DAPPLE_DEVELOPER_ID="383J84DVB6"
-DENABLE_SPOTIFY=$(test -f "${{env.prefix_path}}/lib/gstreamer-1.0/libgstspotify.dylib" && echo "ON" || echo "OFF")
+ -DARCH="${{env.arch}}"
- name: Build
run: cmake --build build --config Release --parallel 4
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ca9c92a2f..6ef36d8c9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -266,9 +266,10 @@ else()
add_definitions(-DKDSINGLEAPPLICATION_STATIC_BUILD)
endif()
-# if(APPLE)
-# find_package(SPMediaKeyTap REQUIRED)
-# endif()
+if(APPLE)
+ find_library(SPARKLE Sparkle)
+ #find_package(SPMediaKeyTap REQUIRED)
+endif()
if(WIN32)
find_package(getopt-win REQUIRED)
@@ -353,6 +354,13 @@ optional_component(EBUR128 ON "EBU R 128 loudness normalization"
DEPENDS "libebur128" LIBEBUR128_FOUND
)
+if(APPLE)
+ optional_component(SPARKLE ON "Sparkle integration"
+ DEPENDS "macOS" APPLE
+ DEPENDS "Sparkle" SPARKLE
+ )
+endif()
+
if(HAVE_SONGFINGERPRINTING OR HAVE_MUSICBRAINZ)
set(HAVE_CHROMAPRINT ON)
endif()
@@ -1198,6 +1206,7 @@ if(APPLE)
src/osd/osdmac.h
src/device/macosdevicelister.h
)
+ optional_source(HAVE_SPARKLE SOURCES src/core/sparkleupdater.mm HEADERS src/core/sparkleupdater.h)
else()
list(APPEND SOURCES src/systemtrayicon/qtsystemtrayicon.cpp src/widgets/searchfield_qt.cpp src/widgets/searchfield_qt_private.cpp)
list(APPEND HEADERS src/systemtrayicon/qtsystemtrayicon.h src/widgets/searchfield_qt_private.h)
@@ -1534,6 +1543,10 @@ if(APPLE)
"-framework IOKit"
"-framework ScriptingBridge"
)
+ if(HAVE_SPARKLE)
+ target_include_directories(strawberry_lib SYSTEM PRIVATE ${SPARKLE}/Headers)
+ target_link_libraries(strawberry_lib PRIVATE ${SPARKLE})
+ endif()
endif()
target_link_libraries(strawberry PUBLIC strawberry_lib)
diff --git a/dist/macos/Info.plist.in b/dist/macos/Info.plist.in
index 5fd0ef089..abfcd4dfe 100644
--- a/dist/macos/Info.plist.in
+++ b/dist/macos/Info.plist.in
@@ -35,9 +35,9 @@
LSMinimumSystemVersion
@LSMinimumSystemVersion@
SUFeedURL
- https://www.strawberrymusicplayer.org/sparkle-macos
+ https://www.strawberrymusicplayer.org/sparkle-macos-@ARCH@
SUPublicEDKey
- 3IRScV8YtNVnx7zoeJAXvg28Kh1gN/Pyl2iPM467pG8=
+ /OydhYVfypuO2Mf7G6DUqVZWW9G19eFV74qaDCBTOUk=
CFBundleURLTypes
diff --git a/src/config.h.in b/src/config.h.in
index 4b5371acd..492829e87 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -18,6 +18,7 @@
#cmakedefine HAVE_AUDIOCD
#cmakedefine HAVE_MTP
#cmakedefine HAVE_GPOD
+#cmakedefine HAVE_SPARKLE
#cmakedefine HAVE_QTSPARKLE
#cmakedefine HAVE_SONGFINGERPRINTING
#cmakedefine HAVE_MUSICBRAINZ
diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp
index c2ecdb93e..93d31a8d4 100644
--- a/src/core/mainwindow.cpp
+++ b/src/core/mainwindow.cpp
@@ -220,6 +220,10 @@
# include "systemtrayicon/qtsystemtrayicon.h"
#endif
+#ifdef HAVE_SPARKLE
+ #include "core/sparkleupdater.h"
+#endif
+
#ifdef HAVE_QTSPARKLE
# include
#endif // HAVE_QTSPARKLE
@@ -833,9 +837,9 @@ MainWindow::MainWindow(Application *app, SharedPtr tray_icon, OS
thumbbar_->SetActions(QList() << ui_->action_previous_track << ui_->action_play_pause << ui_->action_stop << ui_->action_next_track << nullptr << ui_->action_love);
#endif
-#if defined(HAVE_QTSPARKLE)
- QAction *check_updates = ui_->menu_tools->addAction(tr("Check for updates..."));
- check_updates->setMenuRole(QAction::ApplicationSpecificRole);
+#if defined(HAVE_SPARKLE) || defined(HAVE_QTSPARKLE)
+ QAction *action_check_updates = ui_->menu_tools->addAction(tr("Check for updates..."));
+ action_check_updates->setMenuRole(QAction::ApplicationSpecificRole);
#endif
#ifdef HAVE_GLOBALSHORTCUTS
@@ -1046,13 +1050,18 @@ MainWindow::MainWindow(Application *app, SharedPtr tray_icon, OS
app_->scrobbler()->Submit();
}
+#ifdef HAVE_SPARKLE
+ SparkleUpdater *sparkle_updater = new SparkleUpdater(action_check_updates, this);
+ QObject::connect(action_check_updates, &QAction::triggered, sparkle_updater, &SparkleUpdater::CheckForUpdates);
+#endif
+
#ifdef HAVE_QTSPARKLE
QUrl sparkle_url(QString::fromLatin1(QTSPARKLE_URL));
if (!sparkle_url.isEmpty()) {
qLog(Debug) << "Creating Qt Sparkle updater";
qtsparkle::Updater *updater = new qtsparkle::Updater(sparkle_url, this);
updater->SetVersion(QStringLiteral(STRAWBERRY_VERSION_PACKAGE));
- QObject::connect(check_updates, &QAction::triggered, updater, &qtsparkle::Updater::CheckNow);
+ QObject::connect(action_check_updates, &QAction::triggered, updater, &qtsparkle::Updater::CheckNow);
}
#endif
diff --git a/src/core/sparkleupdater.h b/src/core/sparkleupdater.h
new file mode 100644
index 000000000..eb1ecb46e
--- /dev/null
+++ b/src/core/sparkleupdater.h
@@ -0,0 +1,48 @@
+/*
+ * Strawberry Music Player
+ * Copyright 2025, Jonas Kvinge
+ *
+ * Strawberry 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Strawberry 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Strawberry. If not, see .
+ *
+ */
+
+#ifndef SPARKLEUPDATER_H
+#define SPARKLEUPDATER_H
+
+#include
+
+class QAction;
+
+#ifdef __OBJC__
+@class AppUpdaterDelegate;
+#endif
+
+class SparkleUpdater : public QObject {
+ Q_OBJECT
+
+ public:
+ explicit SparkleUpdater(QAction *action_check_updates, QObject *parent = nullptr);
+
+ public Q_SLOTS:
+ void CheckForUpdates();
+
+ private:
+#ifdef __OBJC__
+ AppUpdaterDelegate *updater_delegate_;
+#else
+ void *updater_delegate_;
+#endif
+};
+
+#endif // SPARKLEUPDATER_H
diff --git a/src/core/sparkleupdater.mm b/src/core/sparkleupdater.mm
new file mode 100644
index 000000000..b7efc0074
--- /dev/null
+++ b/src/core/sparkleupdater.mm
@@ -0,0 +1,79 @@
+/*
+ * Strawberry Music Player
+ * Copyright 2025, Jonas Kvinge
+ *
+ * Strawberry 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Strawberry 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Strawberry. If not, see .
+ *
+ */
+
+#import
+
+#include
+#include
+
+#include "sparkleupdater.h"
+
+@interface AppUpdaterDelegate : NSObject
+
+@property(nonatomic, assign) SPUStandardUpdaterController *updater_controller;
+
+@end
+
+@implementation AppUpdaterDelegate
+
+- (void)observeCanCheckForUpdatesWithAction:(QAction*)action_check_updates {
+ [_updater_controller.updater addObserver:self forKeyPath:NSStringFromSelector(@selector(canCheckForUpdates)) options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:(void*)action_check_updates];
+}
+
+- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context {
+
+ if ([keyPath isEqualToString:NSStringFromSelector(@selector(canCheckForUpdates))]) {
+ QAction *action = reinterpret_cast(context);
+ action->setEnabled(_updater_controller.updater.canCheckForUpdates);
+ }
+ else {
+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+ }
+
+}
+
+- (void)dealloc {
+
+ @autoreleasepool {
+ [_updater_controller.updater removeObserver:self forKeyPath:NSStringFromSelector(@selector(canCheckForUpdates))];
+ }
+
+ [super dealloc];
+
+}
+
+@end
+
+SparkleUpdater::SparkleUpdater(QAction *action_check_updates, QObject *parent) : QObject(parent) {
+
+ @autoreleasepool {
+ updater_delegate_ = [[AppUpdaterDelegate alloc] init];
+ updater_delegate_.updater_controller = [[SPUStandardUpdaterController alloc] initWithStartingUpdater:YES updaterDelegate:updater_delegate_ userDriverDelegate:nil];
+ [updater_delegate_ observeCanCheckForUpdatesWithAction:action_check_updates];
+ }
+
+}
+
+void SparkleUpdater::CheckForUpdates() {
+
+ @autoreleasepool {
+ [updater_delegate_.updater_controller checkForUpdates:nil];
+ }
+
+}