--- qsampler/trunk/src/main.cpp 2008/05/14 17:37:45 1739 +++ qsampler/trunk/src/main.cpp 2008/05/23 23:35:55 1740 @@ -1,7 +1,7 @@ // main.cpp // /**************************************************************************** - Copyright (C) 2004-2007, rncbc aka Rui Nuno Capela. All rights reserved. + Copyright (C) 2004-2008, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008 Christian Schoenebeck This program is free software; you can redistribute it and/or @@ -25,36 +25,218 @@ #include "qsamplerMainForm.h" #include +#include #include #include #if defined(__APPLE__) // Toshi Nagata 20080105 #include #endif +#if defined(Q_WS_X11) + //------------------------------------------------------------------------- -// main - The main program trunk. +// Single application instance stuff (Qt/X11 only atm.) // -int main ( int argc, char **argv ) -{ - Q_INIT_RESOURCE(qsampler); +#include + +#include +#include - QApplication app(argc, argv); +#define QSAMPLER_XUNIQUE "qsamplerMainForm_xunique" - // Load translation support. - QTranslator translator(0); - QLocale loc; - if (loc.language() != QLocale::C) { - QString sLocName = "qsampler_" + loc.name(); - if (!translator.load(sLocName, ".")) { - QString sLocPath = CONFIG_PREFIX "/share/locale"; - if (!translator.load(sLocName, sLocPath)) - fprintf(stderr, "Warning: no locale found: %s/%s.qm\n", +#endif + +class qsamplerApplication : public QApplication +{ +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 (m_pQtTranslator->load(sLocName, sLocPath)) { + QApplication::installTranslator(m_pQtTranslator); + } else { + 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 + } + // Try own application translation... + m_pMyTranslator = new QTranslator(this); + sLocName = "qsampler_" + loc.name(); + if (m_pMyTranslator->load(sLocName, sLocPath)) { + QApplication::installTranslator(m_pMyTranslator); + } else { + sLocPath = CONFIG_PREFIX "/share/locale"; + 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 + } + } + } + #if defined(Q_WS_X11) + 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); + #endif + } + + // Destructor. + ~qsamplerApplication() + { + if (m_pMyTranslator) delete m_pMyTranslator; + if (m_pQtTranslator) delete m_pQtTranslator; + } + + // Main application widget accessors. + void setMainWidget(QWidget *pWidget) + { + m_pWidget = pWidget; + #if defined(Q_WS_X11) + XGrabServer(m_pDisplay); + m_wOwner = m_pWidget->winId(); + XSetSelectionOwner(m_pDisplay, m_aUnique, m_wOwner, CurrentTime); + XUngrabServer(m_pDisplay); + #endif + } + + QWidget *mainWidget() const { return m_pWidget; } + + // Check if another instance is running, + // and raise its proper main widget... + bool setup() + { + #if defined(Q_WS_X11) + if (m_wOwner != None) { + // First, notify any freedesktop.org WM + // that we're about to show the main widget... + Screen *pScreen = XDefaultScreenOfDisplay(m_pDisplay); + int iScreen = XScreenNumberOfScreen(pScreen); + XEvent ev; + memset(&ev, 0, sizeof(ev)); + ev.xclient.type = ClientMessage; + ev.xclient.display = m_pDisplay; + ev.xclient.window = m_wOwner; + ev.xclient.message_type = XInternAtom(m_pDisplay, "_NET_ACTIVE_WINDOW", false); + ev.xclient.format = 32; + ev.xclient.data.l[0] = 0; // Source indication. + ev.xclient.data.l[1] = 0; // Timestamp. + ev.xclient.data.l[2] = 0; // Requestor's currently active window (none) + ev.xclient.data.l[3] = 0; + ev.xclient.data.l[4] = 0; + XSelectInput(m_pDisplay, m_wOwner, StructureNotifyMask); + XSendEvent(m_pDisplay, RootWindow(m_pDisplay, iScreen), false, + (SubstructureNotifyMask | SubstructureRedirectMask), &ev); + XSync(m_pDisplay, false); + XRaiseWindow(m_pDisplay, m_wOwner); + // And then, let it get caught on destination + // by QApplication::x11EventFilter... + QByteArray value = QSAMPLER_XUNIQUE; + XChangeProperty( + m_pDisplay, + m_wOwner, + m_aUnique, + m_aUnique, 8, + PropModeReplace, + (unsigned char *) value.data(), + value.length()); + // Done. + return true; + } + #endif + return false; + } + +#if defined(Q_WS_X11) + bool x11EventFilter(XEvent *pEv) + { + if (m_pWidget && m_wOwner != None + && pEv->type == PropertyNotify + && pEv->xproperty.window == m_wOwner + && pEv->xproperty.state == PropertyNewValue) { + // 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); } - app.installTranslator(&translator); + return QApplication::x11EventFilter(pEv); } +#endif + +private: + + // Translation support. + QTranslator *m_pQtTranslator; + QTranslator *m_pMyTranslator; + + // Instance variables. + QWidget *m_pWidget; + +#if defined(Q_WS_X11) + Display *m_pDisplay; + Atom m_aUnique; + Window m_wOwner; +#endif +}; + + +//------------------------------------------------------------------------- +// main - The main program trunk. +// + +int main ( int argc, char **argv ) +{ + Q_INIT_RESOURCE(qsampler); + + qsamplerApplication app(argc, argv); #if defined(__APPLE__) // Toshi Nagata 20080105 { @@ -79,11 +261,20 @@ return 1; } + // Have another instance running? + if (app.setup()) { + app.quit(); + return 2; + } + // Construct, setup and show the main form. QSampler::MainForm w; w.setup(&options); w.show(); + // Settle this one as application main widget... + app.setMainWidget(&w); + // Register the quit signal/slot. // app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));