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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC