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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3465 - (show annotations) (download)
Mon Feb 11 16:51:26 2019 UTC (6 days, 4 hours ago) by capela
File size: 13587 byte(s)
* HiDPI display screen support (Qt >= 5.6). (EXPERIMENTAL)
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 "qsamplerAbout.h"
24 #include "qsamplerOptions.h"
25 #include "qsamplerMainForm.h"
26
27 #include <QApplication>
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 #if QT_VERSION < 0x050000
56 #if defined(Q_WS_X11)
57 #define CONFIG_X11
58 #endif
59 #else
60 #if defined(QT_X11EXTRAS_LIB)
61 #define CONFIG_X11
62 #endif
63 #endif
64
65
66 #ifdef CONFIG_X11
67 #ifdef CONFIG_XUNIQUE
68
69 #include <QX11Info>
70
71 #include <X11/Xatom.h>
72 #include <X11/Xlib.h>
73
74 #define QSAMPLER_XUNIQUE "qsamplerApplication"
75
76 #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 #endif
103
104 #endif // CONFIG_XUNIQUE
105 #endif // CONFIG_X11
106
107
108 class qsamplerApplication : public QApplication
109 {
110 public:
111
112 // Constructor.
113 qsamplerApplication(int& argc, char **argv) : QApplication(argc, argv),
114 m_pQtTranslator(0), m_pMyTranslator(0), m_pWidget(0)
115 {
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 #ifdef RELATIVE_LOCALE_DIR
127 sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR;
128 if (m_pQtTranslator->load(sLocName, sLocPath)) {
129 QApplication::installTranslator(m_pQtTranslator);
130 } else {
131 #endif
132 delete m_pQtTranslator;
133 m_pQtTranslator = 0;
134 #ifdef CONFIG_DEBUG
135 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 #endif
140 #ifdef RELATIVE_LOCALE_DIR
141 }
142 #endif
143 }
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 #ifdef RELATIVE_LOCALE_DIR
151 sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR;
152 #else
153 sLocPath = CONFIG_DATADIR "/qsampler/translations";
154 #endif
155 if (m_pMyTranslator->load(sLocName, sLocPath)) {
156 QApplication::installTranslator(m_pMyTranslator);
157 } else {
158 delete m_pMyTranslator;
159 m_pMyTranslator = 0;
160 #ifdef CONFIG_DEBUG
161 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 #endif
166 }
167 }
168 }
169 #ifdef CONFIG_X11
170 #ifdef CONFIG_XUNIQUE
171 m_pDisplay = NULL;
172 m_aUnique = 0;
173 m_wOwner = 0;
174 #if QT_VERSION >= 0x050100
175 m_pXcbEventFilter = new qsamplerXcbEventFilter(this);
176 installNativeEventFilter(m_pXcbEventFilter);
177 if (QX11Info::isPlatformX11()) {
178 #endif
179 // 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 #endif // CONFIG_XUNIQUE
189 #endif // CONFIG_X11
190 }
191
192 // Destructor.
193 ~qsamplerApplication()
194 {
195 #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 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 #ifdef CONFIG_X11
212 #ifdef CONFIG_XUNIQUE
213 m_wOwner = m_pWidget->winId();
214 if (m_pDisplay && m_wOwner) {
215 XGrabServer(m_pDisplay);
216 XSetSelectionOwner(m_pDisplay, m_aUnique, m_wOwner, CurrentTime);
217 XUngrabServer(m_pDisplay);
218 }
219 #endif // CONFIG_XUNIQUE
220 #endif // CONFIG_X11
221 }
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 #ifdef CONFIG_X11
230 #ifdef CONFIG_XUNIQUE
231 if (m_pDisplay && m_wOwner != None) {
232 // 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 // by QApplication::native/x11EventFilter...
255 const QByteArray value = QSAMPLER_XUNIQUE;
256 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 #endif // CONFIG_XUNIQUE
268 #endif // CONFIG_X11
269 return false;
270 }
271
272 #ifdef CONFIG_X11
273 #ifdef CONFIG_XUNIQUE
274 void x11PropertyNotify(Window w)
275 {
276 if (m_pDisplay && m_pWidget && m_wOwner == w) {
277 // 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 }
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 return QApplication::x11EventFilter(pEv);
315 }
316 #endif
317 #endif // CONFIG_XUNIQUE
318 #endif // CONFIG_X11
319
320 private:
321
322 // Translation support.
323 QTranslator *m_pQtTranslator;
324 QTranslator *m_pMyTranslator;
325
326 // Instance variables.
327 QWidget *m_pWidget;
328
329 #ifdef CONFIG_X11
330 #ifdef CONFIG_XUNIQUE
331 Display *m_pDisplay;
332 Atom m_aUnique;
333 Window m_wOwner;
334 #if QT_VERSION >= 0x050100
335 qsamplerXcbEventFilter *m_pXcbEventFilter;
336 #endif
337 #endif // CONFIG_XUNIQUE
338 #endif // CONFIG_X11
339 };
340
341
342 #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 //-------------------------------------------------------------------------
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 #include <unistd.h>
374 #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 static const char *format = "gdb -q --batch --pid=%d"
388 " --eval-command='thread apply all bt'";
389
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 #if QT_VERSION >= 0x050600
439 app.setAttribute(Qt::AA_EnableHighDpiScaling);
440 #endif
441 #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 #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 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 app.setFont(QFont(app.font().family(), options.iBaseFontSize));
502
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

  ViewVC Help
Powered by ViewVC