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

Contents of /qsampler/trunk/src/qsampler.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3996 - (show 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 // qsampler.cpp
2 //
3 /****************************************************************************
4 Copyright (C) 2004-2021, rncbc aka Rui Nuno Capela. All rights reserved.
5 Copyright (C) 2007,2008,2015,2019 Christian Schoenebeck
6
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 #include "qsampler.h"
24
25 #include "qsamplerOptions.h"
26 #include "qsamplerMainForm.h"
27
28 #include "qsamplerPaletteForm.h"
29
30 #include <QDir>
31
32 #include <QStyleFactory>
33
34 #include <QLibraryInfo>
35 #include <QTranslator>
36 #include <QLocale>
37
38 #if defined(__APPLE__) // Toshi Nagata 20080105
39 #include <QDir>
40 #endif
41
42 #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 #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 #elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
61 #define CONFIG_PLUGINSDIR CONFIG_LIBDIR "/qt5/plugins"
62 #else
63 #define CONFIG_PLUGINSDIR CONFIG_LIBDIR "/qt6/plugins"
64 #endif
65
66 #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
67 #define RELATIVE_LOCALE_DIR "/share/locale"
68 #elif defined(__APPLE__)
69 #define RELATIVE_LOCALE_DIR "/../Resources"
70 #endif
71
72
73 //-------------------------------------------------------------------------
74 // Singleton application instance stuff (Qt/X11 only atm.)
75 //
76
77 #ifdef CONFIG_XUNIQUE
78
79 #define QSAMPLER_XUNIQUE "qsamplerApplication"
80
81 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
82 #ifdef CONFIG_X11
83
84 #include <unistd.h> /* for gethostname() */
85
86 #include <X11/Xatom.h>
87 #include <X11/Xlib.h>
88
89 #endif // CONFIG_X11
90 #else
91 #include <QSharedMemory>
92 #include <QLocalServer>
93 #include <QLocalSocket>
94 #include <QHostInfo>
95 #endif
96
97 #endif // CONFIG_XUNIQUE
98
99
100 // Constructor.
101 qsamplerApplication::qsamplerApplication ( int& argc, char **argv )
102 : QApplication(argc, argv),
103 m_pQtTranslator(nullptr), m_pMyTranslator(nullptr), m_pWidget(nullptr)
104 {
105 #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
106 QApplication::setApplicationName(QSAMPLER_TITLE);
107 QApplication::setApplicationDisplayName(QSAMPLER_TITLE);
108 // QSAMPLER_TITLE " - " + QObject::tr(QSAMPLER_SUBTITLE));
109 #endif
110 // 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 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
117 QString sLocPath = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
118 #else
119 QString sLocPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
120 #endif
121 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 if (m_pQtTranslator->load(sLocName, sLocPath)) {
127 QApplication::installTranslator(m_pQtTranslator);
128 } else {
129 #endif
130 delete m_pQtTranslator;
131 m_pQtTranslator = nullptr;
132 #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 m_pMyTranslator = nullptr;
158 #ifdef CONFIG_DEBUG
159 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 #endif
164 }
165 }
166 }
167 #ifdef CONFIG_XUNIQUE
168 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
169 #ifdef CONFIG_X11
170 m_pDisplay = nullptr;
171 m_aUnique = 0;
172 m_wOwner = 0;
173 #endif // CONFIG_X11
174 #else
175 m_pMemory = nullptr;
176 m_pServer = nullptr;
177 #endif
178 #endif // CONFIG_XUNIQUE
179 }
180
181
182 // Destructor.
183 qsamplerApplication::~qsamplerApplication (void)
184 {
185 #ifdef CONFIG_XUNIQUE
186 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
187 if (m_pServer) {
188 m_pServer->close();
189 delete m_pServer;
190 m_pServer = nullptr;
191 }
192 if (m_pMemory) {
193 delete m_pMemory;
194 m_pMemory = nullptr;
195 }
196 #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 #ifdef CONFIG_XUNIQUE
208 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
209 #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 }
216 #endif // CONFIG_X11
217 #endif
218 #endif // CONFIG_XUNIQUE
219 }
220
221
222 // Check if another instance is running,
223 // and raise its proper main widget...
224 bool qsamplerApplication::setup (void)
225 {
226 #ifdef CONFIG_XUNIQUE
227 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
228 #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 // 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 // by QApplication::native/x11EventFilter...
265 const QByteArray value = QSAMPLER_XUNIQUE;
266 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 #endif // CONFIG_X11
279 return false;
280 #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 }
335
336
337 #ifdef CONFIG_XUNIQUE
338 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
339 #ifdef CONFIG_X11
340
341 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
376
377 bool qsamplerApplication::x11EventFilter ( XEvent *pEv )
378 {
379 if (pEv->type == PropertyNotify
380 && pEv->xproperty.state == PropertyNewValue)
381 x11PropertyNotify(pEv->xproperty.window);
382 return QApplication::x11EventFilter(pEv);
383 }
384
385 #endif // CONFIG_X11
386 #else
387
388 // 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
397 // 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 const QByteArray data = pSocket->read(nread);
405 // 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 //-------------------------------------------------------------------------
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 #include <unistd.h>
429 #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 ::signal(signo, SIG_DFL);
440
441 static const char *shell = "/bin/sh";
442 static const char *format = "gdb -q --batch --pid=%d"
443 " --eval-command='thread apply all bt'";
444
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 execl(shell, shell, "-c", cmd, nullptr);
456 _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 ::signal(SIGILL, stacktrace);
486 ::signal(SIGFPE, stacktrace);
487 ::signal(SIGSEGV, stacktrace);
488 ::signal(SIGABRT, stacktrace);
489 ::signal(SIGBUS, stacktrace);
490 #endif
491 #endif
492 #if defined(Q_OS_LINUX)
493 ::setenv("QT_QPA_PLATFORM", "xcb", 0);
494 #endif
495 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
496 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
497 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
498 #endif
499 #endif
500 qsamplerApplication app(argc, argv);
501
502 #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 // 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 QPalette pal(app.palette());
539 if (QSampler::PaletteForm::namedPalette(
540 &options.settings(), options.sCustomColorTheme, pal))
541 app.setPalette(pal);
542
543 // Set default base font...
544 if (options.iBaseFontSize > 0)
545 app.setFont(QFont(app.font().family(), options.iBaseFontSize));
546
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

  ViewVC Help
Powered by ViewVC