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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC