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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC