diff --git a/.github/workflows/push-master.yml b/.github/workflows/push-master.yml
index 615b531fa..67968c1b4 100644
--- a/.github/workflows/push-master.yml
+++ b/.github/workflows/push-master.yml
@@ -181,7 +181,7 @@ jobs:
if: ( matrix.QT_VERSION == 5 )
shell: bash
run: |
- export Qt5_DIR=`brew --prefix qt5`;
+ export Qt5_DIR=`brew --prefix qt@5`;
echo "Qt5_DIR=$Qt5_DIR" >> $GITHUB_ENV
# Build process
diff --git a/cmake/packages.cmake b/cmake/packages.cmake
index 57eb0c551..c8192db20 100644
--- a/cmake/packages.cmake
+++ b/cmake/packages.cmake
@@ -117,11 +117,12 @@ endif()
if ( ENABLE_CEC )
string(CONCAT CPACK_DEBIAN_PACKAGE_RECOMMENDS "${CPACK_DEBIAN_PACKAGE_RECOMMENDS}" ", libp8-platform-dev" )
endif()
+
+SET ( CPACK_DEBIAN_PACKAGE_SUGGESTS "libx11-6" )
if ( ENABLE_SYSTRAY )
- string(CONCAT CPACK_DEBIAN_PACKAGE_RECOMMENDS "${CPACK_DEBIAN_PACKAGE_RECOMMENDS}" ", libgtk-3-0" )
+ string(CONCAT CPACK_DEBIAN_PACKAGE_SUGGESTS "${CPACK_DEBIAN_PACKAGE_SUGGESTS}" ", libgtk-3-0" )
endif()
-SET ( CPACK_DEBIAN_PACKAGE_SUGGESTS "libx11-6" )
SET ( CPACK_DEBIAN_PACKAGE_SECTION "Miscellaneous" )
# .rpm for rpm
diff --git a/resources/icons/hyperhdr-tray-icon.svg b/resources/icons/hyperhdr-tray-icon.svg
new file mode 100644
index 000000000..611ce163f
--- /dev/null
+++ b/resources/icons/hyperhdr-tray-icon.svg
@@ -0,0 +1,7 @@
+
+
+
diff --git a/sources/grabber/AVF/AVFGrabber.mm b/sources/grabber/AVF/AVFGrabber.mm
index 9091f8559..d1e126327 100644
--- a/sources/grabber/AVF/AVFGrabber.mm
+++ b/sources/grabber/AVF/AVFGrabber.mm
@@ -153,7 +153,7 @@ - (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleB
if (_isAVF)
{
if (!_permission)
- QTimer::singleShot(5000, this, &AVFGrabber::getPermission);
+ QMetaObject::invokeMethod(this, [this]{ QTimer::singleShot(5000, this, &AVFGrabber::getPermission); });
else
{
Info(_log, "Got the video permission. Now trying to start HyperHDR's video grabber.");
diff --git a/sources/hyperhdr/SystrayHandler.cpp b/sources/hyperhdr/SystrayHandler.cpp
index 8318c2d0b..5ed99c8de 100644
--- a/sources/hyperhdr/SystrayHandler.cpp
+++ b/sources/hyperhdr/SystrayHandler.cpp
@@ -35,6 +35,10 @@
#include
#endif
+#ifdef __APPLE__
+ #include
+#endif
+
#include
#include
#include
@@ -147,41 +151,22 @@ void SystrayHandler::close()
}
}
-static void loadPng(std::unique_ptr& menu, QString filename, QString rootFolder)
+static void loadSvg(std::unique_ptr& menu, QString filename, QString rootFolder , QString destFilename = "")
{
-#ifdef __linux__
- QString fullPath = rootFolder + "/icons/" + QFileInfo(filename).fileName();
- QFileInfo iconFile(fullPath);
- QDir dir(iconFile.absolutePath());
- if (!dir.exists())
- dir.mkpath(".");
-
- if (!iconFile.exists())
- {
- QFile stream(filename);
- stream.open(QIODevice::ReadOnly);
- QByteArray ar = stream.readAll();
- stream.close();
-
- QFile newIcon(fullPath);
- newIcon.open(QIODevice::WriteOnly);
- newIcon.write(ar);
- newIcon.close();
- }
- menu->label = fullPath.toStdString();
-#else
- QFile stream(filename);
- stream.open(QIODevice::ReadOnly);
- QByteArray ar = stream.readAll();
- stream.close();
- menu->icon.resize(ar.size());
- memcpy(menu->icon.data(), ar.data(), ar.size());
+#ifdef __linux__
+ int iconDim = 16;
+ #else
+ #ifdef __APPLE__
+ int iconDim = 18;
+ #else
+ int iconDim = 18;
+
+ if (filename == ":/hyperhdr-tray-icon.svg")
+ iconDim = 36;
+ #endif
#endif
-}
-static void loadSvg(std::unique_ptr& menu, QString filename, QString rootFolder , QString destFilename = "")
-{
#ifdef __linux__
if (destFilename.isEmpty())
{
@@ -199,7 +184,7 @@ static void loadSvg(std::unique_ptr& menu, QString filename, QStrin
QByteArray ar;
QBuffer buffer(&ar);
buffer.open(QIODevice::WriteOnly);
- HyperImage::svg2png(filename, 16, 16, buffer);
+ HyperImage::svg2png(filename, iconDim, iconDim, buffer);
QFile newIcon(fullPath);
newIcon.open(QIODevice::WriteOnly);
@@ -212,7 +197,7 @@ static void loadSvg(std::unique_ptr& menu, QString filename, QStrin
QByteArray ar;
QBuffer buffer(&ar);
buffer.open(QIODevice::WriteOnly);
- HyperImage::svg2png(filename, 18, 18, buffer);
+ HyperImage::svg2png(filename, iconDim, iconDim, buffer);
menu->icon.resize(ar.size());
memcpy(menu->icon.data(), ar.data(), ar.size());
@@ -226,8 +211,7 @@ void SystrayHandler::createSystray()
std::unique_ptr mainMenu = std::unique_ptr(new SystrayMenu);
- // main icon
- loadPng(mainMenu, ":/hyperhdr-icon-32px.png", _rootFolder);
+ loadSvg(mainMenu, ":/hyperhdr-tray-icon.svg", _rootFolder);
// settings menu
std::unique_ptr settingsMenu = std::unique_ptr(new SystrayMenu);
@@ -467,7 +451,7 @@ void SystrayHandler::setColor(ColorRgb color)
{
std::shared_ptr instanceManager = _instanceManager.lock();
if (instanceManager)
- instanceManager->setInstanceColor(_selectedInstance, 1, color, 0);
+ QUEUE_CALL_4(instanceManager.get(), setInstanceColor, int, _selectedInstance, int, 1, ColorRgb, color, int, 0);
}
@@ -508,6 +492,19 @@ void SystrayHandler::settings()
printf("xdg-open failed. xdg-utils package is required.\n");
}
#endif
+
+#ifdef __APPLE__
+ std::string slink = link.toStdString();
+ CFURLRef url = CFURLCreateWithBytes(
+ NULL,
+ (UInt8*)slink.c_str(),
+ slink.length(),
+ kCFStringEncodingASCII,
+ NULL
+ );
+ LSOpenCFURLRef(url, 0);
+ CFRelease(url);
+#endif
#ifndef _WIN32
// restoring stdout
@@ -521,14 +518,14 @@ void SystrayHandler::setEffect(QString effect)
{
std::shared_ptr instanceManager = _instanceManager.lock();
if (instanceManager)
- instanceManager->setInstanceEffect(_selectedInstance, effect, 1);
+ QUEUE_CALL_3(instanceManager.get(), setInstanceEffect, int, _selectedInstance, QString, effect, int, 1);
}
void SystrayHandler::clearEfxColor()
{
std::shared_ptr instanceManager = _instanceManager.lock();
if (instanceManager)
- instanceManager->clearInstancePriority(_selectedInstance, 1);
+ QUEUE_CALL_2(instanceManager.get(), clearInstancePriority, int, _selectedInstance, int, 1);
}
void SystrayHandler::signalInstanceStateChangedHandler(InstanceState state, quint8 instance, const QString& name)
diff --git a/sources/hyperhdr/main.cpp b/sources/hyperhdr/main.cpp
index 308ea4810..1261f5092 100644
--- a/sources/hyperhdr/main.cpp
+++ b/sources/hyperhdr/main.cpp
@@ -330,7 +330,7 @@ int main(int argc, char** argv)
}
catch (std::exception& e)
{
- Error(log, "HyperHdr Daemon aborted: %s", e.what());
+ Error(log, "Main HyperHDR service aborted: %s", e.what());
throw;
}
@@ -340,10 +340,12 @@ int main(int argc, char** argv)
if (systray != nullptr && systray->isInitialized())
{
QTimer* timer = new QTimer(systray);
- timer->setInterval(300);
QObject::connect(timer, &QTimer::timeout, systray, [&systray]() {
- systray->loop();
- });
+ systray->loop();
+ });
+
+ timer->setInterval(200);
+ timer->start();
rc = app->exec();
diff --git a/sources/systray/SystrayMacOS.mm b/sources/systray/SystrayMacOS.mm
index 62e5ca3ca..05140a249 100644
--- a/sources/systray/SystrayMacOS.mm
+++ b/sources/systray/SystrayMacOS.mm
@@ -25,12 +25,130 @@
* SOFTWARE.
*/
+#include
#include
+#include
-bool SystrayInitialize(SystrayMenu* tray){return false;}
+@interface MenuDelegate: NSObject
+- (void)clicked:(NSMenuItem*)sender;
+@end
+@implementation MenuDelegate{}
+ - (void)clicked:(NSMenuItem*)sender
+ {
+ id representedObject = sender.representedObject;
+ struct SystrayMenu* pTrayMenu = (struct SystrayMenu*)[representedObject pointerValue];
+ if (pTrayMenu != NULL && pTrayMenu->callback != NULL)
+ {
+ pTrayMenu->callback(pTrayMenu);
+ }
+ }
+@end
-int SystrayLoop() { return 0; }
+namespace
+{
+ MenuDelegate* menuDelegate;
+ NSApplication* app;
+ NSStatusBar* statusBar;
+ NSStatusItem* statusItem;
+}
-void SystrayUpdate(SystrayMenu* tray){}
+static NSMenu* nativeMenu(struct SystrayMenu* m) {
+ NSMenu* menu = [[NSMenu alloc] init];
+ [menu setAutoenablesItems:FALSE];
-void SystrayClose(){}
+ for (; m != NULL && !m->label.empty(); m = m->next.get())
+ {
+ std::string labelText = " " + m->label;
+ labelText.erase(std::remove(labelText.begin(), labelText.end(), '&'), labelText.end());
+
+ if (m->label == "-")
+ {
+ [menu addItem:[NSMenuItem separatorItem]];
+ }
+ else
+ {
+ NSString* labelNS = [NSString stringWithUTF8String: labelText.c_str()];
+ NSMenuItem* menuItem = [[NSMenuItem alloc] init];
+ [menuItem setTitle:labelNS];
+ [menuItem setEnabled:m->isDisabled == 0 ? TRUE : FALSE];
+ [menuItem setState:m->isChecked == 1 ? TRUE : FALSE];
+ [menuItem setRepresentedObject:[NSValue valueWithPointer:m]];
+
+ if (m->icon.size())
+ {
+ auto* data = [NSData dataWithBytes: m->icon.data()
+ length: m->icon.size()];
+
+ NSImage* image = [[NSImage alloc] initWithData:data];
+ [menuItem setImage: image ];
+ }
+
+ if (m->callback != NULL)
+ {
+ [menuItem setTarget:menuDelegate];
+ [menuItem setAction:@selector(clicked:)];
+ }
+ [menu addItem:menuItem];
+ if (m->submenu != NULL)
+ {
+ [menu setSubmenu:nativeMenu(m->submenu.get()) forItem:menuItem];
+ }
+ }
+ }
+ return menu;
+}
+
+bool SystrayInitialize(SystrayMenu* tray)
+{
+ menuDelegate = [[MenuDelegate alloc] init];
+ app = [NSApplication sharedApplication];
+ statusBar = [NSStatusBar systemStatusBar];
+ statusItem = [statusBar statusItemWithLength:NSVariableStatusItemLength];
+
+ if (tray != nullptr)
+ {
+ SystrayUpdate(tray);
+ }
+
+ return true;
+}
+
+int SystrayLoop()
+{
+ NSDate* until = [NSDate distantPast];
+ NSEvent* event = [app nextEventMatchingMask:ULONG_MAX untilDate:until
+ inMode:[NSString stringWithUTF8String:"kCFRunLoopDefaultMode"] dequeue:TRUE];
+ if (event)
+ {
+ [app sendEvent:event];
+ }
+ return 0;
+}
+
+void SystrayUpdate(SystrayMenu* tray)
+{
+ double iconHeight = [[NSStatusBar systemStatusBar] thickness];
+
+ auto* data = [NSData dataWithBytes:tray->icon.data()
+ length:tray->icon.size()];
+
+ NSImage* image = [[NSImage alloc] initWithData:data];
+
+ if (iconHeight < image.size.height)
+ {
+ std::cout << "Resizing the main icon: " << image.size.width << "x" << image.size.height << " to height=" << iconHeight << "\n";
+ double width = image.size.width * (iconHeight / image.size.height);
+ [image setSize:NSMakeSize(width, iconHeight)];
+ }
+
+ statusItem.button.image = image;
+ if (!tray->tooltip.empty())
+ {
+ statusItem.button.toolTip = [NSString stringWithUTF8String:tray->tooltip.c_str()];
+ }
+ [statusItem setMenu:nativeMenu(tray->submenu.get())];
+}
+
+void SystrayClose()
+{
+}