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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC