diff --git a/src/klkt/icons.qrc b/src/klkt/icons.qrc deleted file mode 100644 index f7f3841d4f6245013081d5b10252d94a914b3c69..0000000000000000000000000000000000000000 --- a/src/klkt/icons.qrc +++ /dev/null @@ -1,12 +0,0 @@ -<RCC> - <qresource prefix="/icons"> - <file alias="LICENSE">icons/LICENSE</file> - <file alias="pause.png">icons/pause-fill.png</file> - <file alias="play.png">icons/play-fill.png</file> - <file alias="README">icons/README</file> - <file alias="previous.png">icons/skip-back-mini-fill.png</file> - <file alias="next.png">icons/skip-forward-mini-fill.png</file> - <file alias="stop.png">icons/stop-fill.png</file> - <file alias="shuffle.png">icons/shuffle-line.png</file> - </qresource> -</RCC> diff --git a/src/klkt/icons/LICENSE b/src/klkt/icons/LICENSE deleted file mode 100644 index 261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64..0000000000000000000000000000000000000000 --- a/src/klkt/icons/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/src/klkt/icons/README b/src/klkt/icons/README deleted file mode 100644 index bf4405c87c2c842603273cd493071c089a6a66e5..0000000000000000000000000000000000000000 --- a/src/klkt/icons/README +++ /dev/null @@ -1,2 +0,0 @@ -Icons from https://github.com/Remix-Design/RemixIcon -APACHE 2.0 License, see LICENSE file in this directory. diff --git a/src/klkt/icons/pause-fill.png b/src/klkt/icons/pause-fill.png deleted file mode 100644 index dcf4f380c729f67c6f87c028ff73b8c7f07b7a9d..0000000000000000000000000000000000000000 Binary files a/src/klkt/icons/pause-fill.png and /dev/null differ diff --git a/src/klkt/icons/play-fill.png b/src/klkt/icons/play-fill.png deleted file mode 100644 index 9393efb14bb3db872c5d3536ba8940f95bb13afc..0000000000000000000000000000000000000000 Binary files a/src/klkt/icons/play-fill.png and /dev/null differ diff --git a/src/klkt/icons/shuffle-line.png b/src/klkt/icons/shuffle-line.png deleted file mode 100644 index 9bba2d7dd92327c23d510acdeaa30d81ccc635b8..0000000000000000000000000000000000000000 Binary files a/src/klkt/icons/shuffle-line.png and /dev/null differ diff --git a/src/klkt/icons/skip-back-mini-fill.png b/src/klkt/icons/skip-back-mini-fill.png deleted file mode 100644 index cc7315afa08d3faf1fa333d8503028d8a06f851e..0000000000000000000000000000000000000000 Binary files a/src/klkt/icons/skip-back-mini-fill.png and /dev/null differ diff --git a/src/klkt/icons/skip-forward-mini-fill.png b/src/klkt/icons/skip-forward-mini-fill.png deleted file mode 100644 index fa9a89ecb3221d6c5818866992821d09c8986228..0000000000000000000000000000000000000000 Binary files a/src/klkt/icons/skip-forward-mini-fill.png and /dev/null differ diff --git a/src/klkt/icons/stop-fill.png b/src/klkt/icons/stop-fill.png deleted file mode 100644 index 0fd15cd332493589a7e67e913368517c49fe0e54..0000000000000000000000000000000000000000 Binary files a/src/klkt/icons/stop-fill.png and /dev/null differ diff --git a/src/klkt/klkt.cpp b/src/klkt/klkt.cpp deleted file mode 100644 index 2ffefafbaf2f8e9acc5950f68b0344056b2e07c8..0000000000000000000000000000000000000000 --- a/src/klkt/klkt.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "klkt.hpp" - -#ifdef __linux__ -#include <sys/prctl.h> -#include <signal.h> -#endif - -int -main(int argc, char **argv) -{ -#ifdef __linux__ - /* Dies when the parent dies */ - prctl(PR_SET_PDEATHSIG, SIGHUP); -#endif - - Application app(argc, argv); - int code = app.exec(); - notify_uninit(); - return code; -} diff --git a/src/klkt/klkt.hpp b/src/klkt/klkt.hpp deleted file mode 100644 index b3387d4b93e875b714d0235e463270a93ec270f9..0000000000000000000000000000000000000000 --- a/src/klkt/klkt.hpp +++ /dev/null @@ -1,627 +0,0 @@ -#ifndef APPLICATION_HPP -#define APPLICATION_HPP - -#include <libnotify/notify.h> - -#include <QObject> -#include <QApplication> -#include <QHostAddress> -#include <QSystemTrayIcon> -#include <QIcon> -#include <QPixmap> -#include <QMenu> -#include <QAction> -#include <QList> -#include <QMap> -#include <QTcpSocket> -#include <QTextCodec> -#include <QStandardPaths> -#include <QDir> -#include <QSettings> -#include <QProcess> -#include <QLocalSocket> - -#include <algorithm> -#include <iostream> -#include <stdio.h> - -#include <lektor/common.h> -LKT_PUSH -LKT_IGNORE_WARN_WRITE_STRING -#include <lektor/internal/icon.xpm> -LKT_POP - -static inline const int UTF8_MIB = 106; - -/* Hop();; We wrap the glib types */ -#define URGENCY(x) x = NOTIFY_URGENCY_##x, -enum Urgency { URGENCY(LOW) URGENCY(NORMAL) URGENCY(CRITICAL) }; -#undef URGENCY - -static inline const char * -__urgencyToString(Urgency urg) -{ - switch (urg) { - case Urgency::LOW: return "LOW"; - case Urgency::NORMAL: return "NORMAL"; - case Urgency::CRITICAL: return "CRITICAL"; - default: return "UNKNOWN"; - } -} - -#if defined(Q_OS_LINUX) -/* Restrict libnotify (thus glib...) only to that function */ -static void -sendNotification(const char *name, const char *msg, enum Urgency urgency) -{ - GdkPixbuf *gtk_icon = gdk_pixbuf_new_from_xpm_data(const_cast<const char **>(icon)); - NotifyNotification *notif = notify_notification_new(name, msg, NULL); - notify_notification_set_icon_from_pixbuf(notif, gtk_icon); - notify_notification_set_urgency(notif, static_cast<NotifyUrgency>(urgency)); - notify_notification_show(notif, NULL); - g_object_unref(G_OBJECT(notif)); - g_object_unref(gtk_icon); - fprintf(stdout, "# %s (%s) -> %s\n", name, __urgencyToString(urgency), - QString(msg).replace('\n', "\\n").toStdString().c_str()); - fflush(stdout); -} -#else -#error \ - "System is not supported yet, you need to write a 'sendNotification(const char *, const char *, enum Urgency)' function for that system" -#endif - -/* Config class, the ~/.config/lektor/klkt.ini file */ -class Config final { -private: - static inline const QString opt_host = "lektord/host"; - static inline const QString opt_port = "lektord/port"; - - QString m_host; - qint16 m_port; - -public: - Config(QApplication *app, const QString &file) - { - QSettings settings(file, QSettings::IniFormat, app); - m_host = settings.value(opt_host, "127.0.0.1").toString(); - m_port = settings.value(opt_port, "6600").toInt(); - - settings.setValue(opt_host, m_host); - settings.setValue(opt_port, m_port); - } - - qint16 getPort(void) const { return m_port; } - bool isUnix(void) const { return m_port <= 0; } - const QString &getHost(void) const { return m_host; } -}; - -/* Socket, can be unix socket or tcp socket. Because QIODevice don't have all that what we need */ -class Socket final : public QObject { - Q_OBJECT -private: - enum Type { - Unix, - Tcp, - }; - - /* Can be tcp or unix socket */ - QTcpSocket m_tcp; - QLocalSocket m_unix; - Type m_type; - - /* Where to connect */ - QString m_host; - qint16 m_port; - -public slots: - /* Re-emit signals */ - inline void triggetConnected(void) { emit connected(); } - inline void triggetDisconnected(void) { emit disconnected(); } - inline void triggetReadyRead(void) { emit readyRead(); } - -signals: - /* Used signals from TCP and Unix sockets */ - void connected(void); - void disconnected(void); - void readyRead(void); - -public: - Socket(const QString &host, qint16 port) { reset(host, port); } - - void reset(const QString host, qint16 port) - { - m_host = host; - m_port = port; - - /* Unix specific stuff */ - if (port <= 0) { - m_type = Type::Unix; - connect(&m_unix, &QLocalSocket::connected, this, &Socket::triggetConnected); - connect(&m_unix, &QLocalSocket::disconnected, this, &Socket::triggetDisconnected); - connect(&m_unix, &QLocalSocket::readyRead, this, &Socket::triggetReadyRead); - } - - /* TCP specific stuff */ - else { - m_type = Type::Tcp; - connect(&m_tcp, &QTcpSocket::connected, this, &Socket::triggetConnected); - connect(&m_tcp, &QTcpSocket::disconnected, this, &Socket::triggetDisconnected); - connect(&m_tcp, &QTcpSocket::readyRead, this, &Socket::triggetReadyRead); - } - } - -#define __DIFFERENTIATE(unix, tcp) \ - { \ - switch (m_type) { \ - case Type::Unix: unix; break; \ - case Type::Tcp: tcp; break; \ - } \ - sendNotification("Klkt fatal error", "Unknown socket type", Urgency::CRITICAL); \ - ::exit(EXIT_FAILURE); \ - } - - // clang-format off - inline bool isValid(void) __DIFFERENTIATE({ return m_unix.isValid(); }, { return m_tcp.isValid(); }); - inline QByteArray readAll(void) __DIFFERENTIATE({ return m_unix.readAll(); }, { return m_tcp.readAll(); }); - inline qint64 write(const char *d) __DIFFERENTIATE({ return m_unix.write(d); }, { return m_tcp.write(d); }); - inline void close(void) __DIFFERENTIATE({ return m_unix.close(); }, { return m_tcp.close(); }); - inline void doConnect(void) __DIFFERENTIATE({ return m_unix.connectToServer(m_host); }, - { return m_tcp.connectToHost(m_host, m_port); }); - inline bool waitForConnected(int ms = 30000) __DIFFERENTIATE({ return m_unix.waitForConnected(ms); }, - { return m_tcp.waitForConnected(ms); }); - inline bool waitForDisconnected(int ms = 30000) __DIFFERENTIATE({ return m_unix.waitForDisconnected(ms); }, - { return m_tcp.waitForDisconnected(ms); }); - // clang-format on -#undef __DIFFERENTIATE -}; - -/* Used to generate a notification for the state of lektord and get the currently playing kara */ -class Status final : public QWidget { - Q_OBJECT -private: - Socket m_sock; - QString m_pending_data; - QString m_state; - QMap<QString, QString> m_current_kara; - QMetaObject::Connection m_connect_read; - bool m_deletable = false; - bool m_send_notif = true; - - static inline const char *StatusString = "status\n"; - static inline const char *CurrentString = "currentsong\n"; - - void sendNotification(const char *title, const char *msg, Urgency urg) - { - if (!m_send_notif) - return; - ::sendNotification(title, msg, urg); - } - -private slots: - void connected(void) { m_sock.write(StatusString); } - - void disconnected(void) - { - if (m_deletable) - return; - - if (m_state == "play") { - // m_current_kara["category"] + " - " + m_current_kara["language"] + "\n" + - QString kara = m_current_kara["source"] + "\n" + m_current_kara["type"] + " - " + - m_current_kara["title"] + " [" + m_current_kara["author"] + "]"; - sendNotification("lektord is playing", kara.toStdString().c_str(), Urgency::LOW); - emit changeCurrentKara(kara); - emit changeStatus(Play); - } - - else if (m_state == "stop") { - sendNotification("lektord is stopped", "lektord is not playing", Urgency::LOW); - emit changeCurrentKara("lektord is stopped"); - emit changeStatus(Stop); - } - - else if (m_state == "pause") { - sendNotification("lektord is paused", "lektord is not playing", Urgency::LOW); - emit changeCurrentKara("lektord is paused"); - emit changeStatus(Pause); - } - - else { - sendNotification("lektord error", - tr("lektord has the following unkown state: '%1'") - .arg(m_state) - .toStdString() - .c_str(), - Urgency::CRITICAL); - emit changeCurrentKara(tr("Unknown state: '%1'").arg(m_state)); - emit changeStatus(Unknown); - } - - m_deletable = true; - } - - void readCurrent(void) - { - QByteArray got = m_sock.readAll(); - m_pending_data += QTextCodec::codecForMib(UTF8_MIB)->toUnicode(got); - QStringList lines = m_pending_data.split("\n"); - int return_position; - - for (auto &line : lines) { - return_position = line.length() + 1; - m_pending_data = m_pending_data.right(m_pending_data.length() - return_position); - if (line == "OK" || line.left(3) == "ACK") { - m_sock.close(); - return; - } - - /* Decode line */ -#define DECODE(what) \ - if (line.startsWith(what ": ", Qt::CaseInsensitive)) { \ - line.remove(0, static_cast<int>(strlen(what ": "))); \ - m_current_kara.insert(what, line); \ - } - DECODE("title") - DECODE("author") - DECODE("source") - DECODE("type") - DECODE("category") - DECODE("language") -#undef DECODE - } - } - - void readStatus(void) - { - QByteArray got = m_sock.readAll(); - m_pending_data += QTextCodec::codecForMib(UTF8_MIB)->toUnicode(got); - QStringList lines = m_pending_data.split("\n"); - int return_position; - - for (const auto &line : lines) { - return_position = line.length() + 1; - m_pending_data = m_pending_data.right(m_pending_data.length() - return_position); - if (line == "OK" || line.left(3) == "ACK") { - /* Read the current song if needed */ - if (m_state == "play") { - QWidget::disconnect(m_connect_read); - m_pending_data = ""; - m_connect_read = - QWidget::connect(&m_sock, &Socket::readyRead, this, &Status::readCurrent); - m_sock.write(CurrentString); - } else - m_sock.close(); - return; - } - - QStringList play_state = line.split(": "); - if (play_state.length() == 2 && play_state.at(0) == "state") - m_state = play_state.at(1); - } - } - -public: - Status(const QString &host, qint16 port, bool send_notif = true) - : m_sock(host, port) - , m_send_notif(send_notif) - { - fprintf(stdout, "Query status%s\n", send_notif ? "" : " (no notification)"); - m_sock.doConnect(); - QWidget::connect(&m_sock, &Socket::connected, this, &Status::connected); - QWidget::connect(&m_sock, &Socket::disconnected, this, &Status::disconnected); - m_connect_read = QWidget::connect(&m_sock, &Socket::readyRead, this, &Status::readStatus); - fflush(stdout); - } - - Status &operator=(Status &) = delete; - - inline bool isDeletable(void) const { return m_deletable; } - inline void waitForDisconnected(void) { m_sock.waitForDisconnected(-1); } - - enum { - Pause, - Play, - Stop, - Unknown, - }; - -signals: - void changeCurrentKara(QString); - void changeStatus(int); -}; - -/* Send commends to lektord */ -class Commander final : public QObject { - Q_OBJECT -private: - Socket m_sock; - const char *m_cmd; - - static inline const char *CMD_NEXT = "next\n"; - static inline const char *CMD_PREVIOUS = "previous\n"; - static inline const char *CMD_SHUFFLE = "shuffle\n"; - static inline const char *CMD_FORCE_PLAY = "play\n"; - static inline const char *CMD_TOGGLE = "pause\n"; - - void doCommand(void) - { - fprintf(stdout, "Send command %s", m_cmd); - m_sock.doConnect(); - connect(&m_sock, &Socket::connected, this, [&]() { m_sock.write(m_cmd); }); - connect(&m_sock, &Socket::disconnected, this, [&]() { emit finished(); }); - connect(&m_sock, &Socket::readyRead, this, [&]() { - QStringList lines = - QTextCodec::codecForMib(UTF8_MIB)->toUnicode(m_sock.readAll()).split("\n"); - for (auto &line : lines) { - if (line == "OK" || line.left(3) == "ACK") { - m_sock.close(); - emit finished(); - return; - } - } - }); - fflush(stdout); - m_sock.waitForDisconnected(); - } - - Commander(const QString &host, qint16 port, const char *command) - : m_sock(host, port) - , m_cmd(command) - { - doCommand(); - }; - - Commander(const QString &host, qint16 port) - : m_sock(host, port) - , m_cmd(nullptr) - { - } - -public slots: -#define DECLARE_CMD(name) \ - static void name(const QString &host, qint16 port) { Commander cmd(host, port, CMD_##name); } - DECLARE_CMD(NEXT) - DECLARE_CMD(PREVIOUS) - DECLARE_CMD(SHUFFLE) - DECLARE_CMD(TOGGLE) - DECLARE_CMD(FORCE_PLAY) - - void handleCorrectPlay(int sta) - { - switch (sta) { - case Status::Play: - case Status::Pause: - m_cmd = CMD_TOGGLE; - doCommand(); - break; - - default: - m_cmd = CMD_FORCE_PLAY; - doCommand(); - break; - } - } - - static void PLAY(const QString &host, qint16 port) - { - std::cout << "Asked a PLAY command" << std::endl; - Status sta(host, port, false); - Commander cmd(host, port); - connect(&sta, &Status::changeStatus, &cmd, &Commander::handleCorrectPlay); - sta.waitForDisconnected(); - } -#undef DECLARE_CMD - -signals: - void finished(void); -}; - -/* The application */ -class Application final : public QApplication { - Q_OBJECT -private: - bool m_exit; - QPixmap m_xpm; - QIcon m_icon; - QSystemTrayIcon m_tray_icon; - QMenu m_menu; - - bool m_already_red = false; - bool m_is_connected = false; - QString m_pending_data; - - QString m_host = "127.0.0.1"; - qint16 m_port = 6600; - QString m_config_file; - - Socket m_sock; - - QList<Status *> m_garbage; - - static inline const char *ListenString = "idle player\n"; - -protected slots: - void notifyExit(void) - { - garbageCollect(true); - - if (m_exit) - return; - - sendNotification("Klkt quitting", "Klkt will stop", Urgency::LOW); - m_exit = true; - if (m_sock.isValid()) - m_sock.close(); - - quit(); - } - - void disconnected(void) - { - if (m_exit || !m_is_connected) - return; - - sendNotification("Connexion lost", "Connexion to lektord has been lost!", - Urgency::CRITICAL); - m_pending_data = ""; - m_is_connected = false; - } - - void reconnect(void) - { - Config conf(this, m_config_file); - if (conf.isUnix()) { -#if defined(Q_OS_MSDOS) || defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_WIN) || \ - defined(Q_OS_WINRT) - sendNotification("Klkt fatal error", - "The 'unix' socket type is not available on your platform", - Urgency::CRITICAL); -#endif - } - - m_host = conf.getHost(); - m_port = conf.getPort(); - m_sock.reset(m_host, m_port); - m_sock.doConnect(); - if (!m_sock.waitForConnected(50000)) - sendNotification("Klkt not connected", "Connexion to lektord failed", - Urgency::CRITICAL); - else - m_is_connected = true; - } - - void read(void) - { - QByteArray got = m_sock.readAll(); - m_pending_data = QTextCodec::codecForMib(UTF8_MIB)->toUnicode(got); - - if (!m_already_red) { - m_already_red = true; - m_sock.write(ListenString); - } - - for (const auto &line : m_pending_data.split("\n")) { - if (line.left(2) == "OK") - queryStatus(); - } - } - - void connected(void) {} - -private: - void queryStatus(void) - { - garbageCollect(); - Status *ptr_status = new Status(m_host, m_port); - connect(ptr_status, &Status::changeCurrentKara, this, - [&](QString kara) { m_tray_icon.setToolTip(kara); }); - m_garbage.push_back(ptr_status); - } - - void garbageCollect(bool force = false) - { - std::transform(m_garbage.begin(), m_garbage.end(), m_garbage.begin(), - [&force](Status *p_sta) -> Status * { - if (force || (p_sta && p_sta->isDeletable())) { - delete p_sta; - return nullptr; - } else - return p_sta; - }); - - /* Should be enaugh to delete all used status sockets */ - while (m_garbage.length() > 0 && m_garbage.front() == nullptr) - m_garbage.pop_front(); - } - - // Qt::GenericConfigLocation -public: - Application(int argc, char **argv) - : QApplication(argc, argv) - , m_exit(false) - , m_xpm(icon) - , m_icon(m_xpm) - , m_tray_icon(m_icon) - , m_config_file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation)) - , m_sock(m_host, m_port) - { - notify_init("Klkt"); - - { - QDir config_dir(m_config_file); - if (!config_dir.mkpath(m_config_file)) { - sendNotification("Klkt fatal error", - tr("Failed to create the Klkt config dir %1") - .arg(m_config_file) - .toStdString() - .c_str(), - Urgency::CRITICAL); - ::exit(EXIT_FAILURE); - } - m_config_file += "/lektor/klkt.ini"; - QFile conf_file(m_config_file); - if (!conf_file.open(QIODevice::ReadWrite | QIODevice::Text)) { - sendNotification("Klkt fatal error", - tr("Failed to create Klkt config file %1") - .arg(m_config_file) - .toStdString() - .c_str(), - Urgency::CRITICAL); - ::exit(EXIT_FAILURE); - } - conf_file.close(); - } - - { - m_menu.addSection("Playback"); - QAction *playback_play = m_menu.addAction(QIcon(":/icons/play.png"), "Play/Pause"); - QAction *playback_next = m_menu.addAction(QIcon(":/icons/next.png"), "Next"); - QAction *playback_prev = m_menu.addAction(QIcon(":/icons/previous.png"), "Previous"); - QAction *playback_shuf = m_menu.addAction(QIcon(":/icons/shuffle.png"), "Shuffle"); - m_menu.addSection("System"); - QAction *action_reco = m_menu.addAction("Reconnect"); - QAction *action_restart = m_menu.addAction("Restart"); - QAction *action_quit = m_menu.addAction("Quit"); - m_tray_icon.setContextMenu(&m_menu); - m_tray_icon.setToolTip("The lektord mk7 system tray client"); - - playback_play->setIconVisibleInMenu(true); - playback_prev->setIconVisibleInMenu(true); - playback_next->setIconVisibleInMenu(true); - playback_shuf->setIconVisibleInMenu(true); - - connect(playback_play, &QAction::triggered, this, - [&]() { Commander::PLAY(m_host, m_port); }); - connect(playback_next, &QAction::triggered, this, - [&]() { Commander::NEXT(m_host, m_port); }); - connect(playback_prev, &QAction::triggered, this, - [&]() { Commander::PREVIOUS(m_host, m_port); }); - connect(playback_shuf, &QAction::triggered, this, - [&]() { Commander::SHUFFLE(m_host, m_port); }); - - connect(action_quit, &QAction::triggered, this, &Application::notifyExit); - connect(action_reco, &QAction::triggered, this, &Application::reconnect); - connect(action_restart, &QAction::triggered, this, &Application::restart); - connect(&m_tray_icon, &QSystemTrayIcon::activated, &m_menu, - [&]() { m_menu.popup(QCursor::pos()); }); - } - - m_tray_icon.show(); - - connect(&m_sock, &Socket::connected, this, &Application::connected); - connect(&m_sock, &Socket::disconnected, this, &Application::disconnected); - connect(&m_sock, &Socket::readyRead, this, &Application::read); - - reconnect(); - } - - void restart(void) const - { - sendNotification("Klkt restart", "Klkt will restart", Urgency::LOW); - QStringList args{ QApplication::applicationFilePath() }; - QProcess::startDetached(args[0], args); - ::exit(EXIT_SUCCESS); - } -}; - -#endif // APPLICATION_HPP diff --git a/src/klkt/klkt.pro b/src/klkt/klkt.pro deleted file mode 100644 index 25125e87a8a19681ca45867b3ed272aa3373eca6..0000000000000000000000000000000000000000 --- a/src/klkt/klkt.pro +++ /dev/null @@ -1,29 +0,0 @@ -QT += core gui network -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -QT_CONFIG -= no-pkg-config -CONFIG += c++17 console -CONFIG -= app_bundle -CONFIG += link_pkgconfig -PKGCONFIG += libnotify - -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 - -SOURCES += \ - klkt.cpp \ - -HEADERS += \ - klkt.hpp \ - ../../inc/lektor/icon.xpm \ - ../../inc/lektor/common.h \ - -INCLUDEPATH += \ - ../../inc/ - -# Default rules for deployment. -qnx: target.path = /tmp/$${TARGET}/bin -else: unix:!android: target.path = /opt/$${TARGET}/bin -!isEmpty(target.path): INSTALLS += target - -RESOURCES += \ - icons.qrc