From 2225fcaf9d6fe97466632aa40a9e69920f49459f Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 6 Feb 2015 01:27:07 +0100 Subject: [PATCH 1/5] Initial android support --- android/AndroidManifest.xml | 56 +++++++++++++++++++++++++ qtox.pro | 63 ++++++++++++++++++++--------- src/coreencryption.cpp | 2 +- src/main.cpp | 2 + src/widget/form/settings/avform.cpp | 4 ++ src/widget/widget.cpp | 4 +- 6 files changed, 108 insertions(+), 23 deletions(-) create mode 100644 android/AndroidManifest.xml diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 000000000..f8e2ee1c8 --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qtox.pro b/qtox.pro index 7de0f7811..d42fba74b 100644 --- a/qtox.pro +++ b/qtox.pro @@ -69,6 +69,22 @@ contains(ENABLE_SYSTRAY_UNITY_BACKEND, YES) { LIBS += -lgobject-2.0 -lappindicator -lgtk-x11-2.0 } +android { + ANDROID_TOOLCHAIN=/opt/android/toolchain-r9d-17/ + INCLUDEPATH += $$ANDROID_TOOLCHAIN/include/ + LIBS += -L$$ANDROID_TOOLCHAIN/lib + + DISABLE_PLATFORM_EXT=YES + DISABLE_FILTER_AUDIO=YES + + ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android + contains(ANDROID_TARGET_ARCH,armeabi) { + ANDROID_EXTRA_LIBS = \ + $$ANDROID_TOOLCHAIN/lib/libopenal.so + } +} + + contains(DISABLE_PLATFORM_EXT, YES) { } else { @@ -110,31 +126,38 @@ win32 { contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation } contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio } } else { - # If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package - contains(STATICPKG, YES) { - target.path = /usr/bin - INSTALLS += target - LIBS += -L$$PWD/libs/lib/ -lopus -lvpx -lopenal -Wl,-Bstatic -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lopencv_highgui -lopencv_imgproc -lopencv_core -lz -Wl,-Bdynamic - LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig - LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0 + android { + LIBS += -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns + LIBS += -lopencv_videoio -lopencv_imgcodecs -lopencv_highgui -lopencv_imgproc -lopencv_androidcamera + LIBS += -llibjpeg -llibwebp -llibpng -llibtiff -llibjasper -lIlmImf -lopencv_core + LIBS += -lopus -lvpx -lsodium -lopenal } else { - LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lsodium -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc - } - - contains(DEFINES, QTOX_PLATFORM_EXT) { - LIBS += -lX11 -lXss - } - - contains(DEFINES, QTOX_FILTER_AUDIO) { + # If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package contains(STATICPKG, YES) { - LIBS += -Wl,-Bstatic -lfilteraudio + target.path = /usr/bin + INSTALLS += target + LIBS += -L$$PWD/libs/lib/ -lopus -lvpx -lopenal -Wl,-Bstatic -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lopencv_highgui -lopencv_imgproc -lopencv_core -lz -Wl,-Bdynamic + LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig + LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0 } else { - LIBS += -lfilteraudio + LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lsodium -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc } - } - contains(JENKINS, YES) { - LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxdns.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a ./libs/lib/libfilteraudio.a /usr/lib/libopencv_core.so /usr/lib/libopencv_highgui.so /usr/lib/libopencv_imgproc.so -lopenal -lX11 -lXss -s + contains(DEFINES, QTOX_PLATFORM_EXT) { + LIBS += -lX11 -lXss + } + + contains(DEFINES, QTOX_FILTER_AUDIO) { + contains(STATICPKG, YES) { + LIBS += -Wl,-Bstatic -lfilteraudio + } else { + LIBS += -lfilteraudio + } + } + + contains(JENKINS, YES) { + LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxdns.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a ./libs/lib/libfilteraudio.a /usr/lib/libopencv_core.so /usr/lib/libopencv_highgui.so /usr/lib/libopencv_imgproc.so -lopenal -lX11 -lXss -s + } } } } diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index 00e4d1a52..69319f830 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -295,7 +295,7 @@ void Core::saveConfiguration(const QString& path) else fileSize = tox_size(tox); - if (fileSize > 0 && fileSize <= INT32_MAX) { + if (fileSize > 0 && fileSize <= std::numeric_limits::max()) { uint8_t *data = new uint8_t[fileSize]; if (encrypt) diff --git a/src/main.cpp b/src/main.cpp index ad8c23342..a1c3dbdde 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -121,6 +121,7 @@ int main(int argc, char *argv[]) AutoUpdater::installLocalUpdate(); ///< NORETURN #endif +#ifndef Q_OS_ANDROID // Inter-process communication IPC ipc; ipc.registerEventHandler(&toxURIEventHandler); @@ -175,6 +176,7 @@ int main(int argc, char *argv[]) if (!ipc.isCurrentOwner()) return EXIT_SUCCESS; } +#endif // Run a.setQuitOnLastWindowClosed(false); diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 3c170821e..d3cefe8a7 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -27,6 +27,10 @@ #include #endif +#ifndef ALC_ALL_DEVICES_SPECIFIER +#define ALC_ALL_DEVICES_SPECIFIER ALC_DEVICE_SPECIFIER +#endif + AVForm::AVForm() : GenericForm(tr("Audio/Video"), QPixmap(":/img/settings/av.png")) { diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index eb3999504..cca091025 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -64,11 +64,11 @@ Widget *Widget::instance{nullptr}; Widget::Widget(QWidget *parent) : QMainWindow(parent), + icon{nullptr}, ui(new Ui::MainWindow), activeChatroomWidget{nullptr}, eventFlag(false), - eventIcon(false), - icon{nullptr} + eventIcon(false) { translator = new QTranslator; setTranslation(); From 46bba3f2f1f86fc9bb07e18168c0376988d8a807 Mon Sep 17 00:00:00 2001 From: tux3/mlkj Date: Fri, 6 Feb 2015 12:28:49 +0100 Subject: [PATCH 2/5] Initial Android support We create a GUI class to abstract common GUI needs (showing a message box, asking a question, ...) from the actual GUI backend. We also create a Nexus class to manage the startup and lifetime of our main systems (Core, GUI, ...) instead of delegating that to Widget. Eventually, Widget will only be in charge of the Desktop GUI and AndroidGUI of the mobile GUI. Nexus will overview the system and GUI will provide a clean platform-independant interface. --- qtox.pro | 15 +- src/core.cpp | 9 +- src/main.cpp | 6 +- src/misc/settings.cpp | 66 +++++++++ src/misc/settings.h | 3 + src/nexus.cpp | 121 ++++++++++++++++ src/nexus.h | 35 +++++ src/widget/androidgui.cpp | 13 ++ src/widget/androidgui.h | 19 +++ src/widget/form/settings/identityform.cpp | 2 +- src/widget/gui.cpp | 47 +++++++ src/widget/gui.h | 33 +++++ src/widget/widget.cpp | 164 +++------------------- src/widget/widget.h | 53 +++---- 14 files changed, 401 insertions(+), 185 deletions(-) create mode 100644 src/nexus.cpp create mode 100644 src/nexus.h create mode 100644 src/widget/androidgui.cpp create mode 100644 src/widget/androidgui.h create mode 100644 src/widget/gui.cpp create mode 100644 src/widget/gui.h diff --git a/qtox.pro b/qtox.pro index d42fba74b..3c95c22ba 100644 --- a/qtox.pro +++ b/qtox.pro @@ -80,7 +80,8 @@ android { ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android contains(ANDROID_TARGET_ARCH,armeabi) { ANDROID_EXTRA_LIBS = \ - $$ANDROID_TOOLCHAIN/lib/libopenal.so + $$ANDROID_TOOLCHAIN/lib/libopenal.so \ + $$ANDROID_TOOLCHAIN/lib/libsodium.so } } @@ -106,7 +107,7 @@ contains(JENKINS,YES) { # Rules for Windows, Mac OSX, and Linux win32 { RC_FILE = windows/qtox.rc - LIBS += -L$$PWD/libs/lib -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lsodium -lvpx -lpthread + LIBS += -L$$PWD/libs/lib -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lsodium -lvpx -lpthread LIBS += -L$$PWD/libs/lib -lopencv_core249 -lopencv_highgui249 -lopencv_imgproc249 -lOpenAL32 -lopus LIBS += -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -lws2_32 -liphlpapi -lz @@ -229,7 +230,10 @@ HEADERS += src/widget/form/addfriendform.h \ src/audio.h \ src/widget/callconfirmwidget.h \ src/widget/systemtrayicon.h \ - src/widget/systemtrayicon_private.h + src/widget/systemtrayicon_private.h \ + src/nexus.h \ + src/widget/gui.h \ + src/widget/androidgui.h SOURCES += \ src/widget/form/addfriendform.cpp \ @@ -298,7 +302,10 @@ SOURCES += \ src/widget/form/settings/advancedform.cpp \ src/audio.cpp \ src/widget/callconfirmwidget.cpp \ - src/widget/systemtrayicon.cpp + src/widget/systemtrayicon.cpp \ + src/nexus.cpp \ + src/widget/gui.cpp \ + src/widget/androidgui.cpp contains(DEFINES, QTOX_FILTER_AUDIO) { HEADERS += src/audiofilterer.h diff --git a/src/core.cpp b/src/core.cpp index 4b82a1d5a..f6fa4463c 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -15,6 +15,7 @@ */ #include "core.h" +#include "nexus.h" #include "misc/cdata.h" #include "misc/cstring.h" #include "misc/settings.h" @@ -106,6 +107,7 @@ Core::~Core() { qDebug() << "Deleting Core"; + saveConfiguration(); toxTimer->stop(); coreThread->exit(0); while (coreThread->isRunning()) @@ -128,7 +130,7 @@ Core::~Core() Core* Core::getInstance() { - return Widget::getInstance()->getCore(); + return Nexus::getCore(); } void Core::make_tox() @@ -223,6 +225,8 @@ void Core::make_tox() void Core::start() { + qDebug() << "Core: Starting up"; + make_tox(); qsrand(time(nullptr)); @@ -1202,8 +1206,7 @@ bool Core::loadConfiguration(QString path) { configurationFile.close(); - QString profile; - QMetaObject::invokeMethod(Widget::getInstance(), "askProfiles", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, profile)); + QString profile = Settings::getInstance().askProfiles(); if (!profile.isEmpty()) { diff --git a/src/main.cpp b/src/main.cpp index a1c3dbdde..8d5ba8934 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,7 @@ #include "widget/widget.h" #include "misc/settings.h" +#include "src/nexus.h" #include "src/ipc.h" #include "src/widget/toxuri.h" #include "src/widget/toxsave.h" @@ -70,6 +71,7 @@ int main(int argc, char *argv[]) parser.process(a); Settings::getInstance(); // Build our Settings singleton as soon as QApplication is ready, not before + if (parser.isSet("p")) { QString profile = parser.value("p"); @@ -121,6 +123,8 @@ int main(int argc, char *argv[]) AutoUpdater::installLocalUpdate(); ///< NORETURN #endif +Nexus::getInstance().start(); + #ifndef Q_OS_ANDROID // Inter-process communication IPC ipc; @@ -180,10 +184,8 @@ int main(int argc, char *argv[]) // Run a.setQuitOnLastWindowClosed(false); - Widget* w = Widget::getInstance(); int errorcode = a.exec(); - delete w; #ifdef LOG_TO_FILE delete logFile; logFile = nullptr; diff --git a/src/misc/settings.cpp b/src/misc/settings.cpp index 196202865..96b2b2c6e 100644 --- a/src/misc/settings.cpp +++ b/src/misc/settings.cpp @@ -18,6 +18,8 @@ #include "smileypack.h" #include "src/corestructs.h" #include "src/misc/db/plaindb.h" +#include "src/core.h" +#include "src/widget/gui.h" #include #include @@ -65,6 +67,70 @@ void Settings::switchProfile(const QString& profile) resetInstance(); } +QString Settings::detectProfile() +{ + QDir dir(getSettingsDirPath()); + QString path, profile = getCurrentProfile(); + path = dir.filePath(profile + Core::TOX_EXT); + QFile file(path); + if (profile.isEmpty() || !file.exists()) + { + setCurrentProfile(""); +#if 1 // deprecation attempt + // if the last profile doesn't exist, fall back to old "data" + path = dir.filePath(Core::CONFIG_FILE_NAME); + QFile file(path); + if (file.exists()) + return path; + else if (QFile(path = dir.filePath("tox_save")).exists()) // also import tox_save if no data + return path; + else +#endif + { + profile = askProfiles(); + if (profile.isEmpty()) + return ""; + else + { + switchProfile(profile); + return dir.filePath(profile + Core::TOX_EXT); + } + } + } + else + return path; +} + +QList Settings::searchProfiles() +{ + QList out; + QDir dir(getSettingsDirPath()); + dir.setFilter(QDir::Files | QDir::NoDotAndDotDot); + dir.setNameFilters(QStringList("*.tox")); + for (QFileInfo file : dir.entryInfoList()) + out += file.completeBaseName(); + return out; +} + +QString Settings::askProfiles() +{ // TODO: allow user to create new Tox ID, even if a profile already exists + QList profiles = searchProfiles(); + if (profiles.empty()) return ""; + bool ok; + QString profile = GUI::itemInputDialog(nullptr, + tr("Choose a profile"), + tr("Please choose which identity to use"), + profiles, + 0, // which slot to start on + false, // if the user can enter their own input + &ok); + if (!ok) // user cancelled + return ""; + else + return profile; +} + + void Settings::load() { if (loaded) diff --git a/src/misc/settings.h b/src/misc/settings.h index 391fe1c58..550b79840 100644 --- a/src/misc/settings.h +++ b/src/misc/settings.h @@ -33,6 +33,9 @@ public: static Settings& getInstance(); static void resetInstance(); void switchProfile(const QString& profile); + QString detectProfile(); + QList searchProfiles(); + QString askProfiles(); ~Settings() = default; void executeSettingsDialog(QWidget* parent); diff --git a/src/nexus.cpp b/src/nexus.cpp new file mode 100644 index 000000000..91b65530e --- /dev/null +++ b/src/nexus.cpp @@ -0,0 +1,121 @@ +#include "nexus.h" +#include "core.h" +#include "misc/settings.h" +#include "video/camera.h" +#include +#include + +#ifdef Q_OS_ANDROID +#include +#else +#include +#endif + +Nexus::Nexus(QObject *parent) : + QObject(parent), + core{nullptr}, + coreThread{nullptr}, + widget{nullptr}, + androidgui{nullptr}, + started{false} +{ +} + +Nexus::~Nexus() +{ + delete core; + delete coreThread; +#ifdef Q_OS_ANDROID + delete androidgui; +#else + delete widget; +#endif +} + +void Nexus::start() +{ + if (started) + return; + qDebug() << "Nexus: Starting up"; + + // Setup the environment + qRegisterMetaType("Status"); + qRegisterMetaType("vpx_image"); + qRegisterMetaType("uint8_t"); + qRegisterMetaType("uint16_t"); + qRegisterMetaType("const int16_t*"); + qRegisterMetaType("int32_t"); + qRegisterMetaType("int64_t"); + qRegisterMetaType("QPixmap"); + qRegisterMetaType("ToxFile"); + qRegisterMetaType("ToxFile::FileDirection"); + qRegisterMetaType("Core::PasswordType"); + + // Create Core + QString profilePath = Settings::getInstance().detectProfile(); + coreThread = new QThread(this); + coreThread->setObjectName("qTox Core"); + core = new Core(Camera::getInstance(), coreThread, profilePath); + core->moveToThread(coreThread); + connect(coreThread, &QThread::started, core, &Core::start); + + // Start GUI +#ifdef Q_OS_ANDROID + androidgui = new AndroidGUI; + androidgui->show(); +#else + widget = Widget::getInstance(); +#endif + + // Connections +#ifndef Q_OS_ANDROID + connect(core, &Core::connected, widget, &Widget::onConnected); + connect(core, &Core::disconnected, widget, &Widget::onDisconnected); + connect(core, &Core::failedToStart, widget, &Widget::onFailedToStartCore); + connect(core, &Core::badProxy, widget, &Widget::onBadProxyCore); + connect(core, &Core::statusSet, widget, &Widget::onStatusSet); + connect(core, &Core::usernameSet, widget, &Widget::setUsername); + connect(core, &Core::statusMessageSet, widget, &Widget::setStatusMessage); + connect(core, &Core::selfAvatarChanged, widget, &Widget::onSelfAvatarLoaded); + connect(core, &Core::friendAdded, widget, &Widget::addFriend); + connect(core, &Core::failedToAddFriend, widget, &Widget::addFriendFailed); + connect(core, &Core::friendUsernameChanged, widget, &Widget::onFriendUsernameChanged); + connect(core, &Core::friendStatusChanged, widget, &Widget::onFriendStatusChanged); + connect(core, &Core::friendStatusMessageChanged, widget, &Widget::onFriendStatusMessageChanged); + connect(core, &Core::friendRequestReceived, widget, &Widget::onFriendRequestReceived); + connect(core, &Core::friendMessageReceived, widget, &Widget::onFriendMessageReceived); + connect(core, &Core::receiptRecieved, widget, &Widget::onReceiptRecieved); + connect(core, &Core::groupInviteReceived, widget, &Widget::onGroupInviteReceived); + connect(core, &Core::groupMessageReceived, widget, &Widget::onGroupMessageReceived); + connect(core, &Core::groupNamelistChanged, widget, &Widget::onGroupNamelistChanged); + connect(core, &Core::groupTitleChanged, widget, &Widget::onGroupTitleChanged); + connect(core, &Core::emptyGroupCreated, widget, &Widget::onEmptyGroupCreated); + connect(core, &Core::avInvite, widget, &Widget::playRingtone); + connect(core, &Core::blockingClearContacts, widget, &Widget::clearContactsList, Qt::BlockingQueuedConnection); + connect(core, &Core::friendTypingChanged, widget, &Widget::onFriendTypingChanged); + + connect(core, SIGNAL(messageSentResult(int,QString,int)), widget, SLOT(onMessageSendResult(int,QString,int))); + connect(core, SIGNAL(groupSentResult(int,QString,int)), widget, SLOT(onGroupSendResult(int,QString,int))); + + connect(widget, &Widget::statusSet, core, &Core::setStatus); + connect(widget, &Widget::friendRequested, core, &Core::requestFriendship); + connect(widget, &Widget::friendRequestAccepted, core, &Core::acceptFriendRequest); + connect(widget, &Widget::changeProfile, core, &Core::switchConfiguration); +#endif + + // Start Core + coreThread->start(); + + started = true; +} + +Nexus& Nexus::getInstance() +{ + static Nexus nexus; + return nexus; +} + +Core* Nexus::getCore() +{ + return getInstance().core; +} diff --git a/src/nexus.h b/src/nexus.h new file mode 100644 index 000000000..f8b5dd4b5 --- /dev/null +++ b/src/nexus.h @@ -0,0 +1,35 @@ +#ifndef NEXUS_H +#define NEXUS_H + +#include + +class QThread; +class Core; +class Widget; +class AndroidGUI; + +/// This class is in charge of connecting various systems together +/// and forwarding signals appropriately to the right objects +/// It is in charge of starting the GUI and the Core +class Nexus : public QObject +{ + Q_OBJECT +public: + void start(); ///< Will initialise the systems (GUI, Core, ...) + + static Nexus& getInstance(); + static Core* getCore(); ///< Will return 0 if not started + +private: + explicit Nexus(QObject *parent = 0); + ~Nexus(); + +private: + Core* core; + QThread* coreThread; + Widget* widget; + AndroidGUI* androidgui; + bool started; +}; + +#endif // NEXUS_H diff --git a/src/widget/androidgui.cpp b/src/widget/androidgui.cpp new file mode 100644 index 000000000..7ae41d983 --- /dev/null +++ b/src/widget/androidgui.cpp @@ -0,0 +1,13 @@ +#include "androidgui.h" +#include + +AndroidGUI::AndroidGUI(QWidget *parent) : + QWidget(parent) +{ + l = new QLabel("qTox Android", this); +} + +AndroidGUI::~AndroidGUI() +{ + delete l; +} diff --git a/src/widget/androidgui.h b/src/widget/androidgui.h new file mode 100644 index 000000000..853483ce2 --- /dev/null +++ b/src/widget/androidgui.h @@ -0,0 +1,19 @@ +#ifndef ANDROIDGUI_H +#define ANDROIDGUI_H + +#include + +class QLabel; + +class AndroidGUI : public QWidget +{ + Q_OBJECT +public: + explicit AndroidGUI(QWidget *parent = 0); + ~AndroidGUI(); + +private: + QLabel* l; +}; + +#endif // ANDROIDGUI_H diff --git a/src/widget/form/settings/identityform.cpp b/src/widget/form/settings/identityform.cpp index 8d067b606..a856af1b5 100644 --- a/src/widget/form/settings/identityform.cpp +++ b/src/widget/form/settings/identityform.cpp @@ -111,7 +111,7 @@ void IdentityForm::present() toxId->setText(Core::getInstance()->getSelfId().toString()); toxId->setCursorPosition(0); bodyUI->profiles->clear(); - for (QString profile : Widget::searchProfiles()) + for (QString profile : Settings::getInstance().searchProfiles()) bodyUI->profiles->addItem(profile); QString current = Settings::getInstance().getCurrentProfile(); if (current != "") diff --git a/src/widget/gui.cpp b/src/widget/gui.cpp new file mode 100644 index 000000000..76f77e8db --- /dev/null +++ b/src/widget/gui.cpp @@ -0,0 +1,47 @@ +#include "gui.h" +#include +#include +#include + +GUI::GUI(QObject *parent) : + QObject(parent) +{ +} + +GUI& GUI::getInstance() +{ + static GUI gui; + return gui; +} + +QString GUI::itemInputDialog(QWidget * parent, const QString & title, + const QString & label, const QStringList & items, + int current, bool editable, bool * ok, + Qt::WindowFlags flags, + Qt::InputMethodHints hints) +{ + if (QThread::currentThread() == qApp->thread()) + { + return getInstance()._itemInputDialog(parent, title, label, items, current, editable, ok, flags, hints); + } + else + { + QString r; + QMetaObject::invokeMethod(&getInstance(), "_itemInputDialog", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QString, r), + Q_ARG(QWidget*, parent), Q_ARG(const QString&, title), + Q_ARG(const QString&,label), Q_ARG(const QStringList&, items), + Q_ARG(int, current), Q_ARG(bool, editable), Q_ARG(bool*, ok), + Q_ARG(Qt::WindowFlags, flags), Q_ARG(Qt::InputMethodHints, hints)); + return r; + } +} + +QString GUI::_itemInputDialog(QWidget * parent, const QString & title, + const QString & label, const QStringList & items, + int current, bool editable, bool * ok, + Qt::WindowFlags flags, + Qt::InputMethodHints hints) +{ + return QInputDialog::getItem(parent, title, label, items, current, editable, ok, flags, hints); +} diff --git a/src/widget/gui.h b/src/widget/gui.h new file mode 100644 index 000000000..7a7f70339 --- /dev/null +++ b/src/widget/gui.h @@ -0,0 +1,33 @@ +#ifndef GUI_H +#define GUI_H + +#include + +class QWidget; + +/// Abstracts the GUI from the target backend (AndroidGUI, DesktopGUI, ...) +/// All the functions exposed here are thread-safe +/// Prefer calling this class to calling a GUI backend directly +class GUI : public QObject +{ + Q_OBJECT +public: + static GUI& getInstance(); + static QString itemInputDialog(QWidget * parent, const QString & title, + const QString & label, const QStringList & items, + int current = 0, bool editable = true, bool * ok = 0, + Qt::WindowFlags flags = 0, + Qt::InputMethodHints hints = Qt::ImhNone); + +private: + explicit GUI(QObject *parent = 0); + +private slots: + QString _itemInputDialog(QWidget * parent, const QString & title, + const QString & label, const QStringList & items, + int current = 0, bool editable = true, bool * ok = 0, + Qt::WindowFlags flags = 0, + Qt::InputMethodHints inputMethodHints = Qt::ImhNone); +}; + +#endif // GUI_H diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index cca091025..3a5d5ee5c 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -36,6 +36,7 @@ #include "src/audio.h" #include "src/platform/timer.h" #include "systemtrayicon.h" +#include "src/nexus.h" #include #include #include @@ -194,67 +195,15 @@ void Widget::init() Style::setThemeColor(Settings::getInstance().getThemeColor()); Style::applyTheme(); - - qRegisterMetaType("Status"); - qRegisterMetaType("vpx_image"); - qRegisterMetaType("uint8_t"); - qRegisterMetaType("uint16_t"); - qRegisterMetaType("const int16_t*"); - qRegisterMetaType("int32_t"); - qRegisterMetaType("int64_t"); - qRegisterMetaType("QPixmap"); - qRegisterMetaType("ToxFile"); - qRegisterMetaType("ToxFile::FileDirection"); - qRegisterMetaType("Core::PasswordType"); - - QString profilePath = detectProfile(); - coreThread = new QThread(this); - coreThread->setObjectName("qTox Core"); - core = new Core(Camera::getInstance(), coreThread, profilePath); - core->moveToThread(coreThread); - connect(coreThread, &QThread::started, core, &Core::start); filesForm = new FilesForm(); addFriendForm = new AddFriendForm; settingsWidget = new SettingsWidget(); - connect(settingsWidget, &SettingsWidget::setShowSystemTray, this, &Widget::onSetShowSystemTray); - - connect(core, &Core::connected, this, &Widget::onConnected); - connect(core, &Core::disconnected, this, &Widget::onDisconnected); - connect(core, &Core::failedToStart, this, &Widget::onFailedToStartCore); - connect(core, &Core::badProxy, this, &Widget::onBadProxyCore); - connect(core, &Core::statusSet, this, &Widget::onStatusSet); - connect(core, &Core::usernameSet, this, &Widget::setUsername); - connect(core, &Core::statusMessageSet, this, &Widget::setStatusMessage); - connect(core, &Core::selfAvatarChanged, this, &Widget::onSelfAvatarLoaded); + Core* core = Nexus::getCore(); connect(core, SIGNAL(fileDownloadFinished(const QString&)), filesForm, SLOT(onFileDownloadComplete(const QString&))); connect(core, SIGNAL(fileUploadFinished(const QString&)), filesForm, SLOT(onFileUploadComplete(const QString&))); - connect(core, &Core::friendAdded, this, &Widget::addFriend); - connect(core, &Core::failedToAddFriend, this, &Widget::addFriendFailed); - connect(core, &Core::friendUsernameChanged, this, &Widget::onFriendUsernameChanged); - connect(core, &Core::friendStatusChanged, this, &Widget::onFriendStatusChanged); - connect(core, &Core::friendStatusMessageChanged, this, &Widget::onFriendStatusMessageChanged); - connect(core, &Core::friendRequestReceived, this, &Widget::onFriendRequestReceived); - connect(core, &Core::friendMessageReceived, this, &Widget::onFriendMessageReceived); - connect(core, &Core::receiptRecieved, this, &Widget::onReceiptRecieved); - connect(core, &Core::groupInviteReceived, this, &Widget::onGroupInviteReceived); - connect(core, &Core::groupMessageReceived, this, &Widget::onGroupMessageReceived); - connect(core, &Core::groupNamelistChanged, this, &Widget::onGroupNamelistChanged); - connect(core, &Core::groupTitleChanged, this, &Widget::onGroupTitleChanged); - connect(core, &Core::emptyGroupCreated, this, &Widget::onEmptyGroupCreated); - connect(core, &Core::avInvite, this, &Widget::playRingtone); - connect(core, &Core::blockingClearContacts, this, &Widget::clearContactsList, Qt::BlockingQueuedConnection); - connect(core, &Core::friendTypingChanged, this, &Widget::onFriendTypingChanged); - - connect(core, SIGNAL(messageSentResult(int,QString,int)), this, SLOT(onMessageSendResult(int,QString,int))); - connect(core, SIGNAL(groupSentResult(int,QString,int)), this, SLOT(onGroupSendResult(int,QString,int))); - - connect(this, &Widget::statusSet, core, &Core::setStatus); - connect(this, &Widget::friendRequested, core, &Core::requestFriendship); - connect(this, &Widget::friendRequestAccepted, core, &Core::acceptFriendRequest); - connect(this, &Widget::changeProfile, core, &Core::switchConfiguration); - + connect(settingsWidget, &SettingsWidget::setShowSystemTray, this, &Widget::onSetShowSystemTray); connect(ui->addButton, SIGNAL(clicked()), this, SLOT(onAddClicked())); connect(ui->groupButton, SIGNAL(clicked()), this, SLOT(onGroupClicked())); connect(ui->transferButton, SIGNAL(clicked()), this, SLOT(onTransferClicked())); @@ -270,8 +219,6 @@ void Widget::init() connect(timer, &QTimer::timeout, this, &Widget::onUserAwayCheck); connect(timer, &QTimer::timeout, this, &Widget::onEventIconTick); - coreThread->start(); - addFriendForm->show(*ui); #if (AUTOUPDATE_ENABLED) @@ -318,9 +265,7 @@ void Widget::updateTrayIcon() Widget::~Widget() { qDebug() << "Deleting Widget"; - core->saveConfiguration(); AutoUpdater::abortUpdates(); - delete core; icon->hide(); hideMainForms(); delete settingsWidget; @@ -346,11 +291,6 @@ Widget* Widget::getInstance() return instance; } -QThread* Widget::getCoreThread() -{ - return coreThread; -} - void Widget::closeEvent(QCloseEvent *event) { if (Settings::getInstance().getShowSystemTray() && Settings::getInstance().getCloseToTray() == true) @@ -386,72 +326,9 @@ void Widget::resizeEvent(QResizeEvent *event) emit resized(); } -QString Widget::detectProfile() -{ - QDir dir(Settings::getSettingsDirPath()); - QString path, profile = Settings::getInstance().getCurrentProfile(); - path = dir.filePath(profile + Core::TOX_EXT); - QFile file(path); - if (profile.isEmpty() || !file.exists()) - { - Settings::getInstance().setCurrentProfile(""); -#if 1 // deprecation attempt - // if the last profile doesn't exist, fall back to old "data" - path = dir.filePath(Core::CONFIG_FILE_NAME); - QFile file(path); - if (file.exists()) - return path; - else if (QFile(path = dir.filePath("tox_save")).exists()) // also import tox_save if no data - return path; - else -#endif - { - profile = askProfiles(); - if (profile.isEmpty()) - return ""; - else - { - Settings::getInstance().switchProfile(profile); - return dir.filePath(profile + Core::TOX_EXT); - } - } - } - else - return path; -} - -QList Widget::searchProfiles() -{ - QList out; - QDir dir(Settings::getSettingsDirPath()); - dir.setFilter(QDir::Files | QDir::NoDotAndDotDot); - dir.setNameFilters(QStringList("*.tox")); - for (QFileInfo file : dir.entryInfoList()) - out += file.completeBaseName(); - return out; -} - -QString Widget::askProfiles() -{ // TODO: allow user to create new Tox ID, even if a profile already exists - QList profiles = searchProfiles(); - if (profiles.empty()) return ""; - bool ok; - QString profile = QInputDialog::getItem(this, - tr("Choose a profile"), - tr("Please choose which identity to use"), - profiles, - 0, // which slot to start on - false, // if the user can enter their own input - &ok); - if (!ok) // user cancelled - return ""; - else - return profile; -} - QString Widget::getUsername() { - return core->getUsername(); + return Nexus::getCore()->getUsername(); } void Widget::onAvatarClicked() @@ -495,7 +372,7 @@ void Widget::onAvatarClicked() return; } - core->setAvatar(TOX_AVATAR_FORMAT_PNG, bytes); + Nexus::getCore()->setAvatar(TOX_AVATAR_FORMAT_PNG, bytes); } void Widget::onSelfAvatarLoaded(const QPixmap& pic) @@ -591,7 +468,7 @@ void Widget::onAddClicked() void Widget::onGroupClicked() { - core->createGroup(); + Nexus::getCore()->createGroup(); } void Widget::onTransferClicked() @@ -664,7 +541,7 @@ void Widget::hideMainForms() void Widget::onUsernameChanged(const QString& newUsername, const QString& oldUsername) { setUsername(oldUsername); // restore old username until Core tells us to set it - core->setUsername(newUsername); + Nexus::getCore()->setUsername(newUsername); } void Widget::setUsername(const QString& username) @@ -681,7 +558,7 @@ void Widget::onStatusMessageChanged(const QString& newStatusMessage, const QStri { ui->statusLabel->setText(oldStatusMessage); // restore old status message until Core tells us to set it ui->statusLabel->setToolTip(oldStatusMessage); // for overlength messsages - core->setStatusMessage(newStatusMessage); + Nexus::getCore()->setStatusMessage(newStatusMessage); } void Widget::setStatusMessage(const QString &statusMessage) @@ -707,6 +584,7 @@ void Widget::addFriend(int friendId, const QString &userId) if (Settings::getInstance().getEnableLogging()) newfriend->getChatForm()->loadHistory(QDateTime::currentDateTime().addDays(-7), true); + Core* core = Nexus::getCore(); connect(settingsWidget, &SettingsWidget::compactToggled, newfriend->getFriendWidget(), &GenericChatroomWidget::onCompactChanged); connect(newfriend->getFriendWidget(), SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*))); connect(newfriend->getFriendWidget(), SIGNAL(removeFriend(int)), this, SLOT(removeFriend(int))); @@ -928,7 +806,7 @@ void Widget::removeFriend(Friend* f, bool fake) onAddClicked(); } FriendList::removeFriend(f->getFriendID(), fake); - core->removeFriend(f->getFriendID(), fake); + Nexus::getCore()->removeFriend(f->getFriendID(), fake); delete f; if (ui->mainHead->layout()->isEmpty()) onAddClicked(); @@ -959,7 +837,7 @@ void Widget::copyFriendIdToClipboard(int friendId) if (f != nullptr) { QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(core->getFriendAddress(f->getFriendID()), QClipboard::Clipboard); + clipboard->setText(Nexus::getCore()->getFriendAddress(f->getFriendID()), QClipboard::Clipboard); } } @@ -967,7 +845,7 @@ void Widget::onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray in { if (type == TOX_GROUPCHAT_TYPE_TEXT || type == TOX_GROUPCHAT_TYPE_AV) { - int groupId = core->joinGroupchat(friendId, type, (uint8_t*)invite.data(), invite.length()); + int groupId = Nexus::getCore()->joinGroupchat(friendId, type, (uint8_t*)invite.data(), invite.length()); if (groupId < 0) { qWarning() << "Widget::onGroupInviteReceived: Unable to accept group invite"; @@ -1014,7 +892,7 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha g = createGroup(groupnumber); } - QString name = core->getGroupPeerName(groupnumber, peernumber); + QString name = Nexus::getCore()->getGroupPeerName(groupnumber, peernumber); TOX_CHAT_CHANGE change = static_cast(Change); if (change == TOX_CHAT_CHANGE_PEER_ADD) { @@ -1033,7 +911,7 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha //g->chatForm->addSystemInfoMessage(tr("%1 has left the chat").arg(name), "silver"); } else if (change == TOX_CHAT_CHANGE_PEER_NAME) // core overwrites old name before telling us it changed... - g->updatePeer(peernumber,core->getGroupPeerName(groupnumber, peernumber)); + g->updatePeer(peernumber,Nexus::getCore()->getGroupPeerName(groupnumber, peernumber)); } void Widget::onGroupTitleChanged(int groupnumber, const QString& author, const QString& title) @@ -1056,7 +934,7 @@ void Widget::removeGroup(Group* g, bool fake) onAddClicked(); } GroupList::removeGroup(g->getGroupId(), fake); - core->removeGroup(g->getGroupId(), fake); + Nexus::getCore()->removeGroup(g->getGroupId(), fake); delete g; if (ui->mainHead->layout()->isEmpty()) onAddClicked(); @@ -1070,11 +948,6 @@ void Widget::removeGroup(int groupId) removeGroup(GroupList::findGroup(groupId)); } -Core *Widget::getCore() -{ - return core; -} - Group *Widget::createGroup(int groupId) { Group* g = GroupList::findGroup(groupId); @@ -1090,6 +963,7 @@ Group *Widget::createGroup(int groupId) layout->addWidget(newgroup->getGroupWidget()); newgroup->getGroupWidget()->updateStatusLight(); + Core* core = Nexus::getCore(); connect(newgroup->getGroupWidget(), SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*))); connect(newgroup->getGroupWidget(), SIGNAL(removeGroup(int)), this, SLOT(removeGroup(int))); connect(newgroup->getGroupWidget(), SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), newgroup->getChatForm(), SLOT(focusInput())); @@ -1174,17 +1048,17 @@ void Widget::onEventIconTick() void Widget::setStatusOnline() { - core->setStatus(Status::Online); + Nexus::getCore()->setStatus(Status::Online); } void Widget::setStatusAway() { - core->setStatus(Status::Away); + Nexus::getCore()->setStatus(Status::Away); } void Widget::setStatusBusy() { - core->setStatus(Status::Busy); + Nexus::getCore()->setStatus(Status::Busy); } void Widget::onMessageSendResult(int friendId, const QString& message, int messageId) diff --git a/src/widget/widget.h b/src/widget/widget.h index 0a8307cbe..f43a301f7 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -54,14 +54,11 @@ public: explicit Widget(QWidget *parent = 0); void setCentralWidget(QWidget *widget, const QString &widgetName); QString getUsername(); - Core* getCore(); - QThread* getCoreThread(); Camera* getCamera(); static Widget* getInstance(); void newMessageAlert(GenericChatroomWidget* chat); bool isFriendWidgetCurActiveWidget(Friend* f); bool getIsWindowMinimized(); - static QList searchProfiles(); void clearContactsList(); void setTranslation(); void updateTrayIcon(); @@ -69,7 +66,6 @@ public: Q_INVOKABLE void setEnabledThreadsafe(bool enabled); Q_INVOKABLE bool askQuestion(const QString& title, const QString& msg, bool defaultAns = false, bool warning = true); Q_INVOKABLE QString passwordDialog(const QString& cancel, const QString& body); - Q_INVOKABLE QString askProfiles(); // hooray for threading hacks ~Widget(); @@ -86,6 +82,29 @@ public slots: void onSettingsClicked(); void setWindowTitle(const QString& title); void forceShow(); + void onConnected(); + void onDisconnected(); + void onStatusSet(Status status); + void onFailedToStartCore(); + void onBadProxyCore(); + void onSelfAvatarLoaded(const QPixmap &pic); + void setUsername(const QString& username); + void setStatusMessage(const QString &statusMessage); + void addFriend(int friendId, const QString& userId); + void addFriendFailed(const QString& userId, const QString& errorInfo = QString()); + void onFriendStatusChanged(int friendId, Status status); + void onFriendStatusMessageChanged(int friendId, const QString& message); + void onFriendUsernameChanged(int friendId, const QString& username); + void onFriendMessageReceived(int friendId, const QString& message, bool isAction); + void onFriendRequestReceived(const QString& userId, const QString& message); + void onReceiptRecieved(int friendId, int receipt); + void onEmptyGroupCreated(int groupId); + void onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray invite); + void onGroupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction); + void onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t change); + void onGroupTitleChanged(int groupnumber, const QString& author, const QString& title); + void playRingtone(); + void onFriendTypingChanged(int friendId, bool isTyping); signals: void friendRequestAccepted(const QString& userId); @@ -98,34 +117,13 @@ signals: void resized(); private slots: - void onConnected(); - void onDisconnected(); - void onStatusSet(Status status); void onAddClicked(); void onGroupClicked(); void onTransferClicked(); - void onFailedToStartCore(); - void onBadProxyCore(); void onAvatarClicked(); - void onSelfAvatarLoaded(const QPixmap &pic); void onUsernameChanged(const QString& newUsername, const QString& oldUsername); void onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage); - void setUsername(const QString& username); - void setStatusMessage(const QString &statusMessage); - void addFriend(int friendId, const QString& userId); - void addFriendFailed(const QString& userId, const QString& errorInfo = QString()); - void onFriendStatusChanged(int friendId, Status status); - void onFriendStatusMessageChanged(int friendId, const QString& message); - void onFriendUsernameChanged(int friendId, const QString& username); void onChatroomWidgetClicked(GenericChatroomWidget *); - void onFriendMessageReceived(int friendId, const QString& message, bool isAction); - void onFriendRequestReceived(const QString& userId, const QString& message); - void onReceiptRecieved(int friendId, int receipt); - void onEmptyGroupCreated(int groupId); - void onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray invite); - void onGroupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction); - void onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t change); - void onGroupTitleChanged(int groupnumber, const QString& author, const QString& title); void removeFriend(int friendId); void copyFriendIdToClipboard(int friendId); void removeGroup(int groupId); @@ -134,11 +132,9 @@ private slots: void setStatusBusy(); void onMessageSendResult(int friendId, const QString& message, int messageId); void onGroupSendResult(int groupId, const QString& message, int result); - void playRingtone(); void onIconClick(QSystemTrayIcon::ActivationReason); void onUserAwayCheck(); void onEventIconTick(); - void onFriendTypingChanged(int friendId, bool isTyping); void onSetShowSystemTray(bool newValue); void onSplitterMoved(int pos, int index); @@ -151,7 +147,6 @@ private: void removeGroup(Group* g, bool fake = false); void saveWindowGeometry(); void saveSplitterGeometry(); - QString detectProfile(); SystemTrayIcon *icon; QMenu *trayMenu; QAction *statusOnline, @@ -162,8 +157,6 @@ private: Ui::MainWindow *ui; QSplitter *centralLayout; QPoint dragPosition; - Core* core; - QThread* coreThread; AddFriendForm* addFriendForm; SettingsWidget* settingsWidget; FilesForm* filesForm; From 331baa74474b27e18671d4a38a4847cf17e2e179 Mon Sep 17 00:00:00 2001 From: tux3/mlkj Date: Fri, 6 Feb 2015 19:01:31 +0100 Subject: [PATCH 3/5] Use GUI instead of Widget for common GUI tasks --- src/autoupdate.cpp | 3 +- src/core.cpp | 7 +- src/coreencryption.cpp | 12 +- src/friend.cpp | 6 +- src/group.cpp | 4 +- src/misc/style.cpp | 9 +- src/nexus.cpp | 12 ++ src/nexus.h | 2 + src/widget/callconfirmwidget.cpp | 9 +- src/widget/form/settings/generalform.cpp | 1 + src/widget/gui.cpp | 243 +++++++++++++++++++++++ src/widget/gui.h | 39 ++++ src/widget/toxsave.cpp | 11 +- src/widget/widget.cpp | 8 +- 14 files changed, 330 insertions(+), 36 deletions(-) diff --git a/src/autoupdate.cpp b/src/autoupdate.cpp index 9c4fcc666..5f7b54f97 100644 --- a/src/autoupdate.cpp +++ b/src/autoupdate.cpp @@ -19,6 +19,7 @@ #include "src/misc/serialize.h" #include "src/misc/settings.h" #include "src/widget/widget.h" +#include "src/widget/gui.h" #include #include #include @@ -490,7 +491,7 @@ void AutoUpdater::checkUpdatesAsyncInteractiveWorker() QDir updateDir(updateDirStr); if ((updateDir.exists() && QFile(updateDirStr+"flist").exists()) - || Widget::getInstance()->askQuestion(QObject::tr("Update", "The title of a message box"), + || GUI::askQuestion(QObject::tr("Update", "The title of a message box"), QObject::tr("An update is available, do you want to download it now?\nIt will be installed when qTox restarts."), true, false)) { downloadUpdate(); diff --git a/src/core.cpp b/src/core.cpp index f6fa4463c..610077fda 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -19,7 +19,7 @@ #include "misc/cdata.h" #include "misc/cstring.h" #include "misc/settings.h" -#include "widget/widget.h" +#include "widget/gui.h" #include "historykeeper.h" #include "src/audio.h" @@ -259,7 +259,6 @@ void Core::start() { setStatusMessage(tr("Toxing on qTox")); // this also solves the not updating issue setUsername(tr("qTox User")); - QMetaObject::invokeMethod(Widget::getInstance(), "onSettingsClicked"); // update ui with new profile } tox_callback_friend_request(tox, onFriendRequest, this); @@ -1284,7 +1283,7 @@ void Core::switchConfiguration(const QString& profile) saveCurrentInformation(); // part of a hack, see core.h ready = false; - Widget::getInstance()->setEnabledThreadsafe(false); + GUI::setEnabled(false); clearPassword(ptMain); clearPassword(ptHistory); @@ -1304,7 +1303,7 @@ void Core::switchConfiguration(const QString& profile) start(); if (isReady()) - Widget::getInstance()->setEnabledThreadsafe(true); + GUI::setEnabled(true); } void Core::loadFriends() diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index 69319f830..3f64fe7b3 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -19,7 +19,7 @@ /* was permanently moved here to handle encryption */ #include "core.h" -#include "src/widget/widget.h" +#include "src/widget/gui.h" #include #include #include "src/misc/settings.h" @@ -165,7 +165,7 @@ QByteArray Core::getSaltFromFile(QString filename) bool Core::loadEncryptedSave(QByteArray& data) { if (!Settings::getInstance().getEncryptTox()) - Widget::getInstance()->showWarningMsgBox(tr("Encryption error"), tr("The .tox file is encrypted, but encryption was not checked, continuing regardless.")); + GUI::showWarning(tr("Encryption error"), tr("The .tox file is encrypted, but encryption was not checked, continuing regardless.")); int error = -1; QString a(tr("Please enter the password for the %1 profile.", "used in load() when no pw is already set").arg(Settings::getInstance().getCurrentProfile())); @@ -190,7 +190,7 @@ bool Core::loadEncryptedSave(QByteArray& data) do { - QString pw = Widget::getInstance()->passwordDialog(tr("Change profile"), dialogtxt); + QString pw = GUI::passwordDialog(tr("Change profile"), dialogtxt); if (pw.isEmpty()) { @@ -216,7 +216,7 @@ void Core::checkEncryptedHistory() QByteArray salt = getSaltFromFile(path); if (exists && salt.size() == 0) { // maybe we should handle this better - Widget::getInstance()->showWarningMsgBox(tr("Encrypted chat history"), tr("No encrypted chat history file found, or it was corrupted.\nHistory will be disabled!")); + GUI::showWarning(tr("Encrypted chat history"), tr("No encrypted chat history file found, or it was corrupted.\nHistory will be disabled!")); Settings::getInstance().setEncryptLogs(false); Settings::getInstance().setEnableLogging(false); HistoryKeeper::resetInstance(); @@ -252,7 +252,7 @@ void Core::checkEncryptedHistory() bool error = true; do { - QString pw = Widget::getInstance()->passwordDialog(tr("Disable chat history"), dialogtxt); + QString pw = GUI::passwordDialog(tr("Disable chat history"), dialogtxt); if (pw.isEmpty()) { @@ -303,7 +303,7 @@ void Core::saveConfiguration(const QString& path) if (!pwsaltedkeys[ptMain]) { // probably zero chance event - Widget::getInstance()->showWarningMsgBox(tr("NO Password"), tr("Encryption is enabled, but there is no password! Encryption will be disabled.")); + GUI::showWarning(tr("NO Password"), tr("Encryption is enabled, but there is no password! Encryption will be disabled.")); Settings::getInstance().setEncryptTox(false); tox_save(tox, data); } diff --git a/src/friend.cpp b/src/friend.cpp index 856e2a58c..52f675cf5 100644 --- a/src/friend.cpp +++ b/src/friend.cpp @@ -18,7 +18,7 @@ #include "friendlist.h" #include "widget/friendwidget.h" #include "widget/form/chatform.h" -#include "widget/widget.h" +#include "widget/gui.h" #include "src/core.h" #include "src/misc/settings.h" @@ -52,7 +52,7 @@ void Friend::setName(QString name) chatForm->setName(name); if (widget->isActive()) - Widget::getInstance()->setWindowTitle(name); + GUI::setWindowTitle(name); } } @@ -65,7 +65,7 @@ void Friend::setAlias(QString name) chatForm->setName(dispName); if (widget->isActive()) - Widget::getInstance()->setWindowTitle(dispName); + GUI::setWindowTitle(dispName); } void Friend::setStatusMessage(QString message) diff --git a/src/group.cpp b/src/group.cpp index a75d933a2..c54601c44 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -20,7 +20,7 @@ #include "friendlist.h" #include "friend.h" #include "core.h" -#include "widget/widget.h" +#include "widget/gui.h" #include #include @@ -90,7 +90,7 @@ void Group::setName(const QString& name) chatForm->setName(name); if (widget->isActive()) - Widget::getInstance()->setWindowTitle(name); + GUI::setWindowTitle(name); } void Group::regeneratePeerList() diff --git a/src/misc/style.cpp b/src/misc/style.cpp index ad6f93c7b..ea1318fd7 100644 --- a/src/misc/style.cpp +++ b/src/misc/style.cpp @@ -16,10 +16,7 @@ #include "style.h" #include "settings.h" - -#include "src/widget/widget.h" -#include "ui_mainwindow.h" -#include "src/widget/genericchatroomwidget.h" +#include "src/widget/gui.h" #include #include @@ -198,11 +195,9 @@ void Style::setThemeColor(QColor color) dict["@themeMediumDark"] = getColor(ThemeMediumDark).name(); dict["@themeMedium"] = getColor(ThemeMedium).name(); dict["@themeLight"] = getColor(ThemeLight).name(); - - applyTheme(); } void Style::applyTheme() { - Widget::getInstance()->reloadTheme(); + GUI::reloadTheme(); } diff --git a/src/nexus.cpp b/src/nexus.cpp index 91b65530e..f8a6c1133 100644 --- a/src/nexus.cpp +++ b/src/nexus.cpp @@ -2,6 +2,7 @@ #include "core.h" #include "misc/settings.h" #include "video/camera.h" +#include "widget/gui.h" #include #include @@ -66,6 +67,7 @@ void Nexus::start() #else widget = Widget::getInstance(); #endif + GUI::getInstance(); // Connections #ifndef Q_OS_ANDROID @@ -119,3 +121,13 @@ Core* Nexus::getCore() { return getInstance().core; } + +AndroidGUI* Nexus::getAndroidGUI() +{ + return getInstance().androidgui; +} + +Widget* Nexus::getDesktopGUI() +{ + return getInstance().widget; +} diff --git a/src/nexus.h b/src/nexus.h index f8b5dd4b5..7c84bb1bf 100644 --- a/src/nexus.h +++ b/src/nexus.h @@ -19,6 +19,8 @@ public: static Nexus& getInstance(); static Core* getCore(); ///< Will return 0 if not started + static AndroidGUI* getAndroidGUI(); ///< Will return 0 if not started + static Widget* getDesktopGUI(); ///< Will return 0 if not started private: explicit Nexus(QObject *parent = 0); diff --git a/src/widget/callconfirmwidget.cpp b/src/widget/callconfirmwidget.cpp index 03cc7912f..a5663ec1a 100644 --- a/src/widget/callconfirmwidget.cpp +++ b/src/widget/callconfirmwidget.cpp @@ -1,5 +1,6 @@ #include "callconfirmwidget.h" -#include "widget.h" +#include "gui.h" +#include #include #include #include @@ -11,7 +12,7 @@ #include CallConfirmWidget::CallConfirmWidget(const QWidget *Anchor) : - QWidget(Widget::getInstance()), anchor(Anchor), + QWidget(GUI::getMainWidget()), anchor(Anchor), rectW{120}, rectH{85}, spikeW{30}, spikeH{15}, roundedFactor{20}, @@ -43,7 +44,7 @@ CallConfirmWidget::CallConfirmWidget(const QWidget *Anchor) : connect(buttonBox, &QDialogButtonBox::accepted, this, &CallConfirmWidget::accepted); connect(buttonBox, &QDialogButtonBox::rejected, this, &CallConfirmWidget::rejected); - connect(Widget::getInstance(), &Widget::resized, this, &CallConfirmWidget::reposition); + connect(&GUI::getInstance(), &GUI::resized, this, &CallConfirmWidget::reposition); layout->setMargin(12); layout->addSpacing(spikeH); @@ -56,7 +57,7 @@ CallConfirmWidget::CallConfirmWidget(const QWidget *Anchor) : void CallConfirmWidget::reposition() { - Widget* w = Widget::getInstance(); + QWidget* w = GUI::getMainWidget(); QPoint pos = anchor->mapToGlobal({(anchor->width()-rectW)/2,anchor->height()})-w->mapToGlobal({0,0}); // We don't want the widget to overflow past the right of the screen diff --git a/src/widget/form/settings/generalform.cpp b/src/widget/form/settings/generalform.cpp index 333d9a561..4aca50b3b 100644 --- a/src/widget/form/settings/generalform.cpp +++ b/src/widget/form/settings/generalform.cpp @@ -359,4 +359,5 @@ void GeneralForm::onThemeColorChanged(int) int index = bodyUI->themeColorCBox->currentIndex(); Settings::getInstance().setThemeColor(index); Style::setThemeColor(index); + Style::applyTheme(); } diff --git a/src/widget/gui.cpp b/src/widget/gui.cpp index 76f77e8db..d6b8a7dc0 100644 --- a/src/widget/gui.cpp +++ b/src/widget/gui.cpp @@ -1,11 +1,30 @@ #include "gui.h" +#include "src/nexus.h" +#include #include +#include +#include #include +#include +#include +#include #include +#ifdef Q_OS_ANDROID +#include "androidgui.h" +#else +#include "widget.h" +#endif + GUI::GUI(QObject *parent) : QObject(parent) { + assert(QThread::currentThread() == qApp->thread()); + +#ifndef Q_OS_ANDROID + assert(Nexus::getDesktopGUI()); + connect(Nexus::getDesktopGUI(), &Widget::resized, this, &GUI::resized); +#endif } GUI& GUI::getInstance() @@ -14,6 +33,90 @@ GUI& GUI::getInstance() return gui; } +// Implementation of the public clean interface + +void GUI::setEnabled(bool state) +{ + if (QThread::currentThread() == qApp->thread()) + { + getInstance()._setEnabled(state); + } + else + { + QMetaObject::invokeMethod(&getInstance(), "_setEnabled", Qt::BlockingQueuedConnection, + Q_ARG(bool, state)); + } +} + +void GUI::setWindowTitle(const QString& title) +{ + if (QThread::currentThread() == qApp->thread()) + { + getInstance()._setWindowTitle(title); + } + else + { + QMetaObject::invokeMethod(&getInstance(), "_setWindowTitle", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, title)); + } +} + +void GUI::reloadTheme() +{ + if (QThread::currentThread() == qApp->thread()) + { + getInstance()._reloadTheme(); + } + else + { + QMetaObject::invokeMethod(&getInstance(), "_reloadTheme", Qt::BlockingQueuedConnection); + } +} + +void GUI::showWarning(const QString& title, const QString& msg) +{ + if (QThread::currentThread() == qApp->thread()) + { + getInstance()._showWarning(title, msg); + } + else + { + QMetaObject::invokeMethod(&getInstance(), "_showWarning", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, title), Q_ARG(const QString&, msg)); + } +} + +void GUI::showInfo(const QString& title, const QString& msg) +{ + if (QThread::currentThread() == qApp->thread()) + { + getInstance()._showInfo(title, msg); + } + else + { + QMetaObject::invokeMethod(&getInstance(), "_showInfo", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, title), Q_ARG(const QString&, msg)); + } +} + +bool GUI::askQuestion(const QString& title, const QString& msg, + bool defaultAns, bool warning) +{ + if (QThread::currentThread() == qApp->thread()) + { + return getInstance()._askQuestion(title, msg, defaultAns, warning); + } + else + { + bool ret; + QMetaObject::invokeMethod(&getInstance(), "_askQuestion", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), + Q_ARG(const QString&, title), Q_ARG(const QString&, msg), + Q_ARG(bool, defaultAns), Q_ARG(bool, warning)); + return ret; + } +} + QString GUI::itemInputDialog(QWidget * parent, const QString & title, const QString & label, const QStringList & items, int current, bool editable, bool * ok, @@ -37,6 +140,77 @@ QString GUI::itemInputDialog(QWidget * parent, const QString & title, } } +QString GUI::passwordDialog(const QString& cancel, const QString& body) +{ + if (QThread::currentThread() == qApp->thread()) + { + return getInstance()._passwordDialog(cancel, body); + } + else + { + QString r; + QMetaObject::invokeMethod(&getInstance(), "_passwordDialog", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QString, r), + Q_ARG(const QString&, cancel), Q_ARG(const QString&, body)); + return r; + } +} + +// Private implementations + +void GUI::_setEnabled(bool state) +{ +#ifdef Q_OS_ANDROID + Nexus::getAndroidGUI()->setEnabled(state); +#else + Nexus::getDesktopGUI()->setEnabled(state); +#endif +} + +void GUI::_setWindowTitle(const QString& title) +{ + if (title.isEmpty()) + getMainWidget()->setWindowTitle("qTox"); + else + getMainWidget()->setWindowTitle("qTox - " +title); +} + +void GUI::_reloadTheme() +{ +#ifndef Q_OS_ANDROID + Nexus::getDesktopGUI()->reloadTheme(); +#endif +} + +void GUI::_showWarning(const QString& title, const QString& msg) +{ + QMessageBox::warning(getMainWidget(), title, msg); +} + +void GUI::_showInfo(const QString& title, const QString& msg) +{ + QMessageBox::information(getMainWidget(), title, msg); +} + +bool GUI::_askQuestion(const QString& title, const QString& msg, + bool defaultAns, bool warning) +{ + if (warning) + { + QMessageBox::StandardButton def = QMessageBox::Cancel; + if (defaultAns) + def = QMessageBox::Ok; + return QMessageBox::warning(getMainWidget(), title, msg, QMessageBox::Ok | QMessageBox::Cancel, def) == QMessageBox::Ok; + } + else + { + QMessageBox::StandardButton def = QMessageBox::No; + if (defaultAns) + def = QMessageBox::Yes; + return QMessageBox::question(getMainWidget(), title, msg, QMessageBox::Yes | QMessageBox::No, def) == QMessageBox::Yes; + } +} + QString GUI::_itemInputDialog(QWidget * parent, const QString & title, const QString & label, const QStringList & items, int current, bool editable, bool * ok, @@ -45,3 +219,72 @@ QString GUI::_itemInputDialog(QWidget * parent, const QString & title, { return QInputDialog::getItem(parent, title, label, items, current, editable, ok, flags, hints); } + +QString GUI::_passwordDialog(const QString& cancel, const QString& body) +{ + // we use a hack. It is considered that closing the dialog without explicitly clicking + // disable history is confusing. But we can't distinguish between clicking the cancel + // button and closing the dialog. So instead, we reverse the Ok and Cancel roles, + // so that nothing but explicitly clicking disable history closes the dialog + QString ret; + QInputDialog dialog; + dialog.setWindowTitle(tr("Enter your password")); + dialog.setOkButtonText(cancel); + dialog.setCancelButtonText(tr("Decrypt")); + dialog.setInputMode(QInputDialog::TextInput); + dialog.setTextEchoMode(QLineEdit::Password); + dialog.setLabelText(body); + + // problem with previous hack: the default button is disable history, not decrypt. + // use another hack to reverse the default buttons. + // http://www.qtcentre.org/threads/49924-Change-property-of-QInputDialog-button + QList l = dialog.findChildren(); + if (!l.isEmpty()) + { + QPushButton* ok = l.first()->button(QDialogButtonBox::Ok); + QPushButton* cancel = l.first()->button(QDialogButtonBox::Cancel); + if (ok && cancel) + { + ok->setAutoDefault(false); + ok->setDefault(false); + cancel->setAutoDefault(true); + cancel->setDefault(true); + } + else + qWarning() << "PasswordDialog: Missing button!"; + } + else + qWarning() << "PasswordDialog: No QDialogButtonBox!"; + + // using similar code, set QLabels to wrap + for (auto* label : dialog.findChildren()) + label->setWordWrap(true); + + while (true) + { + int val = dialog.exec(); + if (val == QDialog::Accepted) + return QString(); + else + { + ret = dialog.textValue(); + if (!ret.isEmpty()) + return ret; + } + dialog.setTextValue(""); + dialog.setLabelText(body + "\n\n" + tr("You must enter a non-empty password:")); + } +} + +// Other + +QWidget* GUI::getMainWidget() +{ + QWidget* maingui{nullptr}; +#ifdef Q_OS_ANDROID + maingui = Nexus::getAndroidGUI(); +#else + maingui = Nexus::getDesktopGUI(); +#endif + return maingui; +} diff --git a/src/widget/gui.h b/src/widget/gui.h index 7a7f70339..70cc73a7c 100644 --- a/src/widget/gui.h +++ b/src/widget/gui.h @@ -13,21 +13,60 @@ class GUI : public QObject Q_OBJECT public: static GUI& getInstance(); + /// Returns the main QWidget* of the application + static QWidget* getMainWidget(); + /// Will enable or disable the GUI. + /// A disabled GUI can't be interacted with by the user + static void setEnabled(bool state); + /// Change the title of the main window + /// This is usually always visible to the user + static void setWindowTitle(const QString& title); + /// Reloads the application theme and redraw the window + static void reloadTheme(); + /// Show a warning to the user, for example in a message box + static void showWarning(const QString& title, const QString& msg); + /// Show some text to the user, for example in a message box + static void showInfo(const QString& title, const QString& msg); + /// Asks the user a question, for example in a message box. + /// If warning is true, we will use a special warning style. + /// Returns the answer. + static bool askQuestion(const QString& title, const QString& msg, + bool defaultAns = false, bool warning = true); + /// Asks the user to input text and returns the answer. + /// The interface is equivalent to QInputDialog::getItem() static QString itemInputDialog(QWidget * parent, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints hints = Qt::ImhNone); + /// Asks the user to answer a password + /// cancel is the text on the cancel button and body + /// is descriptive text that will be shown to the user + static QString passwordDialog(const QString& cancel, const QString& body); + +signals: + /// Emitted when the GUI is resized on supported platforms + /// Guaranteed to work on desktop platforms + void resized(); private: explicit GUI(QObject *parent = 0); + // Private implementation, those must be called from the GUI thread private slots: + void _setEnabled(bool state); + void _setWindowTitle(const QString& title); + void _reloadTheme(); + void _showWarning(const QString& title, const QString& msg); + void _showInfo(const QString& title, const QString& msg); + bool _askQuestion(const QString& title, const QString& msg, + bool defaultAns = false, bool warning = true); QString _itemInputDialog(QWidget * parent, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone); + QString _passwordDialog(const QString& cancel, const QString& body); }; #endif // GUI_H diff --git a/src/widget/toxsave.cpp b/src/widget/toxsave.cpp index 9d14879db..8340b1e95 100644 --- a/src/widget/toxsave.cpp +++ b/src/widget/toxsave.cpp @@ -15,7 +15,7 @@ */ #include "toxsave.h" -#include "widget.h" +#include "gui.h" #include "src/core.h" #include "src/misc/settings.h" #include @@ -53,20 +53,19 @@ void handleToxSave(const QString& path) if (info.suffix() != "tox") { - QMessageBox::warning(Widget::getInstance(), - QObject::tr("Ignoring non-Tox file", "popup title"), - QObject::tr("Warning: you've chosen a file that is not a Tox save file; ignoring.", "popup text")); + GUI::showWarning(QObject::tr("Ignoring non-Tox file", "popup title"), + QObject::tr("Warning: you've chosen a file that is not a Tox save file; ignoring.", "popup text")); return; } QString profilePath = QDir(Settings::getSettingsDirPath()).filePath(profile + Core::TOX_EXT); - if (QFileInfo(profilePath).exists() && !Widget::getInstance()->askQuestion(QObject::tr("Profile already exists", "import confirm title"), + if (QFileInfo(profilePath).exists() && !GUI::askQuestion(QObject::tr("Profile already exists", "import confirm title"), QObject::tr("A profile named \"%1\" already exists. Do you want to erase it?", "import confirm text").arg(profile))) return; QFile::copy(path, profilePath); // no good way to update the ui from here... maybe we need a Widget:refreshUi() function... // such a thing would simplify other code as well I believe - QMessageBox::information(Widget::getInstance(), QObject::tr("Profile imported"), QObject::tr("%1.tox was successfully imported").arg(profile)); + GUI::showInfo(QObject::tr("Profile imported"), QObject::tr("%1.tox was successfully imported").arg(profile)); } diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 3a5d5ee5c..445a9855b 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -117,6 +117,9 @@ void Widget::init() this, SLOT(onIconClick(QSystemTrayIcon::ActivationReason))); + icon->show(); + icon->hide(); + if (Settings::getInstance().getShowSystemTray()) { icon->show(); @@ -125,7 +128,6 @@ void Widget::init() } else this->show(); - } else { @@ -194,7 +196,7 @@ void Widget::init() ui->statusButton->setEnabled(false); Style::setThemeColor(Settings::getInstance().getThemeColor()); - Style::applyTheme(); + reloadTheme(); filesForm = new FilesForm(); addFriendForm = new AddFriendForm; @@ -264,7 +266,7 @@ void Widget::updateTrayIcon() Widget::~Widget() { - qDebug() << "Deleting Widget"; + qDebug() << "Widget: Deleting Widget"; AutoUpdater::abortUpdates(); icon->hide(); hideMainForms(); From 2e7c73dcb0108cedb5be70c0615da98cdf1aa7f1 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 6 Feb 2015 19:38:08 +0100 Subject: [PATCH 4/5] Cleanup before returning from main --- src/main.cpp | 4 +++- src/nexus.cpp | 13 +++++++++++-- src/nexus.h | 1 + src/widget/systemtrayicon.cpp | 5 +++++ src/widget/systemtrayicon.h | 1 + 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8d5ba8934..43395a9f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -123,7 +123,7 @@ int main(int argc, char *argv[]) AutoUpdater::installLocalUpdate(); ///< NORETURN #endif -Nexus::getInstance().start(); + Nexus::getInstance().start(); #ifndef Q_OS_ANDROID // Inter-process communication @@ -191,5 +191,7 @@ Nexus::getInstance().start(); logFile = nullptr; #endif + Nexus::destroyInstance(); + return errorcode; } diff --git a/src/nexus.cpp b/src/nexus.cpp index f8a6c1133..9c80bcfcd 100644 --- a/src/nexus.cpp +++ b/src/nexus.cpp @@ -12,6 +12,8 @@ #include #endif +static Nexus* nexus{nullptr}; + Nexus::Nexus(QObject *parent) : QObject(parent), core{nullptr}, @@ -113,8 +115,15 @@ void Nexus::start() Nexus& Nexus::getInstance() { - static Nexus nexus; - return nexus; + if (!nexus) + nexus = new Nexus; + return *nexus; +} + +void Nexus::destroyInstance() +{ + delete nexus; + nexus = nullptr; } Core* Nexus::getCore() diff --git a/src/nexus.h b/src/nexus.h index 7c84bb1bf..f198f21cc 100644 --- a/src/nexus.h +++ b/src/nexus.h @@ -18,6 +18,7 @@ public: void start(); ///< Will initialise the systems (GUI, Core, ...) static Nexus& getInstance(); + static void destroyInstance(); static Core* getCore(); ///< Will return 0 if not started static AndroidGUI* getAndroidGUI(); ///< Will return 0 if not started static Widget* getDesktopGUI(); ///< Will return 0 if not started diff --git a/src/widget/systemtrayicon.cpp b/src/widget/systemtrayicon.cpp index a31929d3e..e33c0a22c 100644 --- a/src/widget/systemtrayicon.cpp +++ b/src/widget/systemtrayicon.cpp @@ -42,6 +42,11 @@ SystemTrayIcon::SystemTrayIcon() } } +SystemTrayIcon::~SystemTrayIcon() +{ + qDebug() << "Deleting SystemTrayIcon"; +} + QString SystemTrayIcon::extractIconToFile(QIcon icon, QString name) { QString iconPath; diff --git a/src/widget/systemtrayicon.h b/src/widget/systemtrayicon.h index aa5120cd0..540d96285 100644 --- a/src/widget/systemtrayicon.h +++ b/src/widget/systemtrayicon.h @@ -12,6 +12,7 @@ class SystemTrayIcon : public QObject Q_OBJECT public: SystemTrayIcon(); + ~SystemTrayIcon(); void setContextMenu(QMenu* menu); void show(); void hide(); From 3b9d4eba2e680b7d0da8388874475ac3424cb978 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 6 Feb 2015 19:51:03 +0100 Subject: [PATCH 5/5] Assert that Widget isn't used on Android That would cause horrible conflicts and apreciable slowdowns --- src/widget/widget.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 445a9855b..ce7c42ee1 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -37,6 +37,7 @@ #include "src/platform/timer.h" #include "systemtrayicon.h" #include "src/nexus.h" +#include #include #include #include @@ -54,6 +55,12 @@ #include #include +#ifdef Q_OS_ANDROID +#define IS_ON_DESKTOP_GUI 0 +#else +#define IS_ON_DESKTOP_GUI 1 +#endif + void toxActivateEventHandler(const QByteArray& data) { if (data != "$activate") @@ -285,6 +292,8 @@ Widget::~Widget() Widget* Widget::getInstance() { + assert(IS_ON_DESKTOP_GUI); // Widget must only be used on Desktop platforms + if (!instance) { instance = new Widget();