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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC