--- qsampler/trunk/src/qsampler.cpp 2017/01/02 12:11:50 3065 +++ qsampler/trunk/src/qsampler.cpp 2019/08/23 10:27:34 3560 @@ -1,7 +1,7 @@ // qsampler.cpp // /**************************************************************************** - Copyright (C) 2004-2017, rncbc aka Rui Nuno Capela. All rights reserved. + Copyright (C) 2004-2019, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007,2008,2015 Christian Schoenebeck This program is free software; you can redistribute it and/or @@ -20,11 +20,11 @@ *****************************************************************************/ -#include "qsamplerAbout.h" +#include "qsampler.h" + #include "qsamplerOptions.h" #include "qsamplerMainForm.h" -#include #include #include #include @@ -41,7 +41,7 @@ #define CONFIG_DATADIR CONFIG_PREFIX "/share" #endif -#if WIN32 +#if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) #define RELATIVE_LOCALE_DIR "/share/locale" #elif defined(__APPLE__) #define RELATIVE_LOCALE_DIR "/../Resources" @@ -52,176 +52,167 @@ // Singleton application instance stuff (Qt/X11 only atm.) // -#if QT_VERSION < 0x050000 -#if defined(Q_WS_X11) -#define CONFIG_X11 -#endif -#else -#if defined(QT_X11EXTRAS_LIB) -#define CONFIG_X11 -#endif -#endif +#ifdef CONFIG_XUNIQUE +#define QSAMPLER_XUNIQUE "qsamplerApplication" +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #ifdef CONFIG_X11 -#ifdef CONFIG_XUNIQUE -#include +#include /* for gethostname() */ #include #include -#define QSAMPLER_XUNIQUE "qsamplerApplication" - -#if QT_VERSION >= 0x050100 - -#include -#include - -#include - -class qsamplerApplication; - -class qsamplerXcbEventFilter : public QAbstractNativeEventFilter -{ -public: - - // Constructor. - qsamplerXcbEventFilter(qsamplerApplication *pApp) - : QAbstractNativeEventFilter(), m_pApp(pApp) {} - - // XCB event filter (virtual processor). - bool nativeEventFilter(const QByteArray& eventType, void *message, long *); - -private: - - // Instance variable. - qsamplerApplication *m_pApp; -}; - +#endif // CONFIG_X11 +#else +#include +#include +#include +#include #endif #endif // CONFIG_XUNIQUE -#endif // CONFIG_X11 -class qsamplerApplication : public QApplication +// Constructor. +qsamplerApplication::qsamplerApplication ( int& argc, char **argv ) + : QApplication(argc, argv), + m_pQtTranslator(nullptr), m_pMyTranslator(nullptr), m_pWidget(nullptr) { -public: - - // Constructor. - qsamplerApplication(int& argc, char **argv) : QApplication(argc, argv), - m_pQtTranslator(0), m_pMyTranslator(0), m_pWidget(0) - { - // Load translation support. - QLocale loc; - if (loc.language() != QLocale::C) { - // Try own Qt translation... - m_pQtTranslator = new QTranslator(this); - QString sLocName = "qt_" + loc.name(); - QString sLocPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); +#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) + QApplication::setApplicationName(QSAMPLER_TITLE); + QApplication::setApplicationDisplayName(QSAMPLER_TITLE); + // QSAMPLER_TITLE " - " + QObject::tr(QSAMPLER_SUBTITLE)); +#endif + // Load translation support. + QLocale loc; + if (loc.language() != QLocale::C) { + // Try own Qt translation... + m_pQtTranslator = new QTranslator(this); + QString sLocName = "qt_" + loc.name(); + QString sLocPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + if (m_pQtTranslator->load(sLocName, sLocPath)) { + QApplication::installTranslator(m_pQtTranslator); + } else { + #ifdef RELATIVE_LOCALE_DIR + sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR; if (m_pQtTranslator->load(sLocName, sLocPath)) { QApplication::installTranslator(m_pQtTranslator); } else { - #ifdef RELATIVE_LOCALE_DIR - sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR; - if (m_pQtTranslator->load(sLocName, sLocPath)) { - QApplication::installTranslator(m_pQtTranslator); - } else { - #endif - delete m_pQtTranslator; - m_pQtTranslator = 0; + #endif + delete m_pQtTranslator; + m_pQtTranslator = 0; + #ifdef CONFIG_DEBUG + qWarning("Warning: no translation found for '%s' locale: %s/%s.qm", + loc.name().toUtf8().constData(), + sLocPath.toUtf8().constData(), + sLocName.toUtf8().constData()); + #endif + #ifdef RELATIVE_LOCALE_DIR + } + #endif + } + // Try own application translation... + m_pMyTranslator = new QTranslator(this); + sLocName = "qsampler_" + loc.name(); + if (m_pMyTranslator->load(sLocName, sLocPath)) { + QApplication::installTranslator(m_pMyTranslator); + } else { + #ifdef RELATIVE_LOCALE_DIR + sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR; + #else + sLocPath = CONFIG_DATADIR "/qsampler/translations"; + #endif + if (m_pMyTranslator->load(sLocName, sLocPath)) { + QApplication::installTranslator(m_pMyTranslator); + } else { + delete m_pMyTranslator; + m_pMyTranslator = 0; #ifdef CONFIG_DEBUG qWarning("Warning: no translation found for '%s' locale: %s/%s.qm", loc.name().toUtf8().constData(), sLocPath.toUtf8().constData(), sLocName.toUtf8().constData()); #endif - #ifdef RELATIVE_LOCALE_DIR - } - #endif - } - // Try own application translation... - m_pMyTranslator = new QTranslator(this); - sLocName = "qsampler_" + loc.name(); - if (m_pMyTranslator->load(sLocName, sLocPath)) { - QApplication::installTranslator(m_pMyTranslator); - } else { - #ifdef RELATIVE_LOCALE_DIR - sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR; - #else - sLocPath = CONFIG_DATADIR "/qsampler/translations"; - #endif - if (m_pMyTranslator->load(sLocName, sLocPath)) { - QApplication::installTranslator(m_pMyTranslator); - } else { - delete m_pMyTranslator; - m_pMyTranslator = 0; - #ifdef CONFIG_DEBUG - qWarning("Warning: no translation found for '%s' locale: %s/%s.qm", - loc.name().toUtf8().constData(), - sLocPath.toUtf8().constData(), - sLocName.toUtf8().constData()); - #endif - } } } - #ifdef CONFIG_X11 - #ifdef CONFIG_XUNIQUE - // Instance uniqueness initialization... - m_pDisplay = QX11Info::display(); - m_aUnique = XInternAtom(m_pDisplay, QSAMPLER_XUNIQUE, false); - XGrabServer(m_pDisplay); - m_wOwner = XGetSelectionOwner(m_pDisplay, m_aUnique); - XUngrabServer(m_pDisplay); - #if QT_VERSION >= 0x050100 - m_pXcbEventFilter = new qsamplerXcbEventFilter(this); - installNativeEventFilter(m_pXcbEventFilter); - #endif - #endif // CONFIG_XUNIQUE - #endif // CONFIG_X11 } +#ifdef CONFIG_XUNIQUE +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) +#ifdef CONFIG_X11 + m_pDisplay = nullptr; + m_aUnique = 0; + m_wOwner = 0; +#endif // CONFIG_X11 +#else + m_pMemory = nullptr; + m_pServer = nullptr; +#endif +#endif // CONFIG_XUNIQUE +} - // Destructor. - ~qsamplerApplication() - { - #ifdef CONFIG_X11 - #ifdef CONFIG_XUNIQUE - #if QT_VERSION >= 0x050100 - removeNativeEventFilter(m_pXcbEventFilter); - delete m_pXcbEventFilter; - #endif - #endif // CONFIG_XUNIQUE - #endif // CONFIG_X11 - if (m_pMyTranslator) delete m_pMyTranslator; - if (m_pQtTranslator) delete m_pQtTranslator; - } - // Main application widget accessors. - void setMainWidget(QWidget *pWidget) - { - m_pWidget = pWidget; - #ifdef CONFIG_X11 - #ifdef CONFIG_XUNIQUE - m_wOwner = m_pWidget->winId(); - if (m_pDisplay && m_wOwner) { - XGrabServer(m_pDisplay); - XSetSelectionOwner(m_pDisplay, m_aUnique, m_wOwner, CurrentTime); - XUngrabServer(m_pDisplay); - } - #endif // CONFIG_XUNIQUE - #endif // CONFIG_X11 +// Destructor. +qsamplerApplication::~qsamplerApplication (void) +{ +#ifdef CONFIG_XUNIQUE +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + if (m_pServer) { + m_pServer->close(); + delete m_pServer; + m_pServer = nullptr; + } + if (m_pMemory) { + delete m_pMemory; + m_pMemory = nullptr; +} +#endif +#endif // CONFIG_XUNIQUE + if (m_pMyTranslator) delete m_pMyTranslator; + if (m_pQtTranslator) delete m_pQtTranslator; +} + + +// Main application widget accessors. +void qsamplerApplication::setMainWidget ( QWidget *pWidget ) +{ + m_pWidget = pWidget; +#ifdef CONFIG_XUNIQUE +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) +#ifdef CONFIG_X11 + m_wOwner = m_pWidget->winId(); + if (m_pDisplay && m_wOwner) { + XGrabServer(m_pDisplay); + XSetSelectionOwner(m_pDisplay, m_aUnique, m_wOwner, CurrentTime); + XUngrabServer(m_pDisplay); } +#endif // CONFIG_X11 +#endif +#endif // CONFIG_XUNIQUE +} - QWidget *mainWidget() const { return m_pWidget; } - // Check if another instance is running, - // and raise its proper main widget... - bool setup() - { - #ifdef CONFIG_X11 - #ifdef CONFIG_XUNIQUE - if (m_pDisplay && m_wOwner != None) { +// Check if another instance is running, +// and raise its proper main widget... +bool qsamplerApplication::setup (void) +{ +#ifdef CONFIG_XUNIQUE +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) +#ifdef CONFIG_X11 + m_pDisplay = QX11Info::display(); + if (m_pDisplay) { + QString sUnique = QSAMPLER_XUNIQUE; + char szHostName[255]; + if (::gethostname(szHostName, sizeof(szHostName)) == 0) { + sUnique += '@'; + sUnique += szHostName; + } + m_aUnique = XInternAtom(m_pDisplay, sUnique.toUtf8().constData(), false); + XGrabServer(m_pDisplay); + m_wOwner = XGetSelectionOwner(m_pDisplay, m_aUnique); + XUngrabServer(m_pDisplay); + if (m_wOwner != None) { // First, notify any freedesktop.org WM // that we're about to show the main widget... Screen *pScreen = XDefaultScreenOfDisplay(m_pDisplay); @@ -257,100 +248,145 @@ // Done. return true; } - #endif // CONFIG_XUNIQUE - #endif // CONFIG_X11 - return false; } - -#ifdef CONFIG_X11 -#ifdef CONFIG_XUNIQUE - void x11PropertyNotify(Window w) - { - if (m_pDisplay && m_pWidget && m_wOwner == w) { - // Always check whether our property-flag is still around... - Atom aType; - int iFormat = 0; - unsigned long iItems = 0; - unsigned long iAfter = 0; - unsigned char *pData = 0; - if (XGetWindowProperty( - m_pDisplay, - m_wOwner, - m_aUnique, - 0, 1024, - false, - m_aUnique, - &aType, - &iFormat, - &iItems, - &iAfter, - &pData) == Success - && aType == m_aUnique && iItems > 0 && iAfter == 0) { - // Avoid repeating it-self... - XDeleteProperty(m_pDisplay, m_wOwner, m_aUnique); - // Just make it always shows up fine... - m_pWidget->show(); - m_pWidget->raise(); - m_pWidget->activateWindow(); - } - // Free any left-overs... - if (iItems > 0 && pData) - XFree(pData); +#endif // CONFIG_X11 + return false; +#else + m_sUnique = QCoreApplication::applicationName(); + m_sUnique += '@'; + m_sUnique += QHostInfo::localHostName(); +#ifdef Q_OS_UNIX + m_pMemory = new QSharedMemory(m_sUnique); + m_pMemory->attach(); + delete m_pMemory; +#endif + m_pMemory = new QSharedMemory(m_sUnique); + bool bServer = false; + const qint64 pid = QCoreApplication::applicationPid(); + struct Data { qint64 pid; }; + if (m_pMemory->create(sizeof(Data))) { + m_pMemory->lock(); + Data *pData = static_cast (m_pMemory->data()); + if (pData) { + pData->pid = pid; + bServer = true; } + m_pMemory->unlock(); } -#if QT_VERSION < 0x050000 - bool x11EventFilter(XEvent *pEv) - { - if (pEv->type == PropertyNotify - && pEv->xproperty.state == PropertyNewValue) - x11PropertyNotify(pEv->xproperty.window); - return QApplication::x11EventFilter(pEv); + else + if (m_pMemory->attach()) { + m_pMemory->lock(); // maybe not necessary? + Data *pData = static_cast (m_pMemory->data()); + if (pData) + bServer = (pData->pid == pid); + m_pMemory->unlock(); + } + if (bServer) { + QLocalServer::removeServer(m_sUnique); + m_pServer = new QLocalServer(); + m_pServer->setSocketOptions(QLocalServer::UserAccessOption); + m_pServer->listen(m_sUnique); + QObject::connect(m_pServer, + SIGNAL(newConnection()), + SLOT(newConnectionSlot())); + } else { + QLocalSocket socket; + socket.connectToServer(m_sUnique); + if (socket.state() == QLocalSocket::ConnectingState) + socket.waitForConnected(200); + if (socket.state() == QLocalSocket::ConnectedState) { + socket.write(QCoreApplication::arguments().join(' ').toUtf8()); + socket.flush(); + socket.waitForBytesWritten(200); + } } + return !bServer; #endif -#endif // CONFIG_XUNIQUE -#endif // CONFIG_X11 - -private: - - // Translation support. - QTranslator *m_pQtTranslator; - QTranslator *m_pMyTranslator; +#else + return false; +#endif // !CONFIG_XUNIQUE +} - // Instance variables. - QWidget *m_pWidget; -#ifdef CONFIG_X11 #ifdef CONFIG_XUNIQUE - Display *m_pDisplay; - Atom m_aUnique; - Window m_wOwner; -#if QT_VERSION >= 0x050100 - qsamplerXcbEventFilter *m_pXcbEventFilter; -#endif -#endif // CONFIG_XUNIQUE +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) +#ifdef CONFIG_X11 + +void qsamplerApplication::x11PropertyNotify ( Window w ) +{ + if (m_pDisplay && m_pWidget && m_wOwner == w) { + // Always check whether our property-flag is still around... + Atom aType; + int iFormat = 0; + unsigned long iItems = 0; + unsigned long iAfter = 0; + unsigned char *pData = 0; + if (XGetWindowProperty( + m_pDisplay, + m_wOwner, + m_aUnique, + 0, 1024, + false, + m_aUnique, + &aType, + &iFormat, + &iItems, + &iAfter, + &pData) == Success + && aType == m_aUnique && iItems > 0 && iAfter == 0) { + // Avoid repeating it-self... + XDeleteProperty(m_pDisplay, m_wOwner, m_aUnique); + // Just make it always shows up fine... + m_pWidget->show(); + m_pWidget->raise(); + m_pWidget->activateWindow(); + } + // Free any left-overs... + if (iItems > 0 && pData) + XFree(pData); + } +} + + +bool qsamplerApplication::x11EventFilter ( XEvent *pEv ) +{ + if (pEv->type == PropertyNotify + && pEv->xproperty.state == PropertyNewValue) + x11PropertyNotify(pEv->xproperty.window); + return QApplication::x11EventFilter(pEv); +} + #endif // CONFIG_X11 -}; +#else +// Local server conection slot. +void qsamplerApplication::newConnectionSlot (void) +{ + QLocalSocket *pSocket = m_pServer->nextPendingConnection(); + QObject::connect(pSocket, + SIGNAL(readyRead()), + SLOT(readyReadSlot())); +} -#ifdef CONFIG_X11 -#ifdef CONFIG_XUNIQUE -#if QT_VERSION >= 0x050100 -// XCB Event filter (virtual processor). -bool qsamplerXcbEventFilter::nativeEventFilter ( - const QByteArray& eventType, void *message, long * ) +// Local server data-ready slot. +void qsamplerApplication::readyReadSlot (void) { - if (eventType == "xcb_generic_event_t") { - xcb_property_notify_event_t *pEv - = static_cast (message); - if ((pEv->response_type & ~0x80) == XCB_PROPERTY_NOTIFY - && pEv->state == XCB_PROPERTY_NEW_VALUE) - m_pApp->x11PropertyNotify(pEv->window); + QLocalSocket *pSocket = qobject_cast (sender()); + if (pSocket) { + const qint64 nread = pSocket->bytesAvailable(); + if (nread > 0) { + const QByteArray data = pSocket->read(nread); + // Just make it always shows up fine... + m_pWidget->hide(); + m_pWidget->show(); + m_pWidget->raise(); + m_pWidget->activateWindow(); + } } - return false; } + #endif #endif // CONFIG_XUNIQUE -#endif // CONFIG_X11 //------------------------------------------------------------------------- @@ -374,7 +410,7 @@ char cmd[80]; // Reinstall default handler; prevent race conditions... - signal(signo, SIG_DFL); + ::signal(signo, SIG_DFL); static const char *shell = "/bin/sh"; static const char *format = "gdb -q --batch --pid=%d" @@ -390,7 +426,7 @@ // Fork child... if (pid == 0) { - execl(shell, shell, "-c", cmd, NULL); + execl(shell, shell, "-c", cmd, nullptr); _exit(1); return; } @@ -420,12 +456,15 @@ Q_INIT_RESOURCE(qsampler); #ifdef CONFIG_STACKTRACE #if defined(__GNUC__) && defined(Q_OS_LINUX) - signal(SIGILL, stacktrace); - signal(SIGFPE, stacktrace); - signal(SIGSEGV, stacktrace); - signal(SIGABRT, stacktrace); - signal(SIGBUS, stacktrace); + ::signal(SIGILL, stacktrace); + ::signal(SIGFPE, stacktrace); + ::signal(SIGSEGV, stacktrace); + ::signal(SIGABRT, stacktrace); + ::signal(SIGBUS, stacktrace); +#endif #endif +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif qsamplerApplication app(argc, argv); @@ -461,7 +500,7 @@ // Dark themes grayed/disabled color group fix... QPalette pal(app.palette()); if (pal.base().color().value() < 0x7f) { - #if QT_VERSION >= 0x050000 + #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) const QColor& color = pal.window().color(); const int iGroups = int(QPalette::Active | QPalette::Inactive) + 1; for (int i = 0; i < iGroups; ++i) {