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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC