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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3493 - (show annotations) (download)
Sat Mar 9 21:47:46 2019 UTC (5 years, 1 month ago) by capela
File size: 12828 byte(s)
- Refactored singleton instance class.
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 "qsampler.h"
24
25 #include "qsamplerOptions.h"
26 #include "qsamplerMainForm.h"
27
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 #ifdef CONFIG_X11
56 #ifdef CONFIG_XUNIQUE
57
58 #include <unistd.h> /* for gethostname() */
59
60 #include <X11/Xatom.h>
61 #include <X11/Xlib.h>
62
63 #define QSAMPLER_XUNIQUE "qsamplerApplication"
64
65 #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 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
93 private:
94
95 // Instance variable.
96 qsamplerApplication *m_pApp;
97 };
98
99 #endif
100
101 #endif // CONFIG_XUNIQUE
102 #endif // CONFIG_X11
103
104
105 // Constructor.
106 qsamplerApplication::qsamplerApplication ( int& argc, char **argv )
107 : QApplication(argc, argv),
108 m_pQtTranslator(NULL), m_pMyTranslator(NULL), m_pWidget(NULL)
109 {
110 // 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 if (m_pQtTranslator->load(sLocName, sLocPath)) {
123 QApplication::installTranslator(m_pQtTranslator);
124 } else {
125 #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 #ifdef CONFIG_DEBUG
155 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 #endif
160 }
161 }
162 }
163 #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
176
177 // 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 }
205 #endif // CONFIG_XUNIQUE
206 #endif // CONFIG_X11
207 }
208
209
210 // 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 // 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 // by QApplication::native/x11EventFilter...
256 const QByteArray value = QSAMPLER_XUNIQUE;
257 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 #endif // CONFIG_XUNIQUE
270 #endif // CONFIG_X11
271 return false;
272 }
273
274
275 #ifdef CONFIG_X11
276 #ifdef CONFIG_XUNIQUE
277 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
312
313 #if QT_VERSION < 0x050000
314 bool qsamplerApplication::x11EventFilter ( XEvent *pEv )
315 {
316 if (pEv->type == PropertyNotify
317 && pEv->xproperty.state == PropertyNewValue)
318 x11PropertyNotify(pEv->xproperty.window);
319 return QApplication::x11EventFilter(pEv);
320 }
321 #endif
322
323 #endif // CONFIG_XUNIQUE
324 #endif // CONFIG_X11
325
326
327 //-------------------------------------------------------------------------
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 #include <unistd.h>
338 #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 static const char *format = "gdb -q --batch --pid=%d"
352 " --eval-command='thread apply all bt'";
353
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 #if QT_VERSION >= 0x050600
403 app.setAttribute(Qt::AA_EnableHighDpiScaling);
404 #endif
405 #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 #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 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 app.setFont(QFont(app.font().family(), options.iBaseFontSize));
466
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

  ViewVC Help
Powered by ViewVC