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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3493 - (hide annotations) (download)
Sat Mar 9 21:47:46 2019 UTC (2 years, 10 months ago) by capela
File size: 12828 byte(s)
- Refactored singleton instance class.
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_X11
56     #ifdef CONFIG_XUNIQUE
57    
58 capela 3493 #include <unistd.h> /* for gethostname() */
59 capela 2074
60     #include <X11/Xatom.h>
61     #include <X11/Xlib.h>
62    
63 capela 2839 #define QSAMPLER_XUNIQUE "qsamplerApplication"
64 capela 2074
65 capela 2839 #if QT_VERSION >= 0x050100
66    
67     #include <xcb/xcb.h>
68     #include <xcb/xproto.h>
69    
70     #include <QAbstractNativeEventFilter>
71    
72     class qsamplerXcbEventFilter : public QAbstractNativeEventFilter
73     {
74     public:
75    
76     // Constructor.
77     qsamplerXcbEventFilter(qsamplerApplication *pApp)
78     : QAbstractNativeEventFilter(), m_pApp(pApp) {}
79    
80     // XCB event filter (virtual processor).
81 capela 3493 bool nativeEventFilter(const QByteArray& eventType, void *message, long *)
82     {
83     if (eventType == "xcb_generic_event_t") {
84     xcb_property_notify_event_t *pEv
85     = static_cast<xcb_property_notify_event_t *> (message);
86     if ((pEv->response_type & ~0x80) == XCB_PROPERTY_NOTIFY
87     && pEv->state == XCB_PROPERTY_NEW_VALUE)
88     m_pApp->x11PropertyNotify(pEv->window);
89     }
90     return false;
91     }
92 capela 2839
93     private:
94    
95     // Instance variable.
96     qsamplerApplication *m_pApp;
97     };
98    
99 capela 2074 #endif
100    
101 capela 2839 #endif // CONFIG_XUNIQUE
102     #endif // CONFIG_X11
103    
104    
105 capela 3493 // Constructor.
106     qsamplerApplication::qsamplerApplication ( int& argc, char **argv )
107     : QApplication(argc, argv),
108     m_pQtTranslator(NULL), m_pMyTranslator(NULL), m_pWidget(NULL)
109 capela 2074 {
110 capela 3493 // Load translation support.
111     QLocale loc;
112     if (loc.language() != QLocale::C) {
113     // Try own Qt translation...
114     m_pQtTranslator = new QTranslator(this);
115     QString sLocName = "qt_" + loc.name();
116     QString sLocPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
117     if (m_pQtTranslator->load(sLocName, sLocPath)) {
118     QApplication::installTranslator(m_pQtTranslator);
119     } else {
120     #ifdef RELATIVE_LOCALE_DIR
121     sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR;
122 capela 2074 if (m_pQtTranslator->load(sLocName, sLocPath)) {
123     QApplication::installTranslator(m_pQtTranslator);
124     } else {
125 capela 3493 #endif
126     delete m_pQtTranslator;
127     m_pQtTranslator = 0;
128     #ifdef CONFIG_DEBUG
129     qWarning("Warning: no translation found for '%s' locale: %s/%s.qm",
130     loc.name().toUtf8().constData(),
131     sLocPath.toUtf8().constData(),
132     sLocName.toUtf8().constData());
133     #endif
134     #ifdef RELATIVE_LOCALE_DIR
135     }
136     #endif
137     }
138     // Try own application translation...
139     m_pMyTranslator = new QTranslator(this);
140     sLocName = "qsampler_" + loc.name();
141     if (m_pMyTranslator->load(sLocName, sLocPath)) {
142     QApplication::installTranslator(m_pMyTranslator);
143     } else {
144     #ifdef RELATIVE_LOCALE_DIR
145     sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR;
146     #else
147     sLocPath = CONFIG_DATADIR "/qsampler/translations";
148     #endif
149     if (m_pMyTranslator->load(sLocName, sLocPath)) {
150     QApplication::installTranslator(m_pMyTranslator);
151     } else {
152     delete m_pMyTranslator;
153     m_pMyTranslator = 0;
154 capela 2631 #ifdef CONFIG_DEBUG
155 capela 2074 qWarning("Warning: no translation found for '%s' locale: %s/%s.qm",
156     loc.name().toUtf8().constData(),
157     sLocPath.toUtf8().constData(),
158     sLocName.toUtf8().constData());
159 capela 2631 #endif
160 capela 2074 }
161     }
162     }
163 capela 3493 #ifdef CONFIG_X11
164     #ifdef CONFIG_XUNIQUE
165     m_pDisplay = NULL;
166     m_aUnique = 0;
167     m_wOwner = 0;
168     #if QT_VERSION >= 0x050100
169     m_pXcbEventFilter = new qsamplerXcbEventFilter(this);
170     installNativeEventFilter(m_pXcbEventFilter);
171     #endif
172     #endif // CONFIG_XUNIQUE
173     #endif // CONFIG_X11
174     }
175 capela 2074
176    
177 capela 3493 // Destructor.
178     qsamplerApplication::~qsamplerApplication (void)
179     {
180     #ifdef CONFIG_X11
181     #ifdef CONFIG_XUNIQUE
182     #if QT_VERSION >= 0x050100
183     removeNativeEventFilter(m_pXcbEventFilter);
184     delete m_pXcbEventFilter;
185     #endif
186     #endif // CONFIG_XUNIQUE
187     #endif // CONFIG_X11
188     if (m_pMyTranslator) delete m_pMyTranslator;
189     if (m_pQtTranslator) delete m_pQtTranslator;
190     }
191    
192    
193     // Main application widget accessors.
194     void qsamplerApplication::setMainWidget ( QWidget *pWidget )
195     {
196     m_pWidget = pWidget;
197     #ifdef CONFIG_X11
198     #ifdef CONFIG_XUNIQUE
199     m_wOwner = m_pWidget->winId();
200     if (m_pDisplay && m_wOwner) {
201     XGrabServer(m_pDisplay);
202     XSetSelectionOwner(m_pDisplay, m_aUnique, m_wOwner, CurrentTime);
203     XUngrabServer(m_pDisplay);
204 capela 2074 }
205 capela 3493 #endif // CONFIG_XUNIQUE
206     #endif // CONFIG_X11
207     }
208 capela 2074
209    
210 capela 3493 // Check if another instance is running,
211     // and raise its proper main widget...
212     bool qsamplerApplication::setup (void)
213     {
214     #ifdef CONFIG_X11
215     #ifdef CONFIG_XUNIQUE
216     #if QT_VERSION >= 0x050100
217     if (!QX11Info::isPlatformX11())
218     return false;
219     #endif
220     m_pDisplay = QX11Info::display();
221     if (m_pDisplay) {
222     QString sUnique = QSAMPLER_XUNIQUE;
223     char szHostName[255];
224     if (::gethostname(szHostName, sizeof(szHostName)) == 0) {
225     sUnique += '@';
226     sUnique += szHostName;
227     }
228     m_aUnique = XInternAtom(m_pDisplay, sUnique.toUtf8().constData(), false);
229     XGrabServer(m_pDisplay);
230     m_wOwner = XGetSelectionOwner(m_pDisplay, m_aUnique);
231     XUngrabServer(m_pDisplay);
232     if (m_wOwner != None) {
233 capela 2074 // First, notify any freedesktop.org WM
234     // that we're about to show the main widget...
235     Screen *pScreen = XDefaultScreenOfDisplay(m_pDisplay);
236     int iScreen = XScreenNumberOfScreen(pScreen);
237     XEvent ev;
238     memset(&ev, 0, sizeof(ev));
239     ev.xclient.type = ClientMessage;
240     ev.xclient.display = m_pDisplay;
241     ev.xclient.window = m_wOwner;
242     ev.xclient.message_type = XInternAtom(m_pDisplay, "_NET_ACTIVE_WINDOW", false);
243     ev.xclient.format = 32;
244     ev.xclient.data.l[0] = 0; // Source indication.
245     ev.xclient.data.l[1] = 0; // Timestamp.
246     ev.xclient.data.l[2] = 0; // Requestor's currently active window (none)
247     ev.xclient.data.l[3] = 0;
248     ev.xclient.data.l[4] = 0;
249     XSelectInput(m_pDisplay, m_wOwner, StructureNotifyMask);
250     XSendEvent(m_pDisplay, RootWindow(m_pDisplay, iScreen), false,
251     (SubstructureNotifyMask | SubstructureRedirectMask), &ev);
252     XSync(m_pDisplay, false);
253     XRaiseWindow(m_pDisplay, m_wOwner);
254     // And then, let it get caught on destination
255 capela 2839 // by QApplication::native/x11EventFilter...
256     const QByteArray value = QSAMPLER_XUNIQUE;
257 capela 2074 XChangeProperty(
258     m_pDisplay,
259     m_wOwner,
260     m_aUnique,
261     m_aUnique, 8,
262     PropModeReplace,
263     (unsigned char *) value.data(),
264     value.length());
265     // Done.
266     return true;
267     }
268     }
269 capela 2839 #endif // CONFIG_XUNIQUE
270     #endif // CONFIG_X11
271 capela 3493 return false;
272     }
273 capela 2074
274    
275 capela 2839 #ifdef CONFIG_X11
276     #ifdef CONFIG_XUNIQUE
277 capela 3493 void qsamplerApplication::x11PropertyNotify ( Window w )
278     {
279     if (m_pDisplay && m_pWidget && m_wOwner == w) {
280     // Always check whether our property-flag is still around...
281     Atom aType;
282     int iFormat = 0;
283     unsigned long iItems = 0;
284     unsigned long iAfter = 0;
285     unsigned char *pData = 0;
286     if (XGetWindowProperty(
287     m_pDisplay,
288     m_wOwner,
289     m_aUnique,
290     0, 1024,
291     false,
292     m_aUnique,
293     &aType,
294     &iFormat,
295     &iItems,
296     &iAfter,
297     &pData) == Success
298     && aType == m_aUnique && iItems > 0 && iAfter == 0) {
299     // Avoid repeating it-self...
300     XDeleteProperty(m_pDisplay, m_wOwner, m_aUnique);
301     // Just make it always shows up fine...
302     m_pWidget->show();
303     m_pWidget->raise();
304     m_pWidget->activateWindow();
305     }
306     // Free any left-overs...
307     if (iItems > 0 && pData)
308     XFree(pData);
309     }
310     }
311 capela 2074
312    
313 capela 3493 #if QT_VERSION < 0x050000
314     bool qsamplerApplication::x11EventFilter ( XEvent *pEv )
315 capela 2839 {
316 capela 3493 if (pEv->type == PropertyNotify
317     && pEv->xproperty.state == PropertyNewValue)
318     x11PropertyNotify(pEv->xproperty.window);
319     return QApplication::x11EventFilter(pEv);
320 capela 2839 }
321     #endif
322 capela 3493
323 capela 2839 #endif // CONFIG_XUNIQUE
324     #endif // CONFIG_X11
325    
326    
327 capela 2074 //-------------------------------------------------------------------------
328     // stacktrace - Signal crash handler.
329     //
330    
331     #ifdef CONFIG_STACKTRACE
332     #if defined(__GNUC__) && defined(Q_OS_LINUX)
333    
334     #include <stdio.h>
335     #include <errno.h>
336     #include <signal.h>
337 capela 2341 #include <unistd.h>
338 capela 2074 #include <sys/wait.h>
339    
340     void stacktrace ( int signo )
341     {
342     pid_t pid;
343     int rc;
344     int status = 0;
345     char cmd[80];
346    
347     // Reinstall default handler; prevent race conditions...
348     signal(signo, SIG_DFL);
349    
350     static const char *shell = "/bin/sh";
351 capela 2181 static const char *format = "gdb -q --batch --pid=%d"
352     " --eval-command='thread apply all bt'";
353 capela 2074
354     snprintf(cmd, sizeof(cmd), format, (int) getpid());
355    
356     pid = fork();
357    
358     // Fork failure!
359     if (pid < 0)
360     return;
361    
362     // Fork child...
363     if (pid == 0) {
364     execl(shell, shell, "-c", cmd, NULL);
365     _exit(1);
366     return;
367     }
368    
369     // Parent here: wait for child to terminate...
370     do { rc = waitpid(pid, &status, 0); }
371     while ((rc < 0) && (errno == EINTR));
372    
373     // Dispatch any logging, if any...
374     QApplication::processEvents(QEventLoop::AllEvents, 3000);
375    
376     // Make sure everyone terminates...
377     kill(pid, SIGTERM);
378     _exit(1);
379     }
380    
381     #endif
382     #endif
383    
384    
385     //-------------------------------------------------------------------------
386     // main - The main program trunk.
387     //
388    
389     int main ( int argc, char **argv )
390     {
391     Q_INIT_RESOURCE(qsampler);
392     #ifdef CONFIG_STACKTRACE
393     #if defined(__GNUC__) && defined(Q_OS_LINUX)
394     signal(SIGILL, stacktrace);
395     signal(SIGFPE, stacktrace);
396     signal(SIGSEGV, stacktrace);
397     signal(SIGABRT, stacktrace);
398     signal(SIGBUS, stacktrace);
399     #endif
400     #endif
401     qsamplerApplication app(argc, argv);
402 capela 3465 #if QT_VERSION >= 0x050600
403     app.setAttribute(Qt::AA_EnableHighDpiScaling);
404     #endif
405 capela 2074 #if defined(__APPLE__) // Toshi Nagata 20080105
406     {
407     // Set the plugin path to @exetutable_path/../plugins
408     QDir dir(QApplication::applicationDirPath());
409     dir.cdUp(); // "Contents" directory
410     QApplication::setLibraryPaths(QStringList(dir.absolutePath() + "/plugins"));
411    
412     // Set the PATH environment variable to include @executable_path/../../..
413     dir.cdUp();
414     dir.cdUp();
415     QString path(getenv("PATH"));
416     path = dir.absolutePath() + ":" + path;
417     setenv("PATH", path.toUtf8().constData(), 1);
418     }
419     #endif
420    
421     // Construct default settings; override with command line arguments.
422     QSampler::Options options;
423     if (!options.parse_args(app.arguments())) {
424     app.quit();
425     return 1;
426     }
427    
428     // Have another instance running?
429     if (app.setup()) {
430     app.quit();
431     return 2;
432     }
433    
434     // Dark themes grayed/disabled color group fix...
435     QPalette pal(app.palette());
436     if (pal.base().color().value() < 0x7f) {
437 capela 2415 #if QT_VERSION >= 0x050000
438     const QColor& color = pal.window().color();
439     const int iGroups = int(QPalette::Active | QPalette::Inactive) + 1;
440     for (int i = 0; i < iGroups; ++i) {
441     const QPalette::ColorGroup group = QPalette::ColorGroup(i);
442     pal.setBrush(group, QPalette::Light, color.lighter(150));
443     pal.setBrush(group, QPalette::Midlight, color.lighter(120));
444     pal.setBrush(group, QPalette::Dark, color.darker(150));
445     pal.setBrush(group, QPalette::Mid, color.darker(120));
446     pal.setBrush(group, QPalette::Shadow, color.darker(200));
447     }
448     // pal.setColor(QPalette::Disabled, QPalette::ButtonText, pal.mid().color());
449     #endif
450 capela 2074 pal.setColorGroup(QPalette::Disabled,
451     pal.windowText().color().darker(),
452     pal.button(),
453     pal.light(),
454     pal.dark(),
455     pal.mid(),
456     pal.text().color().darker(),
457     pal.text().color().lighter(),
458     pal.base(),
459     pal.window());
460     app.setPalette(pal);
461     }
462    
463     // Set default base font...
464     if (options.iBaseFontSize > 0)
465 capela 2677 app.setFont(QFont(app.font().family(), options.iBaseFontSize));
466 capela 2074
467     // Construct, setup and show the main form.
468     QSampler::MainForm w;
469     w.setup(&options);
470     w.show();
471    
472     // Settle this one as application main widget...
473     app.setMainWidget(&w);
474    
475     // Register the quit signal/slot.
476     // app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
477    
478     return app.exec();
479     }
480    
481    
482     // end of qsampler.cpp
483 capela 3065

  ViewVC Help
Powered by ViewVC