/[svn]/qsampler/trunk/src/qsampler.cpp
ViewVC logotype

Annotation of /qsampler/trunk/src/qsampler.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3996 - (hide annotations) (download)
Sun Sep 26 22:46:23 2021 UTC (2 years, 6 months ago) by capela
File size: 14754 byte(s)
- Fixed for Qt6 plugins path eg. widget theme styles.
1 capela 2074 // qsampler.cpp
2     //
3     /****************************************************************************
4 capela 3849 Copyright (C) 2004-2021, rncbc aka Rui Nuno Capela. All rights reserved.
5 capela 3681 Copyright (C) 2007,2008,2015,2019 Christian Schoenebeck
6 capela 2074
7     This program is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     as published by the Free Software Foundation; either version 2
10     of the License, or (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License along
18     with this program; if not, write to the Free Software Foundation, Inc.,
19     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20    
21     *****************************************************************************/
22    
23 capela 3493 #include "qsampler.h"
24    
25 capela 2074 #include "qsamplerOptions.h"
26     #include "qsamplerMainForm.h"
27    
28 capela 3648 #include "qsamplerPaletteForm.h"
29    
30     #include <QDir>
31    
32     #include <QStyleFactory>
33    
34 capela 2074 #include <QLibraryInfo>
35     #include <QTranslator>
36     #include <QLocale>
37 capela 2459
38 capela 2074 #if defined(__APPLE__) // Toshi Nagata 20080105
39     #include <QDir>
40     #endif
41    
42 capela 2998 #ifndef CONFIG_PREFIX
43     #define CONFIG_PREFIX "/usr/local"
44     #endif
45    
46     #ifndef CONFIG_DATADIR
47     #define CONFIG_DATADIR CONFIG_PREFIX "/share"
48     #endif
49    
50 capela 3648 #ifndef CONFIG_LIBDIR
51     #if defined(__x86_64__)
52     #define CONFIG_LIBDIR CONFIG_PREFIX "/lib64"
53     #else
54     #define CONFIG_LIBDIR CONFIG_PREFIX "/lib"
55     #endif
56     #endif
57    
58     #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
59     #define CONFIG_PLUGINSDIR CONFIG_LIBDIR "/qt4/plugins"
60 capela 3996 #elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
61     #define CONFIG_PLUGINSDIR CONFIG_LIBDIR "/qt5/plugins"
62 capela 3648 #else
63 capela 3996 #define CONFIG_PLUGINSDIR CONFIG_LIBDIR "/qt6/plugins"
64 capela 3648 #endif
65    
66 capela 3358 #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
67 persson 2210 #define RELATIVE_LOCALE_DIR "/share/locale"
68     #elif defined(__APPLE__)
69     #define RELATIVE_LOCALE_DIR "/../Resources"
70     #endif
71 capela 2074
72 persson 2210
73 capela 2074 //-------------------------------------------------------------------------
74     // Singleton application instance stuff (Qt/X11 only atm.)
75     //
76    
77 capela 2839 #ifdef CONFIG_XUNIQUE
78    
79 capela 3496 #define QSAMPLER_XUNIQUE "qsamplerApplication"
80    
81 capela 3520 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
82 capela 3496 #ifdef CONFIG_X11
83    
84 capela 3493 #include <unistd.h> /* for gethostname() */
85 capela 2074
86     #include <X11/Xatom.h>
87     #include <X11/Xlib.h>
88    
89 capela 3496 #endif // CONFIG_X11
90     #else
91     #include <QSharedMemory>
92     #include <QLocalServer>
93     #include <QLocalSocket>
94     #include <QHostInfo>
95 capela 2074 #endif
96    
97 capela 2839 #endif // CONFIG_XUNIQUE
98    
99    
100 capela 3493 // Constructor.
101     qsamplerApplication::qsamplerApplication ( int& argc, char **argv )
102     : QApplication(argc, argv),
103 capela 3555 m_pQtTranslator(nullptr), m_pMyTranslator(nullptr), m_pWidget(nullptr)
104 capela 2074 {
105 capela 3558 #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
106     QApplication::setApplicationName(QSAMPLER_TITLE);
107 capela 3560 QApplication::setApplicationDisplayName(QSAMPLER_TITLE);
108     // QSAMPLER_TITLE " - " + QObject::tr(QSAMPLER_SUBTITLE));
109 capela 3558 #endif
110 capela 3493 // Load translation support.
111     QLocale loc;
112     if (loc.language() != QLocale::C) {
113     // Try own Qt translation...
114     m_pQtTranslator = new QTranslator(this);
115     QString sLocName = "qt_" + loc.name();
116 capela 3823 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
117     QString sLocPath = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
118     #else
119 capela 3493 QString sLocPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
120 capela 3823 #endif
121 capela 3493 if (m_pQtTranslator->load(sLocName, sLocPath)) {
122     QApplication::installTranslator(m_pQtTranslator);
123     } else {
124     #ifdef RELATIVE_LOCALE_DIR
125     sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR;
126 capela 2074 if (m_pQtTranslator->load(sLocName, sLocPath)) {
127     QApplication::installTranslator(m_pQtTranslator);
128     } else {
129 capela 3493 #endif
130     delete m_pQtTranslator;
131 capela 3835 m_pQtTranslator = nullptr;
132 capela 3493 #ifdef CONFIG_DEBUG
133     qWarning("Warning: no translation found for '%s' locale: %s/%s.qm",
134     loc.name().toUtf8().constData(),
135     sLocPath.toUtf8().constData(),
136     sLocName.toUtf8().constData());
137     #endif
138     #ifdef RELATIVE_LOCALE_DIR
139     }
140     #endif
141     }
142     // Try own application translation...
143     m_pMyTranslator = new QTranslator(this);
144     sLocName = "qsampler_" + loc.name();
145     if (m_pMyTranslator->load(sLocName, sLocPath)) {
146     QApplication::installTranslator(m_pMyTranslator);
147     } else {
148     #ifdef RELATIVE_LOCALE_DIR
149     sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR;
150     #else
151     sLocPath = CONFIG_DATADIR "/qsampler/translations";
152     #endif
153     if (m_pMyTranslator->load(sLocName, sLocPath)) {
154     QApplication::installTranslator(m_pMyTranslator);
155     } else {
156     delete m_pMyTranslator;
157 capela 3835 m_pMyTranslator = nullptr;
158 capela 2631 #ifdef CONFIG_DEBUG
159 capela 2074 qWarning("Warning: no translation found for '%s' locale: %s/%s.qm",
160     loc.name().toUtf8().constData(),
161     sLocPath.toUtf8().constData(),
162     sLocName.toUtf8().constData());
163 capela 2631 #endif
164 capela 2074 }
165     }
166     }
167 capela 3496 #ifdef CONFIG_XUNIQUE
168 capela 3520 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
169 capela 3493 #ifdef CONFIG_X11
170 capela 3555 m_pDisplay = nullptr;
171 capela 3493 m_aUnique = 0;
172     m_wOwner = 0;
173 capela 3496 #endif // CONFIG_X11
174     #else
175 capela 3555 m_pMemory = nullptr;
176     m_pServer = nullptr;
177 capela 3493 #endif
178     #endif // CONFIG_XUNIQUE
179     }
180 capela 2074
181    
182 capela 3493 // Destructor.
183     qsamplerApplication::~qsamplerApplication (void)
184     {
185     #ifdef CONFIG_XUNIQUE
186 capela 3520 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
187 capela 3496 if (m_pServer) {
188     m_pServer->close();
189     delete m_pServer;
190 capela 3555 m_pServer = nullptr;
191 capela 3496 }
192     if (m_pMemory) {
193     delete m_pMemory;
194 capela 3555 m_pMemory = nullptr;
195 capela 3496 }
196 capela 3493 #endif
197     #endif // CONFIG_XUNIQUE
198     if (m_pMyTranslator) delete m_pMyTranslator;
199     if (m_pQtTranslator) delete m_pQtTranslator;
200     }
201    
202    
203     // Main application widget accessors.
204     void qsamplerApplication::setMainWidget ( QWidget *pWidget )
205     {
206     m_pWidget = pWidget;
207 capela 3496 #ifdef CONFIG_XUNIQUE
208 capela 3520 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
209 capela 3493 #ifdef CONFIG_X11
210     m_wOwner = m_pWidget->winId();
211     if (m_pDisplay && m_wOwner) {
212     XGrabServer(m_pDisplay);
213     XSetSelectionOwner(m_pDisplay, m_aUnique, m_wOwner, CurrentTime);
214     XUngrabServer(m_pDisplay);
215 capela 2074 }
216 capela 3496 #endif // CONFIG_X11
217     #endif
218 capela 3493 #endif // CONFIG_XUNIQUE
219     }
220 capela 2074
221    
222 capela 3493 // Check if another instance is running,
223     // and raise its proper main widget...
224     bool qsamplerApplication::setup (void)
225     {
226 capela 3496 #ifdef CONFIG_XUNIQUE
227 capela 3520 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
228 capela 3493 #ifdef CONFIG_X11
229     m_pDisplay = QX11Info::display();
230     if (m_pDisplay) {
231     QString sUnique = QSAMPLER_XUNIQUE;
232     char szHostName[255];
233     if (::gethostname(szHostName, sizeof(szHostName)) == 0) {
234     sUnique += '@';
235     sUnique += szHostName;
236     }
237     m_aUnique = XInternAtom(m_pDisplay, sUnique.toUtf8().constData(), false);
238     XGrabServer(m_pDisplay);
239     m_wOwner = XGetSelectionOwner(m_pDisplay, m_aUnique);
240     XUngrabServer(m_pDisplay);
241     if (m_wOwner != None) {
242 capela 2074 // First, notify any freedesktop.org WM
243     // that we're about to show the main widget...
244     Screen *pScreen = XDefaultScreenOfDisplay(m_pDisplay);
245     int iScreen = XScreenNumberOfScreen(pScreen);
246     XEvent ev;
247     memset(&ev, 0, sizeof(ev));
248     ev.xclient.type = ClientMessage;
249     ev.xclient.display = m_pDisplay;
250     ev.xclient.window = m_wOwner;
251     ev.xclient.message_type = XInternAtom(m_pDisplay, "_NET_ACTIVE_WINDOW", false);
252     ev.xclient.format = 32;
253     ev.xclient.data.l[0] = 0; // Source indication.
254     ev.xclient.data.l[1] = 0; // Timestamp.
255     ev.xclient.data.l[2] = 0; // Requestor's currently active window (none)
256     ev.xclient.data.l[3] = 0;
257     ev.xclient.data.l[4] = 0;
258     XSelectInput(m_pDisplay, m_wOwner, StructureNotifyMask);
259     XSendEvent(m_pDisplay, RootWindow(m_pDisplay, iScreen), false,
260     (SubstructureNotifyMask | SubstructureRedirectMask), &ev);
261     XSync(m_pDisplay, false);
262     XRaiseWindow(m_pDisplay, m_wOwner);
263     // And then, let it get caught on destination
264 capela 2839 // by QApplication::native/x11EventFilter...
265     const QByteArray value = QSAMPLER_XUNIQUE;
266 capela 2074 XChangeProperty(
267     m_pDisplay,
268     m_wOwner,
269     m_aUnique,
270     m_aUnique, 8,
271     PropModeReplace,
272     (unsigned char *) value.data(),
273     value.length());
274     // Done.
275     return true;
276     }
277     }
278 capela 2839 #endif // CONFIG_X11
279 capela 3493 return false;
280 capela 3496 #else
281     m_sUnique = QCoreApplication::applicationName();
282     m_sUnique += '@';
283     m_sUnique += QHostInfo::localHostName();
284     #ifdef Q_OS_UNIX
285     m_pMemory = new QSharedMemory(m_sUnique);
286     m_pMemory->attach();
287     delete m_pMemory;
288     #endif
289     m_pMemory = new QSharedMemory(m_sUnique);
290     bool bServer = false;
291     const qint64 pid = QCoreApplication::applicationPid();
292     struct Data { qint64 pid; };
293     if (m_pMemory->create(sizeof(Data))) {
294     m_pMemory->lock();
295     Data *pData = static_cast<Data *> (m_pMemory->data());
296     if (pData) {
297     pData->pid = pid;
298     bServer = true;
299     }
300     m_pMemory->unlock();
301     }
302     else
303     if (m_pMemory->attach()) {
304     m_pMemory->lock(); // maybe not necessary?
305     Data *pData = static_cast<Data *> (m_pMemory->data());
306     if (pData)
307     bServer = (pData->pid == pid);
308     m_pMemory->unlock();
309     }
310     if (bServer) {
311     QLocalServer::removeServer(m_sUnique);
312     m_pServer = new QLocalServer();
313     m_pServer->setSocketOptions(QLocalServer::UserAccessOption);
314     m_pServer->listen(m_sUnique);
315     QObject::connect(m_pServer,
316     SIGNAL(newConnection()),
317     SLOT(newConnectionSlot()));
318     } else {
319     QLocalSocket socket;
320     socket.connectToServer(m_sUnique);
321     if (socket.state() == QLocalSocket::ConnectingState)
322     socket.waitForConnected(200);
323     if (socket.state() == QLocalSocket::ConnectedState) {
324     socket.write(QCoreApplication::arguments().join(' ').toUtf8());
325     socket.flush();
326     socket.waitForBytesWritten(200);
327     }
328     }
329     return !bServer;
330     #endif
331     #else
332     return false;
333     #endif // !CONFIG_XUNIQUE
334 capela 3493 }
335 capela 2074
336    
337 capela 3496 #ifdef CONFIG_XUNIQUE
338 capela 3520 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
339 capela 2839 #ifdef CONFIG_X11
340 capela 3496
341 capela 3493 void qsamplerApplication::x11PropertyNotify ( Window w )
342     {
343     if (m_pDisplay && m_pWidget && m_wOwner == w) {
344     // Always check whether our property-flag is still around...
345     Atom aType;
346     int iFormat = 0;
347     unsigned long iItems = 0;
348     unsigned long iAfter = 0;
349     unsigned char *pData = 0;
350     if (XGetWindowProperty(
351     m_pDisplay,
352     m_wOwner,
353     m_aUnique,
354     0, 1024,
355     false,
356     m_aUnique,
357     &aType,
358     &iFormat,
359     &iItems,
360     &iAfter,
361     &pData) == Success
362     && aType == m_aUnique && iItems > 0 && iAfter == 0) {
363     // Avoid repeating it-self...
364     XDeleteProperty(m_pDisplay, m_wOwner, m_aUnique);
365     // Just make it always shows up fine...
366     m_pWidget->show();
367     m_pWidget->raise();
368     m_pWidget->activateWindow();
369     }
370     // Free any left-overs...
371     if (iItems > 0 && pData)
372     XFree(pData);
373     }
374     }
375 capela 2074
376    
377 capela 3493 bool qsamplerApplication::x11EventFilter ( XEvent *pEv )
378 capela 2839 {
379 capela 3493 if (pEv->type == PropertyNotify
380     && pEv->xproperty.state == PropertyNewValue)
381     x11PropertyNotify(pEv->xproperty.window);
382     return QApplication::x11EventFilter(pEv);
383 capela 2839 }
384 capela 3493
385 capela 2839 #endif // CONFIG_X11
386 capela 3496 #else
387 capela 2839
388 capela 3496 // Local server conection slot.
389     void qsamplerApplication::newConnectionSlot (void)
390     {
391     QLocalSocket *pSocket = m_pServer->nextPendingConnection();
392     QObject::connect(pSocket,
393     SIGNAL(readyRead()),
394     SLOT(readyReadSlot()));
395     }
396 capela 2839
397 capela 3496 // Local server data-ready slot.
398     void qsamplerApplication::readyReadSlot (void)
399     {
400     QLocalSocket *pSocket = qobject_cast<QLocalSocket *> (sender());
401     if (pSocket) {
402     const qint64 nread = pSocket->bytesAvailable();
403     if (nread > 0) {
404 capela 3556 const QByteArray data = pSocket->read(nread);
405 capela 3496 // Just make it always shows up fine...
406     m_pWidget->hide();
407     m_pWidget->show();
408     m_pWidget->raise();
409     m_pWidget->activateWindow();
410     }
411     }
412     }
413    
414     #endif
415     #endif // CONFIG_XUNIQUE
416    
417    
418 capela 2074 //-------------------------------------------------------------------------
419     // stacktrace - Signal crash handler.
420     //
421    
422     #ifdef CONFIG_STACKTRACE
423     #if defined(__GNUC__) && defined(Q_OS_LINUX)
424    
425     #include <stdio.h>
426     #include <errno.h>
427     #include <signal.h>
428 capela 2341 #include <unistd.h>
429 capela 2074 #include <sys/wait.h>
430    
431     void stacktrace ( int signo )
432     {
433     pid_t pid;
434     int rc;
435     int status = 0;
436     char cmd[80];
437    
438     // Reinstall default handler; prevent race conditions...
439 capela 3508 ::signal(signo, SIG_DFL);
440 capela 2074
441     static const char *shell = "/bin/sh";
442 capela 2181 static const char *format = "gdb -q --batch --pid=%d"
443     " --eval-command='thread apply all bt'";
444 capela 2074
445     snprintf(cmd, sizeof(cmd), format, (int) getpid());
446    
447     pid = fork();
448    
449     // Fork failure!
450     if (pid < 0)
451     return;
452    
453     // Fork child...
454     if (pid == 0) {
455 capela 3555 execl(shell, shell, "-c", cmd, nullptr);
456 capela 2074 _exit(1);
457     return;
458     }
459    
460     // Parent here: wait for child to terminate...
461     do { rc = waitpid(pid, &status, 0); }
462     while ((rc < 0) && (errno == EINTR));
463    
464     // Dispatch any logging, if any...
465     QApplication::processEvents(QEventLoop::AllEvents, 3000);
466    
467     // Make sure everyone terminates...
468     kill(pid, SIGTERM);
469     _exit(1);
470     }
471    
472     #endif
473     #endif
474    
475    
476     //-------------------------------------------------------------------------
477     // main - The main program trunk.
478     //
479    
480     int main ( int argc, char **argv )
481     {
482     Q_INIT_RESOURCE(qsampler);
483     #ifdef CONFIG_STACKTRACE
484     #if defined(__GNUC__) && defined(Q_OS_LINUX)
485 capela 3508 ::signal(SIGILL, stacktrace);
486     ::signal(SIGFPE, stacktrace);
487     ::signal(SIGSEGV, stacktrace);
488     ::signal(SIGABRT, stacktrace);
489     ::signal(SIGBUS, stacktrace);
490 capela 2074 #endif
491     #endif
492 capela 3911 #if defined(Q_OS_LINUX)
493 capela 3910 ::setenv("QT_QPA_PLATFORM", "xcb", 0);
494 capela 3911 #endif
495 capela 3520 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
496 capela 3823 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
497 capela 3558 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
498 capela 3465 #endif
499 capela 3823 #endif
500 capela 3558 qsamplerApplication app(argc, argv);
501    
502 capela 2074 #if defined(__APPLE__) // Toshi Nagata 20080105
503     {
504     // Set the plugin path to @exetutable_path/../plugins
505     QDir dir(QApplication::applicationDirPath());
506     dir.cdUp(); // "Contents" directory
507     QApplication::setLibraryPaths(QStringList(dir.absolutePath() + "/plugins"));
508    
509     // Set the PATH environment variable to include @executable_path/../../..
510     dir.cdUp();
511     dir.cdUp();
512     QString path(getenv("PATH"));
513     path = dir.absolutePath() + ":" + path;
514     setenv("PATH", path.toUtf8().constData(), 1);
515     }
516     #endif
517    
518     // Construct default settings; override with command line arguments.
519     QSampler::Options options;
520     if (!options.parse_args(app.arguments())) {
521     app.quit();
522     return 1;
523     }
524    
525     // Have another instance running?
526     if (app.setup()) {
527     app.quit();
528     return 2;
529     }
530    
531 capela 3648 // Special custom styles...
532     if (QDir(CONFIG_PLUGINSDIR).exists())
533     app.addLibraryPath(CONFIG_PLUGINSDIR);
534     if (!options.sCustomStyleTheme.isEmpty())
535     app.setStyle(QStyleFactory::create(options.sCustomStyleTheme));
536    
537     // Custom color theme (eg. "KXStudio")...
538 capela 2074 QPalette pal(app.palette());
539 capela 3648 if (QSampler::PaletteForm::namedPalette(
540     &options.settings(), options.sCustomColorTheme, pal))
541 capela 2074 app.setPalette(pal);
542    
543     // Set default base font...
544     if (options.iBaseFontSize > 0)
545 capela 2677 app.setFont(QFont(app.font().family(), options.iBaseFontSize));
546 capela 2074
547     // Construct, setup and show the main form.
548     QSampler::MainForm w;
549     w.setup(&options);
550     w.show();
551    
552     // Settle this one as application main widget...
553     app.setMainWidget(&w);
554    
555     // Register the quit signal/slot.
556     // app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
557    
558     return app.exec();
559     }
560    
561    
562     // end of qsampler.cpp
563 capela 3065

  ViewVC Help
Powered by ViewVC