From 6625a318ac5bf53fcdea0fd9dec2f70251655c44 Mon Sep 17 00:00:00 2001 From: redPanther Date: Tue, 1 Aug 2017 17:29:47 +0200 Subject: [PATCH] hyperiond desktop integration (#453) * add deployment * add correct api key * fix cmake lists and add heroku app name * Update .gitmodules sync modules with upstream * add possibility to start hyperiond as systray app * cleanup * - new command line options: --desktop --service to set desired mode (systray icon / console only) - auto detect x server - if avail run in gui mode - on osx always run in gui mode - use existing icon from webconfig, instead of own icon - add ability to no gice a config file name. If config not given, default config file will be set (home dir, or hyperiond dir, depending on writable state) * fix warnings and compile error * use own icon for systray purpose * use new logo * - set application properties - fix force service mode --- include/grabber/V4L2Grabber.h | 2 +- include/utils/Image.h | 1 + include/webconfig/WebConfig.h | 2 + libsrc/grabber/v4l2/V4L2Grabber.cpp | 2 +- libsrc/hyperion/hyperion-icon_32px.png | Bin 0 -> 4717 bytes libsrc/hyperion/resource.qrc | 1 + src/hyperiond/CMakeLists.txt | 4 + src/hyperiond/hyperiond.cpp | 10 +- src/hyperiond/hyperiond.h | 5 + src/hyperiond/main.cpp | 122 ++++++++++++++++++---- src/hyperiond/systray.cpp | 136 +++++++++++++++++++++++++ src/hyperiond/systray.h | 50 +++++++++ 12 files changed, 307 insertions(+), 28 deletions(-) create mode 100644 libsrc/hyperion/hyperion-icon_32px.png create mode 100644 src/hyperiond/systray.cpp create mode 100644 src/hyperiond/systray.h diff --git a/include/grabber/V4L2Grabber.h b/include/grabber/V4L2Grabber.h index 36c2f8a9..3a877eed 100644 --- a/include/grabber/V4L2Grabber.h +++ b/include/grabber/V4L2Grabber.h @@ -147,8 +147,8 @@ private: double _y_frac_min; double _x_frac_max; double _y_frac_max; + int _currentFrame; - int _currentFrame; QSocketNotifier * _streamNotifier; ImageResampler _imageResampler; diff --git a/include/utils/Image.h b/include/utils/Image.h index e8c82e48..f4c5183e 100644 --- a/include/utils/Image.h +++ b/include/utils/Image.h @@ -5,6 +5,7 @@ #include #include #include +#include #include diff --git a/include/webconfig/WebConfig.h b/include/webconfig/WebConfig.h index b29c89cb..c9b58bfe 100644 --- a/include/webconfig/WebConfig.h +++ b/include/webconfig/WebConfig.h @@ -18,6 +18,8 @@ public: void start(); void stop(); + quint16 getPort() { return _port; }; + private: Hyperion* _hyperion; QString _baseUrl; diff --git a/libsrc/grabber/v4l2/V4L2Grabber.cpp b/libsrc/grabber/v4l2/V4L2Grabber.cpp index d5234530..4bd98509 100644 --- a/libsrc/grabber/v4l2/V4L2Grabber.cpp +++ b/libsrc/grabber/v4l2/V4L2Grabber.cpp @@ -49,12 +49,12 @@ V4L2Grabber::V4L2Grabber(const QString & device , _noSignalThresholdColor(ColorRgb{0,0,0}) , _signalDetectionEnabled(true) , _noSignalDetected(false) + , _noSignalCounter(0) , _x_frac_min(0.25) , _y_frac_min(0.25) , _x_frac_max(0.75) , _y_frac_max(0.75) , _currentFrame(0) - , _noSignalCounter(0) , _streamNotifier(nullptr) , _imageResampler() , _log(Logger::getInstance("V4L2:"+device)) diff --git a/libsrc/hyperion/hyperion-icon_32px.png b/libsrc/hyperion/hyperion-icon_32px.png new file mode 100644 index 0000000000000000000000000000000000000000..12196277a588b306ec07c1b8533df7ed631826c4 GIT binary patch literal 4717 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 + hyperion-icon_32px.png hyperion.schema.json ../../config/hyperion.config.json.default schema/schema-general.json diff --git a/src/hyperiond/CMakeLists.txt b/src/hyperiond/CMakeLists.txt index 2bf5b991..d99ed863 100644 --- a/src/hyperiond/CMakeLists.txt +++ b/src/hyperiond/CMakeLists.txt @@ -1,7 +1,9 @@ add_executable(hyperiond hyperiond.h + systray.h hyperiond.cpp + systray.cpp main.cpp ) @@ -42,6 +44,8 @@ if (ENABLE_X11) target_link_libraries(hyperiond x11-grabber ) endif () +qt5_use_modules(hyperiond Core Gui Network Widgets) + install ( TARGETS hyperiond DESTINATION "share/hyperion/bin/" COMPONENT "${PLATFORM}" ) install ( DIRECTORY ${CMAKE_SOURCE_DIR}/bin/service DESTINATION "share/hyperion/" COMPONENT "${PLATFORM}" ) install ( FILES ${CMAKE_SOURCE_DIR}/effects/readme.txt DESTINATION "share/hyperion/effects" COMPONENT "${PLATFORM}" ) diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index 25f200de..ff73e813 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -137,7 +137,7 @@ void HyperionDaemon::run() void HyperionDaemon::loadConfig(const QString & configFile) { - Info(_log, "Selected configuration file: %s", configFile.toUtf8().constData()); + Info(_log, "Selected configuration file: %s", QSTRING_CSTR(configFile)); // make sure the resources are loaded (they may be left out after static linking) Q_INIT_RESOURCE(resource); @@ -224,7 +224,7 @@ void HyperionDaemon::startInitialEffect() else { int result = hyperion->setEffect(fgEffectConfig, FG_PRIORITY, fg_duration_ms); - Info(_log,"Inital foreground effect '%s' %s", fgEffectConfig.toUtf8().constData(), ((result == 0) ? "started" : "failed")); + Info(_log,"Inital foreground effect '%s' %s", QSTRING_CSTR(fgEffectConfig), ((result == 0) ? "started" : "failed")); } } // initial background effect/color @@ -246,7 +246,7 @@ void HyperionDaemon::startInitialEffect() else { int result = hyperion->setEffect(bgEffectConfig, BG_PRIORITY, DURATION_INFINITY); - Info(_log,"Inital background effect '%s' %s", bgEffectConfig.toUtf8().constData(), ((result == 0) ? "started" : "failed")); + Info(_log,"Inital background effect '%s' %s", QSTRING_CSTR(bgEffectConfig), ((result == 0) ? "started" : "failed")); } } @@ -435,7 +435,7 @@ void HyperionDaemon::createSystemFrameGrabber() { type = "framebuffer"; } - Info( _log, "set screen capture device to '%s'", type.toUtf8().constData()); + Info( _log, "set screen capture device to '%s'", QSTRING_CSTR(type)); } bool grabberCompState = grabberConfig["enable"].toBool(true); @@ -445,7 +445,7 @@ void HyperionDaemon::createSystemFrameGrabber() else if (type == "amlogic") { createGrabberAmlogic(); createGrabberFramebuffer(grabberConfig); } else if (type == "osx") createGrabberOsx(grabberConfig); else if (type == "x11") createGrabberX11(grabberConfig); - else { Warning( _log, "unknown framegrabber type '%s'", type.toUtf8().constData()); grabberCompState = false; } + else { Warning( _log, "unknown framegrabber type '%s'", QSTRING_CSTR(type)); grabberCompState = false; } // _hyperion->getComponentRegister().componentStateChanged(hyperion::COMP_GRABBER, grabberCompState); _hyperion->setComponentState(hyperion::COMP_GRABBER, grabberCompState ); diff --git a/src/hyperiond/hyperiond.h b/src/hyperiond/hyperiond.h index 2e69fb98..f774ea9f 100644 --- a/src/hyperiond/hyperiond.h +++ b/src/hyperiond/hyperiond.h @@ -48,9 +48,14 @@ #include #include +class SysTray; + class HyperionDaemon : public QObject { Q_OBJECT + + friend SysTray; + public: HyperionDaemon(QString configFile, QObject *parent=nullptr); ~HyperionDaemon(); diff --git a/src/hyperiond/main.cpp b/src/hyperiond/main.cpp index df8a1c37..cee1858c 100644 --- a/src/hyperiond/main.cpp +++ b/src/hyperiond/main.cpp @@ -11,12 +11,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include "HyperionConfig.h" @@ -26,7 +28,12 @@ #include #include +#ifdef ENABLE_X11 +#include +#endif + #include "hyperiond.h" +#include "systray.h" using namespace commandline; @@ -58,6 +65,54 @@ void startNewHyperion(int parentPid, std::string hyperionFile, std::string confi } } +QCoreApplication* createApplication(int &argc, char *argv[]) +{ + bool isGuiApp = false; + bool forceNoGui = false; + // command line + for (int i = 1; i < argc; ++i) + { + if (qstrcmp(argv[i], "--desktop") == 0) + { + isGuiApp = true; + } + else if (qstrcmp(argv[i], "--service") == 0) + { + isGuiApp = false; + forceNoGui = true; + } + } + + // on osx/windows gui always available +#if defined(__APPLE__) || defined(__WIN32__) + isGuiApp = true && ! forceNoGui; +#else + if (!forceNoGui) + { + // if x11, then test if xserver is available + #ifdef ENABLE_X11 + Display* dpy = XOpenDisplay(NULL); + if (dpy != NULL) + { + XCloseDisplay(dpy); + isGuiApp = true; + } + } + #endif +#endif + + if (isGuiApp) + { + QApplication* app = new QApplication(argc, argv); + app->setApplicationDisplayName("Hyperion"); + return app; + } + + QCoreApplication* app = new QCoreApplication(argc, argv); + app->setApplicationName("Hyperion"); + app->setApplicationVersion(HYPERION_VERSION); + return app; +} int main(int argc, char** argv) { @@ -68,7 +123,8 @@ int main(int argc, char** argv) Logger::setLogLevel(Logger::WARNING); // Initialising QCoreApplication - QCoreApplication app(argc, argv); + QScopedPointer app(createApplication(argc, argv)); + bool isGuiApp = (qobject_cast(app.data()) != 0 && QSystemTrayIcon::isSystemTrayAvailable()); signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); @@ -88,14 +144,16 @@ int main(int argc, char** argv) BooleanOption & silentOption = parser.add('s', "silent", "do not print any outputs"); BooleanOption & verboseOption = parser.add('v', "verbose", "Increase verbosity"); BooleanOption & debugOption = parser.add('d', "debug", "Show debug messages"); + parser.add(0x0, "desktop", "show systray on desktop"); + parser.add(0x0, "service", "force hyperion to start as console service"); Option & exportConfigOption = parser.add