--- qsampler/trunk/src/main.cpp 2007/10/28 23:30:36 1461 +++ qsampler/trunk/src/main.cpp 2008/07/02 13:19:09 1749 @@ -1,7 +1,8 @@ // 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 modify it under the terms of the GNU General Public License @@ -19,52 +20,270 @@ *****************************************************************************/ -#include -#include -#include - #include "qsamplerAbout.h" #include "qsamplerOptions.h" #include "qsamplerMainForm.h" +#include +#include +#include +#include +#if defined(__APPLE__) // Toshi Nagata 20080105 +#include +#endif + +#if defined(Q_WS_X11) + +//------------------------------------------------------------------------- +// Single application instance stuff (Qt/X11 only atm.) +// + +#include + +#include +#include + +#define QSAMPLER_XUNIQUE "qsamplerMainForm_xunique" + +#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); + } + 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 ) { - QApplication app(argc, argv); + Q_INIT_RESOURCE(qsampler); + + qsamplerApplication app(argc, argv); - // Load translation support. - QTranslator translator(0); - QString sLocale = QTextCodec::codecForLocale()->name(); - if (sLocale != "C") { //TODO: not sure if "C" locale name exists in Qt4 - QString sLocName = "qsampler_" + sLocale; - 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", sLocPath.toLatin1().data(), sLocName.toLatin1().data()); - } - app.installTranslator(&translator); - } - - // Construct default settings; override with command line arguments. - qsamplerOptions options; - if (!options.parse_args(app.argc(), app.argv())) { - app.quit(); - return 1; - } - - // Construct, setup and show the main form. - QSampler::MainForm w; - app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); - w.setup(&options); - w.show(); + #if defined(__APPLE__) // Toshi Nagata 20080105 + { + // Set the plugin path to @exetutable_path/../plugins + QDir dir(QApplication::applicationDirPath()); + dir.cdUp(); // "Contents" directory + QApplication::setLibraryPaths(QStringList(dir.absolutePath() + "/plugins")); + + // Set the PATH environment variable to include @executable_path/../../.. + dir.cdUp(); + dir.cdUp(); + QString path(getenv("PATH")); + path = dir.absolutePath() + ":" + path; + setenv("PATH", path.toUtf8().constData(), 1); + } + #endif + + // Construct default settings; override with command line arguments. + QSampler::Options options; + if (!options.parse_args(app.argc(), app.argv())) { + app.quit(); + return 1; + } + + // Have another instance running? + if (app.setup()) { + app.quit(); + return 2; + } + + // Set default base font... + if (options.iBaseFontSize > 0) + app.setFont(QFont(app.font().family(), options.iBaseFontSize)); + + // Construct, setup and show the main form. + QSampler::MainForm w; + w.setup(&options); + w.show(); - // Register the quit signal/slot. - // app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); + // Settle this one as application main widget... + app.setMainWidget(&w); - return app.exec(); + // Register the quit signal/slot. + // app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); + + return app.exec(); } + // end of main.cpp