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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC