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

Annotation of /qsampler/trunk/src/qsampler.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3508 - (hide annotations) (download)
Mon Apr 1 22:36:26 2019 UTC (10 months, 3 weeks ago) by capela
File size: 14224 byte(s)
- Re-defined all main application UNIX signal handling.
  (EXPERIMENTAL)
1 capela 2074 // qsampler.cpp
2     //
3     /****************************************************************************
4 capela 3465 Copyright (C) 2004-2019, rncbc aka Rui Nuno Capela. All rights reserved.
5 capela 3065 Copyright (C) 2007,2008,2015 Christian Schoenebeck
6 capela 2074
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 capela 3493 #include "qsampler.h"
24    
25 capela 2074 #include "qsamplerOptions.h"
26     #include "qsamplerMainForm.h"
27    
28     #include <QLibraryInfo>
29     #include <QTranslator>
30     #include <QLocale>
31 capela 2459
32 capela 2074 #if defined(__APPLE__) // Toshi Nagata 20080105
33     #include <QDir>
34     #endif
35    
36 capela 2998 #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 capela 3358 #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
45 persson 2210 #define RELATIVE_LOCALE_DIR "/share/locale"
46     #elif defined(__APPLE__)
47     #define RELATIVE_LOCALE_DIR "/../Resources"
48     #endif
49 capela 2074
50 persson 2210
51 capela 2074 //-------------------------------------------------------------------------
52     // Singleton application instance stuff (Qt/X11 only atm.)
53     //
54    
55 capela 2839 #ifdef CONFIG_XUNIQUE
56    
57 capela 3496 #define QSAMPLER_XUNIQUE "qsamplerApplication"
58    
59     #if QT_VERSION < 0x050000
60     #ifdef CONFIG_X11
61    
62 capela 3493 #include <unistd.h> /* for gethostname() */
63 capela 2074
64     #include <X11/Xatom.h>
65     #include <X11/Xlib.h>
66    
67 capela 3496 #endif // CONFIG_X11
68     #else
69     #include <QSharedMemory>
70     #include <QLocalServer>
71     #include <QLocalSocket>
72     #include <QHostInfo>
73 capela 2074 #endif
74    
75 capela 2839 #endif // CONFIG_XUNIQUE
76    
77    
78 capela 3493 // Constructor.
79     qsamplerApplication::qsamplerApplication ( int& argc, char **argv )
80     : QApplication(argc, argv),
81     m_pQtTranslator(NULL), m_pMyTranslator(NULL), m_pWidget(NULL)
82 capela 2074 {
83 capela 3493 // 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 capela 2074 if (m_pQtTranslator->load(sLocName, sLocPath)) {
96     QApplication::installTranslator(m_pQtTranslator);
97     } else {
98 capela 3493 #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 capela 2631 #ifdef CONFIG_DEBUG
128 capela 2074 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 capela 2631 #endif
133 capela 2074 }
134     }
135     }
136 capela 3496 #ifdef CONFIG_XUNIQUE
137     #if QT_VERSION < 0x050000
138 capela 3493 #ifdef CONFIG_X11
139     m_pDisplay = NULL;
140     m_aUnique = 0;
141     m_wOwner = 0;
142 capela 3496 #endif // CONFIG_X11
143     #else
144     m_pMemory = NULL;
145     m_pServer = NULL;
146 capela 3493 #endif
147     #endif // CONFIG_XUNIQUE
148     }
149 capela 2074
150    
151 capela 3493 // Destructor.
152     qsamplerApplication::~qsamplerApplication (void)
153     {
154     #ifdef CONFIG_XUNIQUE
155 capela 3496 #if QT_VERSION >= 0x050000
156     if (m_pServer) {
157     m_pServer->close();
158     delete m_pServer;
159     m_pServer = NULL;
160     }
161     if (m_pMemory) {
162     delete m_pMemory;
163     m_pMemory = NULL;
164     }
165 capela 3493 #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 capela 3496 #ifdef CONFIG_XUNIQUE
177     #if QT_VERSION < 0x050000
178 capela 3493 #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 capela 2074 }
185 capela 3496 #endif // CONFIG_X11
186     #endif
187 capela 3493 #endif // CONFIG_XUNIQUE
188     }
189 capela 2074
190    
191 capela 3493 // Check if another instance is running,
192     // and raise its proper main widget...
193     bool qsamplerApplication::setup (void)
194     {
195 capela 3496 #ifdef CONFIG_XUNIQUE
196     #if QT_VERSION < 0x050000
197 capela 3493 #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 capela 2074 // 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 capela 2839 // by QApplication::native/x11EventFilter...
234     const QByteArray value = QSAMPLER_XUNIQUE;
235 capela 2074 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 capela 2839 #endif // CONFIG_X11
248 capela 3493 return false;
249 capela 3496 #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 capela 3493 }
304 capela 2074
305    
306 capela 3496 #ifdef CONFIG_XUNIQUE
307     #if QT_VERSION < 0x050000
308 capela 2839 #ifdef CONFIG_X11
309 capela 3496
310 capela 3493 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 capela 2074
345    
346 capela 3493 bool qsamplerApplication::x11EventFilter ( XEvent *pEv )
347 capela 2839 {
348 capela 3493 if (pEv->type == PropertyNotify
349     && pEv->xproperty.state == PropertyNewValue)
350     x11PropertyNotify(pEv->xproperty.window);
351     return QApplication::x11EventFilter(pEv);
352 capela 2839 }
353 capela 3493
354 capela 2839 #endif // CONFIG_X11
355 capela 3496 #else
356 capela 2839
357 capela 3496 // 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 capela 2839
366 capela 3496 // 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 capela 2074 //-------------------------------------------------------------------------
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 capela 2341 #include <unistd.h>
398 capela 2074 #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 capela 3508 ::signal(signo, SIG_DFL);
409 capela 2074
410     static const char *shell = "/bin/sh";
411 capela 2181 static const char *format = "gdb -q --batch --pid=%d"
412     " --eval-command='thread apply all bt'";
413 capela 2074
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, NULL);
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 capela 3508 ::signal(SIGILL, stacktrace);
455     ::signal(SIGFPE, stacktrace);
456     ::signal(SIGSEGV, stacktrace);
457     ::signal(SIGABRT, stacktrace);
458     ::signal(SIGBUS, stacktrace);
459 capela 2074 #endif
460     #endif
461     qsamplerApplication app(argc, argv);
462 capela 3465 #if QT_VERSION >= 0x050600
463     app.setAttribute(Qt::AA_EnableHighDpiScaling);
464     #endif
465 capela 2074 #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 capela 2415 #if QT_VERSION >= 0x050000
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 capela 2074 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 capela 2677 app.setFont(QFont(app.font().family(), options.iBaseFontSize));
526 capela 2074
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 capela 3065

  ViewVC Help
Powered by ViewVC