1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtCore module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include "qcoreapplication.h" |
43 | #include "qcoreapplication_p.h" |
44 | |
45 | #include "qabstracteventdispatcher.h" |
46 | #include "qcoreevent.h" |
47 | #include "qeventloop.h" |
48 | #include "qcorecmdlineargs_p.h" |
49 | #include <qdatastream.h> |
50 | #include <qdebug.h> |
51 | #include <qdir.h> |
52 | #include <qfile.h> |
53 | #include <qfileinfo.h> |
54 | #include <qhash.h> |
55 | #include <private/qprocess_p.h> |
56 | #include <qtextcodec.h> |
57 | #include <qthread.h> |
58 | #include <qthreadpool.h> |
59 | #include <qthreadstorage.h> |
60 | #include <private/qthread_p.h> |
61 | #include <qelapsedtimer.h> |
62 | #include <qlibraryinfo.h> |
63 | #include <qvarlengtharray.h> |
64 | #include <private/qfactoryloader_p.h> |
65 | #include <private/qfunctions_p.h> |
66 | #include <private/qlocale_p.h> |
67 | #include <private/qmutexpool_p.h> |
68 | |
69 | #ifdef Q_OS_SYMBIAN |
70 | # include <exception> |
71 | # include <f32file.h> |
72 | # include <e32ldr.h> |
73 | # include "qeventdispatcher_symbian_p.h" |
74 | # include "private/qcore_symbian_p.h" |
75 | # include "private/qfilesystemengine_p.h" |
76 | # include <apacmdln.h> |
77 | #elif defined(Q_OS_UNIX) |
78 | # if defined(Q_OS_BLACKBERRY) |
79 | # include "qeventdispatcher_blackberry_p.h" |
80 | # include <process.h> |
81 | # include <unistd.h> |
82 | # else |
83 | # if !defined(QT_NO_GLIB) |
84 | # include "qeventdispatcher_glib_p.h" |
85 | # endif |
86 | # include "qeventdispatcher_unix_p.h" |
87 | # endif |
88 | #endif |
89 | |
90 | #ifdef Q_OS_WIN |
91 | # include "qeventdispatcher_win_p.h" |
92 | #endif |
93 | |
94 | #ifdef Q_OS_MAC |
95 | # include "qcore_mac_p.h" |
96 | #endif |
97 | |
98 | #include <stdlib.h> |
99 | |
100 | #ifdef Q_OS_UNIX |
101 | # include <locale.h> |
102 | #endif |
103 | |
104 | #ifdef Q_OS_VXWORKS |
105 | # include <taskLib.h> |
106 | #endif |
107 | |
108 | #ifdef Q_OS_QNX |
109 | # include <sys/neutrino.h> |
110 | # include <pthread.h> |
111 | # include <sched.h> |
112 | #endif |
113 | |
114 | QT_BEGIN_NAMESPACE |
115 | |
116 | class QMutexUnlocker |
117 | { |
118 | public: |
119 | inline explicit QMutexUnlocker(QMutex *m) |
120 | : mtx(m) |
121 | { } |
122 | inline ~QMutexUnlocker() { unlock(); } |
123 | inline void unlock() { if (mtx) mtx->unlock(); mtx = 0; } |
124 | |
125 | private: |
126 | Q_DISABLE_COPY(QMutexUnlocker) |
127 | |
128 | QMutex *mtx; |
129 | }; |
130 | |
131 | #ifdef Q_OS_SYMBIAN |
132 | static CApaCommandLine* apaCommandLine = 0; |
133 | static char *apaTail = 0; |
134 | static QVector<char *> *apaArgv = 0; |
135 | |
136 | static void qt_cleanup_apa_cmd_line() |
137 | { |
138 | delete apaCommandLine; |
139 | apaCommandLine = 0; |
140 | delete apaArgv; |
141 | apaArgv = 0; |
142 | delete apaTail; |
143 | apaTail = 0; |
144 | } |
145 | |
146 | static inline void qt_init_symbian_apa_arguments(int &argc, char **&argv) |
147 | { |
148 | // If app is launched via CApaCommandLine::StartApp(), normal arguments only contain |
149 | // application name. |
150 | if (argc == 1) { |
151 | CApaCommandLine* commandLine = QCoreApplicationPrivate::symbianCommandLine(); |
152 | if(commandLine) { |
153 | TPtrC8 apaCmdLine = commandLine->TailEnd(); |
154 | int tailLen = apaCmdLine.Length(); |
155 | if (tailLen) { |
156 | apaTail = reinterpret_cast<char *>(qMalloc(tailLen + 1)); |
157 | qMemCopy(apaTail, reinterpret_cast<const char *>(apaCmdLine.Ptr()), tailLen); |
158 | apaTail[tailLen] = '\0'; |
159 | apaArgv = new QVector<char *>(8); |
160 | // Reuse windows command line parsing |
161 | *apaArgv = qWinCmdLine<char>(apaTail, tailLen, argc); |
162 | apaArgv->insert(0, argv[0]); |
163 | argc++; |
164 | argv = apaArgv->data(); |
165 | } |
166 | } |
167 | } |
168 | } |
169 | |
170 | CApaCommandLine* QCoreApplicationPrivate::symbianCommandLine() |
171 | { |
172 | // Getting of Apa command line needs to be static as it can only be called successfully |
173 | // once per process. |
174 | if (!apaCommandLine) { |
175 | TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(apaCommandLine); |
176 | if (err == KErrNone) { |
177 | qAddPostRoutine(qt_cleanup_apa_cmd_line); |
178 | } |
179 | } |
180 | return apaCommandLine; |
181 | } |
182 | |
183 | #endif |
184 | |
185 | #if defined(Q_WS_WIN) || defined(Q_WS_MAC) |
186 | extern QString qAppFileName(); |
187 | #endif |
188 | |
189 | int QCoreApplicationPrivate::app_compile_version = 0x040000; //we don't know exactly, but it's at least 4.0.0 |
190 | #if defined(QT3_SUPPORT) |
191 | bool QCoreApplicationPrivate::useQt3Support = true; |
192 | #endif |
193 | |
194 | #if !defined(Q_OS_WIN) |
195 | #ifdef Q_OS_MAC |
196 | QString QCoreApplicationPrivate::macMenuBarName() |
197 | { |
198 | QString bundleName; |
199 | CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("CFBundleName" )); |
200 | if (string) |
201 | bundleName = QCFString::toQString(static_cast<CFStringRef>(string)); |
202 | return bundleName; |
203 | } |
204 | #endif |
205 | QString QCoreApplicationPrivate::appName() const |
206 | { |
207 | QMutexLocker locker(QMutexPool::globalInstanceGet(&applicationName)); |
208 | |
209 | if (applicationName.isNull()) { |
210 | #ifdef Q_OS_MAC |
211 | applicationName = macMenuBarName(); |
212 | #endif |
213 | if (applicationName.isEmpty() && argv[0]) { |
214 | char *p = strrchr(argv[0], '/'); |
215 | applicationName = QString::fromLocal8Bit(p ? p + 1 : argv[0]); |
216 | } |
217 | } |
218 | return applicationName; |
219 | } |
220 | #endif |
221 | |
222 | bool QCoreApplicationPrivate::checkInstance(const char *function) |
223 | { |
224 | bool b = (QCoreApplication::self != 0); |
225 | if (!b) |
226 | qWarning("QApplication::%s: Please instantiate the QApplication object first" , function); |
227 | return b; |
228 | } |
229 | |
230 | Q_GLOBAL_STATIC(QString, qmljs_debug_arguments); |
231 | |
232 | void QCoreApplicationPrivate::processCommandLineArguments() |
233 | { |
234 | int j = argc ? 1 : 0; |
235 | for (int i = 1; i < argc; ++i) { |
236 | if (argv[i] && *argv[i] != '-') { |
237 | argv[j++] = argv[i]; |
238 | continue; |
239 | } |
240 | QByteArray arg = argv[i]; |
241 | if (arg.startsWith("-qmljsdebugger=" )) { |
242 | *qmljs_debug_arguments() = QString::fromLocal8Bit(arg.right(arg.length() - 15)); |
243 | } else if (arg == "-qmljsdebugger" && i < argc - 1) { |
244 | ++i; |
245 | *qmljs_debug_arguments() = QString::fromLocal8Bit(argv[i]); |
246 | } else { |
247 | argv[j++] = argv[i]; |
248 | } |
249 | } |
250 | |
251 | if (j < argc) { |
252 | argv[j] = 0; |
253 | argc = j; |
254 | } |
255 | } |
256 | |
257 | // Support for introspection |
258 | |
259 | QSignalSpyCallbackSet Q_CORE_EXPORT qt_signal_spy_callback_set = { 0, 0, 0, 0 }; |
260 | |
261 | void qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet &callback_set) |
262 | { |
263 | qt_signal_spy_callback_set = callback_set; |
264 | } |
265 | |
266 | extern "C" void Q_CORE_EXPORT qt_startup_hook() |
267 | { |
268 | } |
269 | |
270 | typedef QList<QtCleanUpFunction> QVFuncList; |
271 | Q_GLOBAL_STATIC(QVFuncList, postRList) |
272 | |
273 | void qAddPostRoutine(QtCleanUpFunction p) |
274 | { |
275 | QVFuncList *list = postRList(); |
276 | if (!list) |
277 | return; |
278 | list->prepend(p); |
279 | } |
280 | |
281 | void qRemovePostRoutine(QtCleanUpFunction p) |
282 | { |
283 | QVFuncList *list = postRList(); |
284 | if (!list) |
285 | return; |
286 | list->removeAll(p); |
287 | } |
288 | |
289 | void Q_CORE_EXPORT qt_call_post_routines() |
290 | { |
291 | QVFuncList *list = 0; |
292 | QT_TRY { |
293 | list = postRList(); |
294 | } QT_CATCH(const std::bad_alloc &) { |
295 | // ignore - if we can't allocate a post routine list, |
296 | // there's a high probability that there's no post |
297 | // routine to be executed :) |
298 | } |
299 | if (!list) |
300 | return; |
301 | while (!list->isEmpty()) |
302 | (list->takeFirst())(); |
303 | } |
304 | |
305 | |
306 | // app starting up if false |
307 | bool QCoreApplicationPrivate::is_app_running = false; |
308 | // app closing down if true |
309 | bool QCoreApplicationPrivate::is_app_closing = false; |
310 | // initialized in qcoreapplication and in qtextstream autotest when setlocale is called. |
311 | Q_CORE_EXPORT bool qt_locale_initialized = false; |
312 | |
313 | #ifdef Q_OS_SYMBIAN |
314 | // The global QSettings needs to be cleaned where cleanup stack is available, which is not |
315 | // normally the case when global static destructors are run. |
316 | // Declare a custom QGlobalStaticDeleter for QSettings to handle that case. |
317 | template<> |
318 | class QGlobalStaticDeleter<QSettings> |
319 | { |
320 | public: |
321 | QGlobalStatic<QSettings> &globalStatic; |
322 | QGlobalStaticDeleter(QGlobalStatic<QSettings> &_globalStatic) |
323 | : globalStatic(_globalStatic) |
324 | { } |
325 | |
326 | inline ~QGlobalStaticDeleter() |
327 | { |
328 | CTrapCleanup *cleanup = CTrapCleanup::New(); |
329 | delete globalStatic.pointer; |
330 | delete cleanup; |
331 | globalStatic.pointer = 0; |
332 | globalStatic.destroyed = true; |
333 | } |
334 | }; |
335 | #endif |
336 | |
337 | /* |
338 | Create an instance of Trolltech.conf. This ensures that the settings will not |
339 | be thrown out of QSetting's cache for unused settings. |
340 | */ |
341 | Q_GLOBAL_STATIC_WITH_ARGS(QSettings, staticTrolltechConf, (QSettings::UserScope, QLatin1String("Trolltech" ))) |
342 | |
343 | QSettings *QCoreApplicationPrivate::trolltechConf() |
344 | { |
345 | return staticTrolltechConf(); |
346 | } |
347 | |
348 | Q_CORE_EXPORT uint qGlobalPostedEventsCount() |
349 | { |
350 | QThreadData *currentThreadData = QThreadData::current(); |
351 | return currentThreadData->postEventList.size() - currentThreadData->postEventList.startOffset; |
352 | } |
353 | |
354 | |
355 | void qt_set_current_thread_to_main_thread() |
356 | { |
357 | QCoreApplicationPrivate::theMainThread = QThread::currentThread(); |
358 | } |
359 | |
360 | |
361 | |
362 | QCoreApplication *QCoreApplication::self = 0; |
363 | QAbstractEventDispatcher *QCoreApplicationPrivate::eventDispatcher = 0; |
364 | uint QCoreApplicationPrivate::attribs; |
365 | |
366 | #ifdef Q_OS_UNIX |
367 | Qt::HANDLE qt_application_thread_id = 0; |
368 | #endif |
369 | |
370 | struct QCoreApplicationData { |
371 | QCoreApplicationData() { |
372 | #ifndef QT_NO_LIBRARY |
373 | app_libpaths = 0; |
374 | #endif |
375 | } |
376 | ~QCoreApplicationData() { |
377 | #ifndef QT_NO_LIBRARY |
378 | delete app_libpaths; |
379 | #endif |
380 | #ifndef QT_NO_QOBJECT |
381 | // cleanup the QAdoptedThread created for the main() thread |
382 | if (QCoreApplicationPrivate::theMainThread) { |
383 | QThreadData *data = QThreadData::get2(QCoreApplicationPrivate::theMainThread); |
384 | data->deref(); // deletes the data and the adopted thread |
385 | } |
386 | #endif |
387 | } |
388 | |
389 | #ifdef Q_OS_BLACKBERRY |
390 | //The QCoreApplicationData struct is only populated on demand, because it is rarely needed and would |
391 | //affect startup time |
392 | void loadManifest() { |
393 | static bool manifestLoadAttempt = false; |
394 | if (manifestLoadAttempt) |
395 | return; |
396 | |
397 | manifestLoadAttempt = true; |
398 | |
399 | QFile metafile(QLatin1String("app/META-INF/MANIFEST.MF" )); |
400 | if (!metafile.open(QIODevice::ReadOnly)) { |
401 | qWarning() << Q_FUNC_INFO << "Could not open application metafile for reading" ; |
402 | } else { |
403 | while (!metafile.atEnd() && (application.isEmpty() || applicationVersion.isEmpty() || orgName.isEmpty())) { |
404 | QByteArray line = metafile.readLine(); |
405 | if (line.startsWith("Application-Name:" )) |
406 | application = QString::fromUtf8(line.mid(18).trimmed()); |
407 | else if (line.startsWith("Application-Version:" )) |
408 | applicationVersion = QString::fromUtf8(line.mid(21).trimmed()); |
409 | else if (line.startsWith("Package-Author:" )) |
410 | orgName = QString::fromUtf8(line.mid(16).trimmed()); |
411 | } |
412 | metafile.close(); |
413 | } |
414 | } |
415 | #endif |
416 | |
417 | QString orgName, orgDomain, application; |
418 | QString applicationVersion; |
419 | |
420 | #ifndef QT_NO_LIBRARY |
421 | QStringList *app_libpaths; |
422 | #endif |
423 | |
424 | }; |
425 | |
426 | Q_GLOBAL_STATIC(QCoreApplicationData, coreappdata) |
427 | |
428 | QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint flags) |
429 | : QObjectPrivate(), argc(aargc), argv(aargv), application_type(0), eventFilter(0), |
430 | in_exec(false), aboutToQuitEmitted(false) |
431 | { |
432 | app_compile_version = flags & 0xffffff; |
433 | #if defined(QT3_SUPPORT) |
434 | useQt3Support = !(flags & 0x01000000); |
435 | #endif |
436 | static const char *const empty = "" ; |
437 | if (argc == 0 || argv == 0) { |
438 | argc = 0; |
439 | argv = (char **)∅ // ouch! careful with QCoreApplication::argv()! |
440 | } |
441 | QCoreApplicationPrivate::is_app_closing = false; |
442 | |
443 | #ifdef Q_OS_SYMBIAN |
444 | qt_init_symbian_apa_arguments(argc, argv); |
445 | #endif |
446 | |
447 | #ifdef Q_OS_UNIX |
448 | qt_application_thread_id = QThread::currentThreadId(); |
449 | #endif |
450 | |
451 | #ifdef Q_OS_QNX |
452 | // make the kernel attempt to emulate an instruction with a misaligned access |
453 | // if the attempt fails, it faults with a SIGBUS |
454 | int tv = -1; |
455 | ThreadCtl(_NTO_TCTL_ALIGN_FAULT, &tv); |
456 | |
457 | // without Round Robin drawn intensive apps will hog the cpu |
458 | // and make the system appear frozen |
459 | int sched_policy; |
460 | sched_param param; |
461 | if (pthread_getschedparam(0, &sched_policy, ¶m) == 0 && sched_policy != SCHED_RR) { |
462 | sched_policy = SCHED_RR; |
463 | pthread_setschedparam(0, sched_policy, ¶m); |
464 | } |
465 | #endif |
466 | |
467 | // note: this call to QThread::currentThread() may end up setting theMainThread! |
468 | if (QThread::currentThread() != theMainThread) |
469 | qWarning("WARNING: QApplication was not created in the main() thread." ); |
470 | } |
471 | |
472 | QCoreApplicationPrivate::~QCoreApplicationPrivate() |
473 | { |
474 | if (threadData) { |
475 | #ifndef QT_NO_THREAD |
476 | void *data = &threadData->tls; |
477 | QThreadStorageData::finish((void **)data); |
478 | #endif |
479 | |
480 | // need to clear the state of the mainData, just in case a new QCoreApplication comes along. |
481 | QMutexLocker locker(&threadData->postEventList.mutex); |
482 | for (int i = 0; i < threadData->postEventList.size(); ++i) { |
483 | const QPostEvent &pe = threadData->postEventList.at(i); |
484 | if (pe.event) { |
485 | --pe.receiver->d_func()->postedEvents; |
486 | pe.event->posted = false; |
487 | delete pe.event; |
488 | } |
489 | } |
490 | threadData->postEventList.clear(); |
491 | threadData->postEventList.recursion = 0; |
492 | threadData->quitNow = false; |
493 | } |
494 | } |
495 | |
496 | void QCoreApplicationPrivate::createEventDispatcher() |
497 | { |
498 | Q_Q(QCoreApplication); |
499 | #if defined(Q_OS_SYMBIAN) |
500 | eventDispatcher = new QEventDispatcherSymbian(q); |
501 | #elif defined(Q_OS_UNIX) |
502 | # if defined(Q_OS_BLACKBERRY) |
503 | eventDispatcher = new QEventDispatcherBlackberry(q); |
504 | # else |
505 | # if !defined(QT_NO_GLIB) |
506 | if (qgetenv("QT_NO_GLIB" ).isEmpty() && QEventDispatcherGlib::versionSupported()) |
507 | eventDispatcher = new QEventDispatcherGlib(q); |
508 | else |
509 | # endif |
510 | eventDispatcher = new QEventDispatcherUNIX(q); |
511 | # endif |
512 | #elif defined(Q_OS_WIN) |
513 | eventDispatcher = new QEventDispatcherWin32(q); |
514 | #else |
515 | # error "QEventDispatcher not yet ported to this platform" |
516 | #endif |
517 | } |
518 | |
519 | QThread *QCoreApplicationPrivate::theMainThread = 0; |
520 | QThread *QCoreApplicationPrivate::mainThread() |
521 | { |
522 | Q_ASSERT(theMainThread != 0); |
523 | return theMainThread; |
524 | } |
525 | |
526 | #if !defined (QT_NO_DEBUG) || defined (QT_MAC_FRAMEWORK_BUILD) |
527 | void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) |
528 | { |
529 | QThread *currentThread = QThread::currentThread(); |
530 | QThread *thr = receiver->thread(); |
531 | Q_ASSERT_X(currentThread == thr || !thr, |
532 | "QCoreApplication::sendEvent" , |
533 | QString::fromLatin1("Cannot send events to objects owned by a different thread. " |
534 | "Current thread %1. Receiver '%2' (of type '%3') was created in thread %4" ) |
535 | .arg(QString::number((quintptr) currentThread, 16)) |
536 | .arg(receiver->objectName()) |
537 | .arg(QLatin1String(receiver->metaObject()->className())) |
538 | .arg(QString::number((quintptr) thr, 16)) |
539 | .toLocal8Bit().data()); |
540 | Q_UNUSED(currentThread); |
541 | Q_UNUSED(thr); |
542 | } |
543 | #elif defined(Q_OS_SYMBIAN) && defined (QT_NO_DEBUG) |
544 | // no implementation in release builds, but keep the symbol present |
545 | void QCoreApplicationPrivate::checkReceiverThread(QObject * /* receiver */) |
546 | { |
547 | } |
548 | #endif |
549 | |
550 | void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths() |
551 | { |
552 | #if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) |
553 | QStringList *app_libpaths = coreappdata()->app_libpaths; |
554 | Q_ASSERT(app_libpaths); |
555 | # if defined(Q_OS_SYMBIAN) |
556 | QString app_location( QCoreApplication::applicationDirPath() ); |
557 | // File existence check for application's private dir requires additional '\' or |
558 | // platform security will not allow it. |
559 | if (app_location != QLibraryInfo::location(QLibraryInfo::PluginsPath) && QFile::exists(app_location + QLatin1Char('\\')) && !app_libpaths->contains(app_location)) |
560 | # else |
561 | QString app_location( QCoreApplication::applicationFilePath() ); |
562 | app_location.truncate(app_location.lastIndexOf(QLatin1Char('/'))); |
563 | app_location = QDir(app_location).canonicalPath(); |
564 | if (QFile::exists(app_location) && !app_libpaths->contains(app_location)) |
565 | # endif |
566 | app_libpaths->append(app_location); |
567 | #endif |
568 | } |
569 | |
570 | QString QCoreApplicationPrivate::qmljsDebugArguments() |
571 | { |
572 | return *qmljs_debug_arguments(); |
573 | } |
574 | |
575 | QString qAppName() |
576 | { |
577 | if (!QCoreApplicationPrivate::checkInstance("qAppName" )) |
578 | return QString(); |
579 | return QCoreApplication::instance()->d_func()->appName(); |
580 | } |
581 | |
582 | /*! |
583 | \class QCoreApplication |
584 | \brief The QCoreApplication class provides an event loop for console Qt |
585 | applications. |
586 | |
587 | This class is used by non-GUI applications to provide their event |
588 | loop. For non-GUI application that uses Qt, there should be exactly |
589 | one QCoreApplication object. For GUI applications, see |
590 | QApplication. |
591 | |
592 | QCoreApplication contains the main event loop, where all events |
593 | from the operating system (e.g., timer and network events) and |
594 | other sources are processed and dispatched. It also handles the |
595 | application's initialization and finalization, as well as |
596 | system-wide and application-wide settings. |
597 | |
598 | \section1 The Event Loop and Event Handling |
599 | |
600 | The event loop is started with a call to exec(). Long running |
601 | operations can call processEvents() to keep the application |
602 | responsive. |
603 | |
604 | In general, we recommend that you create a QCoreApplication or a |
605 | QApplication object in your \c main() function as early as |
606 | possible. exec() will not return until the event loop exits; e.g., |
607 | when quit() is called. |
608 | |
609 | Several static convenience functions are also provided. The |
610 | QCoreApplication object is available from instance(). Events can |
611 | be sent or posted using sendEvent(), postEvent(), and |
612 | sendPostedEvents(). Pending events can be removed with |
613 | removePostedEvents() or flushed with flush(). |
614 | |
615 | The class provides a quit() slot and an aboutToQuit() signal. |
616 | |
617 | \section1 Application and Library Paths |
618 | |
619 | An application has an applicationDirPath() and an |
620 | applicationFilePath(). Library paths (see QLibrary) can be retrieved |
621 | with libraryPaths() and manipulated by setLibraryPaths(), addLibraryPath(), |
622 | and removeLibraryPath(). |
623 | |
624 | \section1 Internationalization and Translations |
625 | |
626 | Translation files can be added or removed |
627 | using installTranslator() and removeTranslator(). Application |
628 | strings can be translated using translate(). The QObject::tr() |
629 | and QObject::trUtf8() functions are implemented in terms of |
630 | translate(). |
631 | |
632 | \section1 Accessing Command Line Arguments |
633 | |
634 | The command line arguments which are passed to QCoreApplication's |
635 | constructor should be accessed using the arguments() function. |
636 | Note that some arguments supplied by the user may have been |
637 | processed and removed by QCoreApplication. |
638 | |
639 | In cases where command line arguments need to be obtained using the |
640 | argv() function, you must convert them from the local string encoding |
641 | using QString::fromLocal8Bit(). |
642 | |
643 | \section1 Locale Settings |
644 | |
645 | On Unix/Linux Qt is configured to use the system locale settings by |
646 | default. This can cause a conflict when using POSIX functions, for |
647 | instance, when converting between data types such as floats and |
648 | strings, since the notation may differ between locales. To get |
649 | around this problem, call the POSIX function \c{setlocale(LC_NUMERIC,"C")} |
650 | right after initializing QApplication or QCoreApplication to reset |
651 | the locale that is used for number formatting to "C"-locale. |
652 | |
653 | \sa QApplication, QAbstractEventDispatcher, QEventLoop, |
654 | {Semaphores Example}, {Wait Conditions Example} |
655 | */ |
656 | |
657 | /*! |
658 | \fn static QCoreApplication *QCoreApplication::instance() |
659 | |
660 | Returns a pointer to the application's QCoreApplication (or |
661 | QApplication) instance. |
662 | |
663 | If no instance has been allocated, \c null is returned. |
664 | */ |
665 | |
666 | /*!\internal |
667 | */ |
668 | QCoreApplication::QCoreApplication(QCoreApplicationPrivate &p) |
669 | : QObject(p, 0) |
670 | { |
671 | init(); |
672 | // note: it is the subclasses' job to call |
673 | // QCoreApplicationPrivate::eventDispatcher->startingUp(); |
674 | } |
675 | |
676 | /*! |
677 | Flushes the platform specific event queues. |
678 | |
679 | If you are doing graphical changes inside a loop that does not |
680 | return to the event loop on asynchronous window systems like X11 |
681 | or double buffered window systems like Mac OS X, and you want to |
682 | visualize these changes immediately (e.g. Splash Screens), call |
683 | this function. |
684 | |
685 | \sa sendPostedEvents() |
686 | */ |
687 | void QCoreApplication::flush() |
688 | { |
689 | if (self && self->d_func()->eventDispatcher) |
690 | self->d_func()->eventDispatcher->flush(); |
691 | } |
692 | |
693 | /*! |
694 | Constructs a Qt kernel application. Kernel applications are |
695 | applications without a graphical user interface. These type of |
696 | applications are used at the console or as server processes. |
697 | |
698 | The \a argc and \a argv arguments are processed by the application, |
699 | and made available in a more convenient form by the arguments() |
700 | function. |
701 | |
702 | \warning The data referred to by \a argc and \a argv must stay valid |
703 | for the entire lifetime of the QCoreApplication object. In addition, |
704 | \a argc must be greater than zero and \a argv must contain at least |
705 | one valid character string. |
706 | */ |
707 | QCoreApplication::QCoreApplication(int &argc, char **argv) |
708 | : QObject(*new QCoreApplicationPrivate(argc, argv, 0x040000)) |
709 | { |
710 | init(); |
711 | QCoreApplicationPrivate::eventDispatcher->startingUp(); |
712 | #if defined(Q_OS_SYMBIAN) && !defined(QT_NO_LIBRARY) |
713 | // Refresh factoryloader, as text codecs are requested during lib path |
714 | // resolving process and won't be therefore properly loaded. |
715 | // Unknown if this is symbian specific issue. |
716 | QFactoryLoader::refreshAll(); |
717 | #endif |
718 | |
719 | #if defined(Q_OS_SYMBIAN) && !defined(QT_NO_SYSTEMLOCALE) |
720 | d_func()->symbianInit(); |
721 | #endif |
722 | } |
723 | |
724 | QCoreApplication::QCoreApplication(int &argc, char **argv, int _internal) |
725 | : QObject(*new QCoreApplicationPrivate(argc, argv, _internal)) |
726 | { |
727 | init(); |
728 | QCoreApplicationPrivate::eventDispatcher->startingUp(); |
729 | #if defined(Q_OS_SYMBIAN) |
730 | #ifndef QT_NO_LIBRARY |
731 | // Refresh factoryloader, as text codecs are requested during lib path |
732 | // resolving process and won't be therefore properly loaded. |
733 | // Unknown if this is symbian specific issue. |
734 | QFactoryLoader::refreshAll(); |
735 | #endif |
736 | #ifndef QT_NO_SYSTEMLOCALE |
737 | d_func()->symbianInit(); |
738 | #endif |
739 | #endif //Q_OS_SYMBIAN |
740 | } |
741 | |
742 | |
743 | // ### move to QCoreApplicationPrivate constructor? |
744 | void QCoreApplication::init() |
745 | { |
746 | Q_D(QCoreApplication); |
747 | |
748 | #ifdef Q_OS_UNIX |
749 | setlocale(LC_ALL, "" ); // use correct char set mapping |
750 | qt_locale_initialized = true; |
751 | #endif |
752 | |
753 | Q_ASSERT_X(!self, "QCoreApplication" , "there should be only one application object" ); |
754 | QCoreApplication::self = this; |
755 | |
756 | #ifdef Q_OS_SYMBIAN |
757 | //ensure temp and working directories exist |
758 | QFileSystemEngine::createDirectory(QFileSystemEntry(QFileSystemEngine::tempPath()), true); |
759 | QFileSystemEngine::createDirectory(QFileSystemEntry(QFileSystemEngine::currentPath()), true); |
760 | #endif |
761 | |
762 | #ifndef QT_NO_THREAD |
763 | QThread::initialize(); |
764 | #endif |
765 | |
766 | // use the event dispatcher created by the app programmer (if any) |
767 | if (!QCoreApplicationPrivate::eventDispatcher) |
768 | QCoreApplicationPrivate::eventDispatcher = d->threadData->eventDispatcher; |
769 | // otherwise we create one |
770 | if (!QCoreApplicationPrivate::eventDispatcher) |
771 | d->createEventDispatcher(); |
772 | Q_ASSERT(QCoreApplicationPrivate::eventDispatcher != 0); |
773 | |
774 | if (!QCoreApplicationPrivate::eventDispatcher->parent()) |
775 | QCoreApplicationPrivate::eventDispatcher->moveToThread(d->threadData->thread); |
776 | |
777 | d->threadData->eventDispatcher = QCoreApplicationPrivate::eventDispatcher; |
778 | |
779 | #if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) |
780 | if (!coreappdata()->app_libpaths) { |
781 | // make sure that library paths is initialized |
782 | libraryPaths(); |
783 | } else { |
784 | d->appendApplicationPathToLibraryPaths(); |
785 | } |
786 | #endif |
787 | |
788 | #if defined(Q_OS_UNIX) && !(defined(QT_NO_PROCESS)) |
789 | // Make sure the process manager thread object is created in the main |
790 | // thread. |
791 | QProcessPrivate::initializeProcessManager(); |
792 | #endif |
793 | |
794 | #ifdef QT_EVAL |
795 | extern void qt_core_eval_init(uint); |
796 | qt_core_eval_init(d->application_type); |
797 | #endif |
798 | |
799 | #if defined(Q_OS_SYMBIAN) \ |
800 | && defined(Q_CC_NOKIAX86) \ |
801 | && defined(QT_DEBUG) |
802 | /** |
803 | * Prevent the executable from being locked in the Symbian emulator. The |
804 | * code dramatically simplifies debugging on Symbian, but beyond that has |
805 | * no impact. |
806 | * |
807 | * Force the ZLazyUnloadTimer to fire and therefore unload code segments |
808 | * immediately. The code affects Symbian's file server and on the other |
809 | * hand needs only to be run once in each emulator run. |
810 | */ |
811 | { |
812 | RLoader loader; |
813 | CleanupClosePushL(loader); |
814 | User::LeaveIfError(loader.Connect()); |
815 | User::LeaveIfError(loader.CancelLazyDllUnload()); |
816 | CleanupStack::PopAndDestroy(&loader); |
817 | } |
818 | #endif |
819 | |
820 | d->processCommandLineArguments(); |
821 | |
822 | qt_startup_hook(); |
823 | } |
824 | |
825 | #if defined(Q_OS_SYMBIAN) && !defined(QT_NO_SYSTEMLOCALE) |
826 | void QCoreApplicationPrivate::symbianInit() |
827 | { |
828 | if (!environmentChangeNotifier) |
829 | environmentChangeNotifier.reset(new QEnvironmentChangeNotifier); |
830 | } |
831 | #endif |
832 | |
833 | |
834 | /*! |
835 | Destroys the QCoreApplication object. |
836 | */ |
837 | QCoreApplication::~QCoreApplication() |
838 | { |
839 | qt_call_post_routines(); |
840 | |
841 | self = 0; |
842 | QCoreApplicationPrivate::is_app_closing = true; |
843 | QCoreApplicationPrivate::is_app_running = false; |
844 | |
845 | #if !defined(QT_NO_THREAD) |
846 | #if !defined(QT_NO_CONCURRENT) |
847 | // Synchronize and stop the global thread pool threads. |
848 | QThreadPool *globalThreadPool = 0; |
849 | QT_TRY { |
850 | globalThreadPool = QThreadPool::globalInstance(); |
851 | } QT_CATCH (...) { |
852 | // swallow the exception, since destructors shouldn't throw |
853 | } |
854 | if (globalThreadPool) |
855 | globalThreadPool->waitForDone(); |
856 | #endif |
857 | QThread::cleanup(); |
858 | #endif |
859 | |
860 | d_func()->threadData->eventDispatcher = 0; |
861 | if (QCoreApplicationPrivate::eventDispatcher) |
862 | QCoreApplicationPrivate::eventDispatcher->closingDown(); |
863 | QCoreApplicationPrivate::eventDispatcher = 0; |
864 | |
865 | #ifndef QT_NO_LIBRARY |
866 | delete coreappdata()->app_libpaths; |
867 | coreappdata()->app_libpaths = 0; |
868 | #endif |
869 | } |
870 | |
871 | |
872 | /*! |
873 | Sets the attribute \a attribute if \a on is true; |
874 | otherwise clears the attribute. |
875 | |
876 | One of the attributes that can be set with this method is |
877 | Qt::AA_ImmediateWidgetCreation. It tells Qt to create toplevel |
878 | windows immediately. Normally, resources for widgets are allocated |
879 | on demand to improve efficiency and minimize resource usage. |
880 | Therefore, if it is important to minimize resource consumption, do |
881 | not set this attribute. |
882 | |
883 | \sa testAttribute() |
884 | */ |
885 | void QCoreApplication::setAttribute(Qt::ApplicationAttribute attribute, bool on) |
886 | { |
887 | if (on) |
888 | QCoreApplicationPrivate::attribs |= 1 << attribute; |
889 | else |
890 | QCoreApplicationPrivate::attribs &= ~(1 << attribute); |
891 | #ifdef Q_OS_MAC |
892 | // Turn on the no native menubar here, since we used to |
893 | // do this implicitly. We DO NOT flip it off if someone sets |
894 | // it to false. |
895 | // Ideally, we'd have magic that would be something along the lines of |
896 | // "follow MacPluginApplication" unless explicitly set. |
897 | // Considering this attribute isn't only at the beginning |
898 | // it's unlikely it will ever be a problem, but I want |
899 | // to have the behavior documented here. |
900 | if (attribute == Qt::AA_MacPluginApplication && on |
901 | && !testAttribute(Qt::AA_DontUseNativeMenuBar)) { |
902 | setAttribute(Qt::AA_DontUseNativeMenuBar, true); |
903 | } |
904 | #endif |
905 | } |
906 | |
907 | /*! |
908 | Returns true if attribute \a attribute is set; |
909 | otherwise returns false. |
910 | |
911 | \sa setAttribute() |
912 | */ |
913 | bool QCoreApplication::testAttribute(Qt::ApplicationAttribute attribute) |
914 | { |
915 | return QCoreApplicationPrivate::testAttribute(attribute); |
916 | } |
917 | |
918 | |
919 | /*! |
920 | \internal |
921 | |
922 | This function is here to make it possible for Qt extensions to |
923 | hook into event notification without subclassing QApplication |
924 | */ |
925 | bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) |
926 | { |
927 | // Make it possible for Qt Jambi and QSA to hook into events even |
928 | // though QApplication is subclassed... |
929 | bool result = false; |
930 | void *cbdata[] = { receiver, event, &result }; |
931 | if (QInternal::activateCallbacks(QInternal::EventNotifyCallback, cbdata)) { |
932 | return result; |
933 | } |
934 | |
935 | // Qt enforces the rule that events can only be sent to objects in |
936 | // the current thread, so receiver->d_func()->threadData is |
937 | // equivalent to QThreadData::current(), just without the function |
938 | // call overhead. |
939 | QObjectPrivate *d = receiver->d_func(); |
940 | QThreadData *threadData = d->threadData; |
941 | ++threadData->loopLevel; |
942 | |
943 | #ifdef QT_JAMBI_BUILD |
944 | int deleteWatch = 0; |
945 | int *oldDeleteWatch = QObjectPrivate::setDeleteWatch(d, &deleteWatch); |
946 | |
947 | bool inEvent = d->inEventHandler; |
948 | d->inEventHandler = true; |
949 | #endif |
950 | |
951 | bool returnValue; |
952 | QT_TRY { |
953 | returnValue = notify(receiver, event); |
954 | } QT_CATCH (...) { |
955 | --threadData->loopLevel; |
956 | QT_RETHROW; |
957 | } |
958 | |
959 | #ifdef QT_JAMBI_BUILD |
960 | // Restore the previous state if the object was not deleted.. |
961 | if (!deleteWatch) { |
962 | d->inEventHandler = inEvent; |
963 | } |
964 | QObjectPrivate::resetDeleteWatch(d, oldDeleteWatch, deleteWatch); |
965 | #endif |
966 | --threadData->loopLevel; |
967 | return returnValue; |
968 | } |
969 | |
970 | |
971 | /*! |
972 | Sends \a event to \a receiver: \a {receiver}->event(\a event). |
973 | Returns the value that is returned from the receiver's event |
974 | handler. Note that this function is called for all events sent to |
975 | any object in any thread. |
976 | |
977 | For certain types of events (e.g. mouse and key events), |
978 | the event will be propagated to the receiver's parent and so on up to |
979 | the top-level object if the receiver is not interested in the event |
980 | (i.e., it returns false). |
981 | |
982 | There are five different ways that events can be processed; |
983 | reimplementing this virtual function is just one of them. All five |
984 | approaches are listed below: |
985 | \list 1 |
986 | \i Reimplementing paintEvent(), mousePressEvent() and so |
987 | on. This is the commonest, easiest and least powerful way. |
988 | |
989 | \i Reimplementing this function. This is very powerful, providing |
990 | complete control; but only one subclass can be active at a time. |
991 | |
992 | \i Installing an event filter on QCoreApplication::instance(). Such |
993 | an event filter is able to process all events for all widgets, so |
994 | it's just as powerful as reimplementing notify(); furthermore, it's |
995 | possible to have more than one application-global event filter. |
996 | Global event filters even see mouse events for |
997 | \l{QWidget::isEnabled()}{disabled widgets}. Note that application |
998 | event filters are only called for objects that live in the main |
999 | thread. |
1000 | |
1001 | \i Reimplementing QObject::event() (as QWidget does). If you do |
1002 | this you get Tab key presses, and you get to see the events before |
1003 | any widget-specific event filters. |
1004 | |
1005 | \i Installing an event filter on the object. Such an event filter gets all |
1006 | the events, including Tab and Shift+Tab key press events, as long as they |
1007 | do not change the focus widget. |
1008 | \endlist |
1009 | |
1010 | \sa QObject::event(), installEventFilter() |
1011 | */ |
1012 | |
1013 | bool QCoreApplication::notify(QObject *receiver, QEvent *event) |
1014 | { |
1015 | Q_D(QCoreApplication); |
1016 | // no events are delivered after ~QCoreApplication() has started |
1017 | if (QCoreApplicationPrivate::is_app_closing) |
1018 | return true; |
1019 | |
1020 | if (receiver == 0) { // serious error |
1021 | qWarning("QCoreApplication::notify: Unexpected null receiver" ); |
1022 | return true; |
1023 | } |
1024 | |
1025 | #ifndef QT_NO_DEBUG |
1026 | d->checkReceiverThread(receiver); |
1027 | #endif |
1028 | |
1029 | return receiver->isWidgetType() ? false : d->notify_helper(receiver, event); |
1030 | } |
1031 | |
1032 | bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event) |
1033 | { |
1034 | if (receiver->d_func()->threadData == this->threadData) { |
1035 | // application event filters are only called for objects in the GUI thread |
1036 | for (int i = 0; i < eventFilters.size(); ++i) { |
1037 | register QObject *obj = eventFilters.at(i); |
1038 | if (!obj) |
1039 | continue; |
1040 | if (obj->d_func()->threadData != threadData) { |
1041 | qWarning("QCoreApplication: Application event filter cannot be in a different thread." ); |
1042 | continue; |
1043 | } |
1044 | if (obj->eventFilter(receiver, event)) |
1045 | return true; |
1046 | } |
1047 | } |
1048 | return false; |
1049 | } |
1050 | |
1051 | bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, QEvent *event) |
1052 | { |
1053 | Q_Q(QCoreApplication); |
1054 | if (receiver != q) { |
1055 | for (int i = 0; i < receiver->d_func()->eventFilters.size(); ++i) { |
1056 | register QObject *obj = receiver->d_func()->eventFilters.at(i); |
1057 | if (!obj) |
1058 | continue; |
1059 | if (obj->d_func()->threadData != receiver->d_func()->threadData) { |
1060 | qWarning("QCoreApplication: Object event filter cannot be in a different thread." ); |
1061 | continue; |
1062 | } |
1063 | if (obj->eventFilter(receiver, event)) |
1064 | return true; |
1065 | } |
1066 | } |
1067 | return false; |
1068 | } |
1069 | |
1070 | /*!\internal |
1071 | |
1072 | Helper function called by notify() |
1073 | */ |
1074 | bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event) |
1075 | { |
1076 | // send to all application event filters |
1077 | if (sendThroughApplicationEventFilters(receiver, event)) |
1078 | return true; |
1079 | // send to all receiver event filters |
1080 | if (sendThroughObjectEventFilters(receiver, event)) |
1081 | return true; |
1082 | // deliver the event |
1083 | return receiver->event(event); |
1084 | } |
1085 | |
1086 | /*! |
1087 | Returns true if an application object has not been created yet; |
1088 | otherwise returns false. |
1089 | |
1090 | \sa closingDown() |
1091 | */ |
1092 | |
1093 | bool QCoreApplication::startingUp() |
1094 | { |
1095 | return !QCoreApplicationPrivate::is_app_running; |
1096 | } |
1097 | |
1098 | /*! |
1099 | Returns true if the application objects are being destroyed; |
1100 | otherwise returns false. |
1101 | |
1102 | \sa startingUp() |
1103 | */ |
1104 | |
1105 | bool QCoreApplication::closingDown() |
1106 | { |
1107 | return QCoreApplicationPrivate::is_app_closing; |
1108 | } |
1109 | |
1110 | |
1111 | /*! |
1112 | Processes all pending events for the calling thread according to |
1113 | the specified \a flags until there are no more events to process. |
1114 | |
1115 | You can call this function occasionally when your program is busy |
1116 | performing a long operation (e.g. copying a file). |
1117 | |
1118 | In event you are running a local loop which calls this function |
1119 | continuously, without an event loop, the |
1120 | \l{QEvent::DeferredDelete}{DeferredDelete} events will |
1121 | not be processed. This can affect the behaviour of widgets, |
1122 | e.g. QToolTip, that rely on \l{QEvent::DeferredDelete}{DeferredDelete} |
1123 | events to function properly. An alternative would be to call |
1124 | \l{QCoreApplication::sendPostedEvents()}{sendPostedEvents()} from |
1125 | within that local loop. |
1126 | |
1127 | Calling this function processes events only for the calling thread. |
1128 | |
1129 | \threadsafe |
1130 | |
1131 | \sa exec(), QTimer, QEventLoop::processEvents(), flush(), sendPostedEvents() |
1132 | */ |
1133 | void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags) |
1134 | { |
1135 | QThreadData *data = QThreadData::current(); |
1136 | if (!data->eventDispatcher) |
1137 | return; |
1138 | if (flags & QEventLoop::DeferredDeletion) |
1139 | QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
1140 | data->eventDispatcher->processEvents(flags); |
1141 | } |
1142 | |
1143 | /*! |
1144 | \overload processEvents() |
1145 | |
1146 | Processes pending events for the calling thread for \a maxtime |
1147 | milliseconds or until there are no more events to process, |
1148 | whichever is shorter. |
1149 | |
1150 | You can call this function occasionally when you program is busy |
1151 | doing a long operation (e.g. copying a file). |
1152 | |
1153 | Calling this function processes events only for the calling thread. |
1154 | |
1155 | \threadsafe |
1156 | |
1157 | \sa exec(), QTimer, QEventLoop::processEvents() |
1158 | */ |
1159 | void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime) |
1160 | { |
1161 | QThreadData *data = QThreadData::current(); |
1162 | if (!data->eventDispatcher) |
1163 | return; |
1164 | QElapsedTimer start; |
1165 | start.start(); |
1166 | if (flags & QEventLoop::DeferredDeletion) |
1167 | QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
1168 | while (data->eventDispatcher->processEvents(flags & ~QEventLoop::WaitForMoreEvents)) { |
1169 | if (start.elapsed() > maxtime) |
1170 | break; |
1171 | if (flags & QEventLoop::DeferredDeletion) |
1172 | QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
1173 | } |
1174 | } |
1175 | |
1176 | /***************************************************************************** |
1177 | Main event loop wrappers |
1178 | *****************************************************************************/ |
1179 | |
1180 | /*! |
1181 | Enters the main event loop and waits until exit() is called. |
1182 | Returns the value that was set to exit() (which is 0 if exit() is |
1183 | called via quit()). |
1184 | |
1185 | It is necessary to call this function to start event handling. The |
1186 | main event loop receives events from the window system and |
1187 | dispatches these to the application widgets. |
1188 | |
1189 | To make your application perform idle processing (i.e. executing a |
1190 | special function whenever there are no pending events), use a |
1191 | QTimer with 0 timeout. More advanced idle processing schemes can |
1192 | be achieved using processEvents(). |
1193 | |
1194 | We recommend that you connect clean-up code to the |
1195 | \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in |
1196 | your application's \c{main()} function because on some platforms the |
1197 | QCoreApplication::exec() call may not return. For example, on Windows |
1198 | when the user logs off, the system terminates the process after Qt |
1199 | closes all top-level windows. Hence, there is no guarantee that the |
1200 | application will have time to exit its event loop and execute code at |
1201 | the end of the \c{main()} function after the QCoreApplication::exec() |
1202 | call. |
1203 | |
1204 | \sa quit(), exit(), processEvents(), QApplication::exec() |
1205 | */ |
1206 | int QCoreApplication::exec() |
1207 | { |
1208 | if (!QCoreApplicationPrivate::checkInstance("exec" )) |
1209 | return -1; |
1210 | |
1211 | QThreadData *threadData = self->d_func()->threadData; |
1212 | if (threadData != QThreadData::current()) { |
1213 | qWarning("%s::exec: Must be called from the main thread" , self->metaObject()->className()); |
1214 | return -1; |
1215 | } |
1216 | if (!threadData->eventLoops.isEmpty()) { |
1217 | qWarning("QCoreApplication::exec: The event loop is already running" ); |
1218 | return -1; |
1219 | } |
1220 | |
1221 | threadData->quitNow = false; |
1222 | QEventLoop eventLoop; |
1223 | self->d_func()->in_exec = true; |
1224 | self->d_func()->aboutToQuitEmitted = false; |
1225 | int returnCode = eventLoop.exec(); |
1226 | threadData->quitNow = false; |
1227 | if (self) { |
1228 | self->d_func()->in_exec = false; |
1229 | if (!self->d_func()->aboutToQuitEmitted) |
1230 | emit self->aboutToQuit(); |
1231 | self->d_func()->aboutToQuitEmitted = true; |
1232 | sendPostedEvents(0, QEvent::DeferredDelete); |
1233 | } |
1234 | |
1235 | return returnCode; |
1236 | } |
1237 | |
1238 | |
1239 | /*! |
1240 | Tells the application to exit with a return code. |
1241 | |
1242 | After this function has been called, the application leaves the |
1243 | main event loop and returns from the call to exec(). The exec() |
1244 | function returns \a returnCode. If the event loop is not running, |
1245 | this function does nothing. |
1246 | |
1247 | By convention, a \a returnCode of 0 means success, and any non-zero |
1248 | value indicates an error. |
1249 | |
1250 | Note that unlike the C library function of the same name, this |
1251 | function \e does return to the caller -- it is event processing that |
1252 | stops. |
1253 | |
1254 | \sa quit(), exec() |
1255 | */ |
1256 | void QCoreApplication::exit(int returnCode) |
1257 | { |
1258 | if (!self) |
1259 | return; |
1260 | QThreadData *data = self->d_func()->threadData; |
1261 | data->quitNow = true; |
1262 | for (int i = 0; i < data->eventLoops.size(); ++i) { |
1263 | QEventLoop *eventLoop = data->eventLoops.at(i); |
1264 | eventLoop->exit(returnCode); |
1265 | } |
1266 | } |
1267 | |
1268 | /***************************************************************************** |
1269 | QCoreApplication management of posted events |
1270 | *****************************************************************************/ |
1271 | |
1272 | /*! |
1273 | \fn bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event) |
1274 | |
1275 | Sends event \a event directly to receiver \a receiver, using the |
1276 | notify() function. Returns the value that was returned from the |
1277 | event handler. |
1278 | |
1279 | The event is \e not deleted when the event has been sent. The normal |
1280 | approach is to create the event on the stack, for example: |
1281 | |
1282 | \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 0 |
1283 | |
1284 | \sa postEvent(), notify() |
1285 | */ |
1286 | |
1287 | /*! |
1288 | Adds the event \a event, with the object \a receiver as the |
1289 | receiver of the event, to an event queue and returns immediately. |
1290 | |
1291 | The event must be allocated on the heap since the post event queue |
1292 | will take ownership of the event and delete it once it has been |
1293 | posted. It is \e {not safe} to access the event after |
1294 | it has been posted. |
1295 | |
1296 | When control returns to the main event loop, all events that are |
1297 | stored in the queue will be sent using the notify() function. |
1298 | |
1299 | Events are processed in the order posted. For more control over |
1300 | the processing order, use the postEvent() overload below, which |
1301 | takes a priority argument. This function posts all event with a |
1302 | Qt::NormalEventPriority. |
1303 | |
1304 | \threadsafe |
1305 | |
1306 | \sa sendEvent(), notify(), sendPostedEvents() |
1307 | */ |
1308 | |
1309 | void QCoreApplication::postEvent(QObject *receiver, QEvent *event) |
1310 | { |
1311 | postEvent(receiver, event, Qt::NormalEventPriority); |
1312 | } |
1313 | |
1314 | |
1315 | /*! |
1316 | \overload postEvent() |
1317 | \since 4.3 |
1318 | |
1319 | Adds the event \a event, with the object \a receiver as the |
1320 | receiver of the event, to an event queue and returns immediately. |
1321 | |
1322 | The event must be allocated on the heap since the post event queue |
1323 | will take ownership of the event and delete it once it has been |
1324 | posted. It is \e {not safe} to access the event after |
1325 | it has been posted. |
1326 | |
1327 | When control returns to the main event loop, all events that are |
1328 | stored in the queue will be sent using the notify() function. |
1329 | |
1330 | Events are sorted in descending \a priority order, i.e. events |
1331 | with a high \a priority are queued before events with a lower \a |
1332 | priority. The \a priority can be any integer value, i.e. between |
1333 | INT_MAX and INT_MIN, inclusive; see Qt::EventPriority for more |
1334 | details. Events with equal \a priority will be processed in the |
1335 | order posted. |
1336 | |
1337 | \threadsafe |
1338 | |
1339 | \sa sendEvent(), notify(), sendPostedEvents(), Qt::EventPriority |
1340 | */ |
1341 | void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority) |
1342 | { |
1343 | if (receiver == 0) { |
1344 | qWarning("QCoreApplication::postEvent: Unexpected null receiver" ); |
1345 | delete event; |
1346 | return; |
1347 | } |
1348 | |
1349 | QThreadData * volatile * pdata = &receiver->d_func()->threadData; |
1350 | QThreadData *data = *pdata; |
1351 | if (!data) { |
1352 | // posting during destruction? just delete the event to prevent a leak |
1353 | delete event; |
1354 | return; |
1355 | } |
1356 | |
1357 | // lock the post event mutex |
1358 | data->postEventList.mutex.lock(); |
1359 | |
1360 | // if object has moved to another thread, follow it |
1361 | while (data != *pdata) { |
1362 | data->postEventList.mutex.unlock(); |
1363 | |
1364 | data = *pdata; |
1365 | if (!data) { |
1366 | // posting during destruction? just delete the event to prevent a leak |
1367 | delete event; |
1368 | return; |
1369 | } |
1370 | |
1371 | data->postEventList.mutex.lock(); |
1372 | } |
1373 | |
1374 | QMutexUnlocker locker(&data->postEventList.mutex); |
1375 | |
1376 | // if this is one of the compressible events, do compression |
1377 | if (receiver->d_func()->postedEvents |
1378 | && self && self->compressEvent(event, receiver, &data->postEventList)) { |
1379 | return; |
1380 | } |
1381 | |
1382 | if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) { |
1383 | // remember the current running eventloop for DeferredDelete |
1384 | // events posted in the receiver's thread |
1385 | event->d = reinterpret_cast<QEventPrivate *>(quintptr(data->loopLevel)); |
1386 | } |
1387 | |
1388 | // delete the event on exceptions to protect against memory leaks till the event is |
1389 | // properly owned in the postEventList |
1390 | QScopedPointer<QEvent> eventDeleter(event); |
1391 | data->postEventList.addEvent(QPostEvent(receiver, event, priority)); |
1392 | eventDeleter.take(); |
1393 | event->posted = true; |
1394 | ++receiver->d_func()->postedEvents; |
1395 | data->canWait = false; |
1396 | locker.unlock(); |
1397 | |
1398 | if (data->eventDispatcher) |
1399 | data->eventDispatcher->wakeUp(); |
1400 | } |
1401 | |
1402 | /*! |
1403 | \internal |
1404 | Returns true if \a event was compressed away (possibly deleted) and should not be added to the list. |
1405 | */ |
1406 | bool QCoreApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents) |
1407 | { |
1408 | #ifdef Q_WS_WIN |
1409 | Q_ASSERT(event); |
1410 | Q_ASSERT(receiver); |
1411 | Q_ASSERT(postedEvents); |
1412 | |
1413 | // compress posted timers to this object. |
1414 | if (event->type() == QEvent::Timer && receiver->d_func()->postedEvents > 0) { |
1415 | int timerId = ((QTimerEvent *) event)->timerId(); |
1416 | for (int i=0; i<postedEvents->size(); ++i) { |
1417 | const QPostEvent &e = postedEvents->at(i); |
1418 | if (e.receiver == receiver && e.event && e.event->type() == QEvent::Timer |
1419 | && ((QTimerEvent *) e.event)->timerId() == timerId) { |
1420 | delete event; |
1421 | return true; |
1422 | } |
1423 | } |
1424 | } else |
1425 | #endif |
1426 | if ((event->type() == QEvent::DeferredDelete |
1427 | || event->type() == QEvent::Quit) |
1428 | && receiver->d_func()->postedEvents > 0) { |
1429 | for (int i = 0; i < postedEvents->size(); ++i) { |
1430 | const QPostEvent &cur = postedEvents->at(i); |
1431 | if (cur.receiver != receiver |
1432 | || cur.event == 0 |
1433 | || cur.event->type() != event->type()) |
1434 | continue; |
1435 | // found an event for this receiver |
1436 | delete event; |
1437 | return true; |
1438 | } |
1439 | } |
1440 | return false; |
1441 | } |
1442 | |
1443 | /*! |
1444 | \fn void QCoreApplication::sendPostedEvents() |
1445 | \overload sendPostedEvents() |
1446 | |
1447 | Dispatches all posted events, i.e. empties the event queue. |
1448 | */ |
1449 | |
1450 | /*! |
1451 | Immediately dispatches all events which have been previously queued |
1452 | with QCoreApplication::postEvent() and which are for the object \a receiver |
1453 | and have the event type \a event_type. |
1454 | |
1455 | Events from the window system are \e not dispatched by this |
1456 | function, but by processEvents(). |
1457 | |
1458 | If \a receiver is null, the events of \a event_type are sent for all |
1459 | objects. If \a event_type is 0, all the events are sent for \a receiver. |
1460 | |
1461 | \note This method must be called from the same thread as its QObject parameter, \a receiver. |
1462 | |
1463 | \sa flush(), postEvent() |
1464 | */ |
1465 | |
1466 | void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type) |
1467 | { |
1468 | QThreadData *data = QThreadData::current(); |
1469 | |
1470 | QCoreApplicationPrivate::sendPostedEvents(receiver, event_type, data); |
1471 | } |
1472 | |
1473 | void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type, |
1474 | QThreadData *data) |
1475 | { |
1476 | if (event_type == -1) { |
1477 | // we were called by an obsolete event dispatcher. |
1478 | event_type = 0; |
1479 | } |
1480 | |
1481 | if (receiver && receiver->d_func()->threadData != data) { |
1482 | qWarning("QCoreApplication::sendPostedEvents: Cannot send " |
1483 | "posted events for objects in another thread" ); |
1484 | return; |
1485 | } |
1486 | |
1487 | ++data->postEventList.recursion; |
1488 | |
1489 | #ifdef QT3_SUPPORT |
1490 | if (event_type == QEvent::ChildInserted) { |
1491 | if (receiver) { |
1492 | // optimize sendPostedEvents(w, QEvent::ChildInserted) calls away |
1493 | receiver->d_func()->sendPendingChildInsertedEvents(); |
1494 | --data->postEventList.recursion; |
1495 | return; |
1496 | } |
1497 | |
1498 | // ChildInserted events are sent in response to *Request |
1499 | event_type = QEvent::ChildInsertedRequest; |
1500 | } |
1501 | #endif |
1502 | |
1503 | QMutexLocker locker(&data->postEventList.mutex); |
1504 | |
1505 | // by default, we assume that the event dispatcher can go to sleep after |
1506 | // processing all events. if any new events are posted while we send |
1507 | // events, canWait will be set to false. |
1508 | data->canWait = (data->postEventList.size() == 0); |
1509 | |
1510 | if (data->postEventList.size() == 0 || (receiver && !receiver->d_func()->postedEvents)) { |
1511 | --data->postEventList.recursion; |
1512 | return; |
1513 | } |
1514 | |
1515 | data->canWait = true; |
1516 | |
1517 | // okay. here is the tricky loop. be careful about optimizing |
1518 | // this, it looks the way it does for good reasons. |
1519 | int startOffset = data->postEventList.startOffset; |
1520 | int &i = (!event_type && !receiver) ? data->postEventList.startOffset : startOffset; |
1521 | data->postEventList.insertionOffset = data->postEventList.size(); |
1522 | |
1523 | while (i < data->postEventList.size()) { |
1524 | // avoid live-lock |
1525 | if (i >= data->postEventList.insertionOffset) |
1526 | break; |
1527 | |
1528 | const QPostEvent &pe = data->postEventList.at(i); |
1529 | ++i; |
1530 | |
1531 | if (!pe.event) |
1532 | continue; |
1533 | if ((receiver && receiver != pe.receiver) || (event_type && event_type != pe.event->type())) { |
1534 | data->canWait = false; |
1535 | continue; |
1536 | } |
1537 | |
1538 | if (pe.event->type() == QEvent::DeferredDelete) { |
1539 | // DeferredDelete events are only sent when we are explicitly asked to |
1540 | // (s.a. QEvent::DeferredDelete), and then only if the event loop that |
1541 | // posted the event has returned. |
1542 | const bool allowDeferredDelete = |
1543 | (quintptr(pe.event->d) > unsigned(data->loopLevel) |
1544 | || (!quintptr(pe.event->d) && data->loopLevel > 0) |
1545 | || (event_type == QEvent::DeferredDelete |
1546 | && quintptr(pe.event->d) == unsigned(data->loopLevel))); |
1547 | if (!allowDeferredDelete) { |
1548 | // cannot send deferred delete |
1549 | if (!event_type && !receiver) { |
1550 | // don't lose the event |
1551 | data->postEventList.addEvent(pe); |
1552 | const_cast<QPostEvent &>(pe).event = 0; |
1553 | } |
1554 | continue; |
1555 | } |
1556 | } |
1557 | |
1558 | // first, we diddle the event so that we can deliver |
1559 | // it, and that no one will try to touch it later. |
1560 | pe.event->posted = false; |
1561 | QEvent * e = pe.event; |
1562 | QObject * r = pe.receiver; |
1563 | |
1564 | --r->d_func()->postedEvents; |
1565 | Q_ASSERT(r->d_func()->postedEvents >= 0); |
1566 | |
1567 | // next, update the data structure so that we're ready |
1568 | // for the next event. |
1569 | const_cast<QPostEvent &>(pe).event = 0; |
1570 | |
1571 | locker.unlock(); |
1572 | // after all that work, it's time to deliver the event. |
1573 | #ifdef QT_NO_EXCEPTIONS |
1574 | QCoreApplication::sendEvent(r, e); |
1575 | #else |
1576 | try { |
1577 | QCoreApplication::sendEvent(r, e); |
1578 | } catch (...) { |
1579 | delete e; |
1580 | locker.relock(); |
1581 | |
1582 | // since we were interrupted, we need another pass to make sure we clean everything up |
1583 | data->canWait = false; |
1584 | |
1585 | // uglehack: copied from below |
1586 | --data->postEventList.recursion; |
1587 | if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher) |
1588 | data->eventDispatcher->wakeUp(); |
1589 | throw; // rethrow |
1590 | } |
1591 | #endif |
1592 | |
1593 | delete e; |
1594 | locker.relock(); |
1595 | |
1596 | // careful when adding anything below this point - the |
1597 | // sendEvent() call might invalidate any invariants this |
1598 | // function depends on. |
1599 | } |
1600 | |
1601 | --data->postEventList.recursion; |
1602 | if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher) |
1603 | data->eventDispatcher->wakeUp(); |
1604 | |
1605 | // clear the global list, i.e. remove everything that was |
1606 | // delivered. |
1607 | if (!event_type && !receiver && data->postEventList.startOffset >= 0) { |
1608 | const QPostEventList::iterator it = data->postEventList.begin(); |
1609 | data->postEventList.erase(it, it + data->postEventList.startOffset); |
1610 | data->postEventList.insertionOffset -= data->postEventList.startOffset; |
1611 | Q_ASSERT(data->postEventList.insertionOffset >= 0); |
1612 | data->postEventList.startOffset = 0; |
1613 | } |
1614 | } |
1615 | |
1616 | /*! |
1617 | Removes all events posted using postEvent() for \a receiver. |
1618 | |
1619 | The events are \e not dispatched, instead they are removed from the |
1620 | queue. You should never need to call this function. If you do call it, |
1621 | be aware that killing events may cause \a receiver to break one or |
1622 | more invariants. |
1623 | |
1624 | \threadsafe |
1625 | */ |
1626 | |
1627 | void QCoreApplication::removePostedEvents(QObject *receiver) |
1628 | { |
1629 | removePostedEvents(receiver, 0); |
1630 | } |
1631 | |
1632 | /*! |
1633 | \overload removePostedEvents() |
1634 | \since 4.3 |
1635 | |
1636 | Removes all events of the given \a eventType that were posted |
1637 | using postEvent() for \a receiver. |
1638 | |
1639 | The events are \e not dispatched, instead they are removed from |
1640 | the queue. You should never need to call this function. If you do |
1641 | call it, be aware that killing events may cause \a receiver to |
1642 | break one or more invariants. |
1643 | |
1644 | If \a receiver is null, the events of \a eventType are removed for |
1645 | all objects. If \a eventType is 0, all the events are removed for |
1646 | \a receiver. |
1647 | |
1648 | \threadsafe |
1649 | */ |
1650 | |
1651 | void QCoreApplication::removePostedEvents(QObject *receiver, int eventType) |
1652 | { |
1653 | #ifdef QT3_SUPPORT |
1654 | if (eventType == QEvent::ChildInserted) |
1655 | eventType = QEvent::ChildInsertedRequest; |
1656 | #endif |
1657 | |
1658 | QThreadData *data = receiver ? receiver->d_func()->threadData : QThreadData::current(); |
1659 | QMutexLocker locker(&data->postEventList.mutex); |
1660 | |
1661 | // the QObject destructor calls this function directly. this can |
1662 | // happen while the event loop is in the middle of posting events, |
1663 | // and when we get here, we may not have any more posted events |
1664 | // for this object. |
1665 | if (receiver && !receiver->d_func()->postedEvents) |
1666 | return; |
1667 | |
1668 | //we will collect all the posted events for the QObject |
1669 | //and we'll delete after the mutex was unlocked |
1670 | QVarLengthArray<QEvent*> events; |
1671 | int n = data->postEventList.size(); |
1672 | int j = 0; |
1673 | |
1674 | for (int i = 0; i < n; ++i) { |
1675 | const QPostEvent &pe = data->postEventList.at(i); |
1676 | |
1677 | if ((!receiver || pe.receiver == receiver) |
1678 | && (pe.event && (eventType == 0 || pe.event->type() == eventType))) { |
1679 | --pe.receiver->d_func()->postedEvents; |
1680 | #ifdef QT3_SUPPORT |
1681 | if (pe.event->type() == QEvent::ChildInsertedRequest) |
1682 | pe.receiver->d_func()->pendingChildInsertedEvents.clear(); |
1683 | #endif |
1684 | pe.event->posted = false; |
1685 | events.append(pe.event); |
1686 | const_cast<QPostEvent &>(pe).event = 0; |
1687 | } else if (!data->postEventList.recursion) { |
1688 | if (i != j) |
1689 | data->postEventList.swap(i, j); |
1690 | ++j; |
1691 | } |
1692 | } |
1693 | |
1694 | #ifdef QT_DEBUG |
1695 | if (receiver && eventType == 0) { |
1696 | Q_ASSERT(!receiver->d_func()->postedEvents); |
1697 | } |
1698 | #endif |
1699 | |
1700 | if (!data->postEventList.recursion) { |
1701 | // truncate list |
1702 | data->postEventList.erase(data->postEventList.begin() + j, data->postEventList.end()); |
1703 | } |
1704 | |
1705 | locker.unlock(); |
1706 | for (int i = 0; i < events.count(); ++i) { |
1707 | delete events[i]; |
1708 | } |
1709 | } |
1710 | |
1711 | /*! |
1712 | Removes \a event from the queue of posted events, and emits a |
1713 | warning message if appropriate. |
1714 | |
1715 | \warning This function can be \e really slow. Avoid using it, if |
1716 | possible. |
1717 | |
1718 | \threadsafe |
1719 | */ |
1720 | |
1721 | void QCoreApplicationPrivate::removePostedEvent(QEvent * event) |
1722 | { |
1723 | if (!event || !event->posted) |
1724 | return; |
1725 | |
1726 | QThreadData *data = QThreadData::current(); |
1727 | |
1728 | QMutexLocker locker(&data->postEventList.mutex); |
1729 | |
1730 | if (data->postEventList.size() == 0) { |
1731 | #if defined(QT_DEBUG) |
1732 | qDebug("QCoreApplication::removePostedEvent: Internal error: %p %d is posted" , |
1733 | (void*)event, event->type()); |
1734 | return; |
1735 | #endif |
1736 | } |
1737 | |
1738 | for (int i = 0; i < data->postEventList.size(); ++i) { |
1739 | const QPostEvent & pe = data->postEventList.at(i); |
1740 | if (pe.event == event) { |
1741 | #ifndef QT_NO_DEBUG |
1742 | qWarning("QCoreApplication::removePostedEvent: Event of type %d deleted while posted to %s %s" , |
1743 | event->type(), |
1744 | pe.receiver->metaObject()->className(), |
1745 | pe.receiver->objectName().toLocal8Bit().data()); |
1746 | #endif |
1747 | --pe.receiver->d_func()->postedEvents; |
1748 | pe.event->posted = false; |
1749 | delete pe.event; |
1750 | const_cast<QPostEvent &>(pe).event = 0; |
1751 | return; |
1752 | } |
1753 | } |
1754 | } |
1755 | |
1756 | /*!\reimp |
1757 | |
1758 | */ |
1759 | bool QCoreApplication::event(QEvent *e) |
1760 | { |
1761 | if (e->type() == QEvent::Quit) { |
1762 | quit(); |
1763 | return true; |
1764 | } |
1765 | return QObject::event(e); |
1766 | } |
1767 | |
1768 | /*! \enum QCoreApplication::Encoding |
1769 | |
1770 | This enum type defines the 8-bit encoding of character string |
1771 | arguments to translate(): |
1772 | |
1773 | \value CodecForTr The encoding specified by |
1774 | QTextCodec::codecForTr() (Latin-1 if none has |
1775 | been set). |
1776 | \value UnicodeUTF8 UTF-8. |
1777 | \value DefaultCodec (Obsolete) Use CodecForTr instead. |
1778 | |
1779 | \sa QObject::tr(), QObject::trUtf8(), QString::fromUtf8() |
1780 | */ |
1781 | |
1782 | /*! |
1783 | Tells the application to exit with return code 0 (success). |
1784 | Equivalent to calling QCoreApplication::exit(0). |
1785 | |
1786 | It's common to connect the QApplication::lastWindowClosed() signal |
1787 | to quit(), and you also often connect e.g. QAbstractButton::clicked() or |
1788 | signals in QAction, QMenu, or QMenuBar to it. |
1789 | |
1790 | Example: |
1791 | |
1792 | \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 1 |
1793 | |
1794 | \sa exit(), aboutToQuit(), QApplication::lastWindowClosed() |
1795 | */ |
1796 | |
1797 | void QCoreApplication::quit() |
1798 | { |
1799 | exit(0); |
1800 | } |
1801 | |
1802 | /*! |
1803 | \fn void QCoreApplication::aboutToQuit() |
1804 | |
1805 | This signal is emitted when the application is about to quit the |
1806 | main event loop, e.g. when the event loop level drops to zero. |
1807 | This may happen either after a call to quit() from inside the |
1808 | application or when the users shuts down the entire desktop session. |
1809 | |
1810 | The signal is particularly useful if your application has to do some |
1811 | last-second cleanup. Note that no user interaction is possible in |
1812 | this state. |
1813 | |
1814 | \sa quit() |
1815 | */ |
1816 | |
1817 | #ifndef QT_NO_TRANSLATION |
1818 | /*! |
1819 | Adds the translation file \a translationFile to the list of |
1820 | translation files to be used for translations. |
1821 | |
1822 | Multiple translation files can be installed. Translations are |
1823 | searched for in the reverse order in which they were installed, |
1824 | so the most recently installed translation file is searched first |
1825 | and the first translation file installed is searched last. |
1826 | The search stops as soon as a translation containing a matching |
1827 | string is found. |
1828 | |
1829 | Installing or removing a QTranslator, or changing an installed QTranslator |
1830 | generates a \l{QEvent::LanguageChange}{LanguageChange} event for the |
1831 | QCoreApplication instance. A QApplication instance will propagate the event |
1832 | to all toplevel windows, where a reimplementation of changeEvent can |
1833 | re-translate the user interface by passing user-visible strings via the |
1834 | tr() function to the respective property setters. User-interface classes |
1835 | generated by \l{Qt Designer} provide a \c retranslateUi() function that can be |
1836 | called. |
1837 | |
1838 | \sa removeTranslator() translate() QTranslator::load() {Dynamic Translation} |
1839 | */ |
1840 | |
1841 | void QCoreApplication::installTranslator(QTranslator *translationFile) |
1842 | { |
1843 | if (!translationFile) |
1844 | return; |
1845 | |
1846 | if (!QCoreApplicationPrivate::checkInstance("installTranslator" )) |
1847 | return; |
1848 | QCoreApplicationPrivate *d = self->d_func(); |
1849 | d->translators.prepend(translationFile); |
1850 | |
1851 | #ifndef QT_NO_TRANSLATION_BUILDER |
1852 | if (translationFile->isEmpty()) |
1853 | return; |
1854 | #endif |
1855 | |
1856 | QEvent ev(QEvent::LanguageChange); |
1857 | QCoreApplication::sendEvent(self, &ev); |
1858 | } |
1859 | |
1860 | /*! |
1861 | Removes the translation file \a translationFile from the list of |
1862 | translation files used by this application. (It does not delete the |
1863 | translation file from the file system.) |
1864 | |
1865 | \sa installTranslator() translate(), QObject::tr() |
1866 | */ |
1867 | |
1868 | void QCoreApplication::removeTranslator(QTranslator *translationFile) |
1869 | { |
1870 | if (!translationFile) |
1871 | return; |
1872 | if (!QCoreApplicationPrivate::checkInstance("removeTranslator" )) |
1873 | return; |
1874 | QCoreApplicationPrivate *d = self->d_func(); |
1875 | if (d->translators.removeAll(translationFile) && !self->closingDown()) { |
1876 | QEvent ev(QEvent::LanguageChange); |
1877 | QCoreApplication::sendEvent(self, &ev); |
1878 | } |
1879 | } |
1880 | |
1881 | /*! |
1882 | \overload translate() |
1883 | */ |
1884 | QString QCoreApplication::translate(const char *context, const char *sourceText, |
1885 | const char *disambiguation, Encoding encoding) |
1886 | { |
1887 | return translate(context, sourceText, disambiguation, encoding, -1); |
1888 | } |
1889 | |
1890 | static void replacePercentN(QString *result, int n) |
1891 | { |
1892 | if (n >= 0) { |
1893 | int percentPos = 0; |
1894 | int len = 0; |
1895 | while ((percentPos = result->indexOf(QLatin1Char('%'), percentPos + len)) != -1) { |
1896 | len = 1; |
1897 | QString fmt; |
1898 | if (result->at(percentPos + len) == QLatin1Char('L')) { |
1899 | ++len; |
1900 | fmt = QLatin1String("%L1" ); |
1901 | } else { |
1902 | fmt = QLatin1String("%1" ); |
1903 | } |
1904 | if (result->at(percentPos + len) == QLatin1Char('n')) { |
1905 | fmt = fmt.arg(n); |
1906 | ++len; |
1907 | result->replace(percentPos, len, fmt); |
1908 | len = fmt.length(); |
1909 | } |
1910 | } |
1911 | } |
1912 | } |
1913 | |
1914 | /*! |
1915 | \reentrant |
1916 | \since 4.5 |
1917 | |
1918 | Returns the translation text for \a sourceText, by querying the |
1919 | installed translation files. The translation files are searched |
1920 | from the most recently installed file back to the first |
1921 | installed file. |
1922 | |
1923 | QObject::tr() and QObject::trUtf8() provide this functionality |
1924 | more conveniently. |
1925 | |
1926 | \a context is typically a class name (e.g., "MyDialog") and \a |
1927 | sourceText is either English text or a short identifying text. |
1928 | |
1929 | \a disambiguation is an identifying string, for when the same \a |
1930 | sourceText is used in different roles within the same context. By |
1931 | default, it is null. |
1932 | |
1933 | See the \l QTranslator and \l QObject::tr() documentation for |
1934 | more information about contexts, disambiguations and comments. |
1935 | |
1936 | \a encoding indicates the 8-bit encoding of character strings. |
1937 | |
1938 | \a n is used in conjunction with \c %n to support plural forms. |
1939 | See QObject::tr() for details. |
1940 | |
1941 | If none of the translation files contain a translation for \a |
1942 | sourceText in \a context, this function returns a QString |
1943 | equivalent of \a sourceText. The encoding of \a sourceText is |
1944 | specified by \e encoding; it defaults to CodecForTr. |
1945 | |
1946 | This function is not virtual. You can use alternative translation |
1947 | techniques by subclassing \l QTranslator. |
1948 | |
1949 | \warning This method is reentrant only if all translators are |
1950 | installed \e before calling this method. Installing or removing |
1951 | translators while performing translations is not supported. Doing |
1952 | so will most likely result in crashes or other undesirable |
1953 | behavior. |
1954 | |
1955 | \sa QObject::tr() installTranslator() QTextCodec::codecForTr() |
1956 | */ |
1957 | |
1958 | |
1959 | QString QCoreApplication::translate(const char *context, const char *sourceText, |
1960 | const char *disambiguation, Encoding encoding, int n) |
1961 | { |
1962 | QString result; |
1963 | |
1964 | if (!sourceText) |
1965 | return result; |
1966 | |
1967 | if (self && !self->d_func()->translators.isEmpty()) { |
1968 | QList<QTranslator*>::ConstIterator it; |
1969 | QTranslator *translationFile; |
1970 | for (it = self->d_func()->translators.constBegin(); it != self->d_func()->translators.constEnd(); ++it) { |
1971 | translationFile = *it; |
1972 | result = translationFile->translate(context, sourceText, disambiguation, n); |
1973 | if (!result.isEmpty()) |
1974 | break; |
1975 | } |
1976 | } |
1977 | |
1978 | if (result.isEmpty()) { |
1979 | #ifdef QT_NO_TEXTCODEC |
1980 | Q_UNUSED(encoding) |
1981 | #else |
1982 | if (encoding == UnicodeUTF8) |
1983 | result = QString::fromUtf8(sourceText); |
1984 | else if (QTextCodec::codecForTr() != 0) |
1985 | result = QTextCodec::codecForTr()->toUnicode(sourceText); |
1986 | else |
1987 | #endif |
1988 | result = QString::fromLatin1(sourceText); |
1989 | } |
1990 | |
1991 | replacePercentN(&result, n); |
1992 | return result; |
1993 | } |
1994 | |
1995 | // Declared in qglobal.h |
1996 | QString qtTrId(const char *id, int n) |
1997 | { |
1998 | return QCoreApplication::translate(0, id, 0, QCoreApplication::UnicodeUTF8, n); |
1999 | } |
2000 | |
2001 | bool QCoreApplicationPrivate::isTranslatorInstalled(QTranslator *translator) |
2002 | { |
2003 | return QCoreApplication::self |
2004 | && QCoreApplication::self->d_func()->translators.contains(translator); |
2005 | } |
2006 | |
2007 | #endif //QT_NO_TRANSLATE |
2008 | |
2009 | /*! |
2010 | Returns the directory that contains the application executable. |
2011 | |
2012 | For example, if you have installed Qt in the \c{C:\Trolltech\Qt} |
2013 | directory, and you run the \c{regexp} example, this function will |
2014 | return "C:/Trolltech/Qt/examples/tools/regexp". |
2015 | |
2016 | On Mac OS X this will point to the directory actually containing the |
2017 | executable, which may be inside of an application bundle (if the |
2018 | application is bundled). |
2019 | |
2020 | \warning On Linux, this function will try to get the path from the |
2021 | \c {/proc} file system. If that fails, it assumes that \c |
2022 | {argv[0]} contains the absolute file name of the executable. The |
2023 | function also assumes that the current directory has not been |
2024 | changed by the application. |
2025 | |
2026 | In Symbian this function will return the application private directory, |
2027 | not the path to executable itself, as those are always in \c {/sys/bin}. |
2028 | If the application is in a read only drive, i.e. ROM, then the private path |
2029 | on the system drive will be returned. |
2030 | |
2031 | \sa applicationFilePath() |
2032 | */ |
2033 | QString QCoreApplication::applicationDirPath() |
2034 | { |
2035 | if (!self) { |
2036 | qWarning("QCoreApplication::applicationDirPath: Please instantiate the QApplication object first" ); |
2037 | return QString(); |
2038 | } |
2039 | |
2040 | QCoreApplicationPrivate *d = self->d_func(); |
2041 | if (d->cachedApplicationDirPath.isNull()) |
2042 | #if defined(Q_OS_SYMBIAN) |
2043 | { |
2044 | QString appPath; |
2045 | RFs& fs = qt_s60GetRFs(); |
2046 | TChar driveChar; |
2047 | QChar qDriveChar; |
2048 | driveChar = (RProcess().FileName())[0]; |
2049 | |
2050 | //Check if the process is installed in a read only drive (typically ROM), |
2051 | //and use the system drive (typically C:) if so. |
2052 | TInt drive; |
2053 | TDriveInfo driveInfo; |
2054 | TInt err = fs.CharToDrive(driveChar, drive); |
2055 | if (err == KErrNone) { |
2056 | err = fs.Drive(driveInfo, drive); |
2057 | } |
2058 | if (err != KErrNone || (driveInfo.iDriveAtt & KDriveAttRom) || (driveInfo.iMediaAtt |
2059 | & KMediaAttWriteProtected)) { |
2060 | drive = fs.GetSystemDrive(); |
2061 | fs.DriveToChar(drive, driveChar); |
2062 | } |
2063 | |
2064 | qDriveChar = QChar(QLatin1Char(driveChar)).toUpper(); |
2065 | |
2066 | TFileName privatePath; |
2067 | fs.PrivatePath(privatePath); |
2068 | appPath = qt_TDesC2QString(privatePath); |
2069 | appPath.prepend(QLatin1Char(':')).prepend(qDriveChar); |
2070 | |
2071 | d->cachedApplicationDirPath = QFileInfo(appPath).path(); |
2072 | } |
2073 | #else |
2074 | d->cachedApplicationDirPath = QFileInfo(applicationFilePath()).path(); |
2075 | #endif |
2076 | return d->cachedApplicationDirPath; |
2077 | } |
2078 | |
2079 | /*! |
2080 | Returns the file path of the application executable. |
2081 | |
2082 | For example, if you have installed Qt in the \c{/usr/local/qt} |
2083 | directory, and you run the \c{regexp} example, this function will |
2084 | return "/usr/local/qt/examples/tools/regexp/regexp". |
2085 | |
2086 | \warning On Linux, this function will try to get the path from the |
2087 | \c {/proc} file system. If that fails, it assumes that \c |
2088 | {argv[0]} contains the absolute file name of the executable. The |
2089 | function also assumes that the current directory has not been |
2090 | changed by the application. |
2091 | |
2092 | \sa applicationDirPath() |
2093 | */ |
2094 | QString QCoreApplication::applicationFilePath() |
2095 | { |
2096 | if (!self) { |
2097 | qWarning("QCoreApplication::applicationFilePath: Please instantiate the QApplication object first" ); |
2098 | return QString(); |
2099 | } |
2100 | |
2101 | QCoreApplicationPrivate *d = self->d_func(); |
2102 | if (!d->cachedApplicationFilePath.isNull()) |
2103 | return d->cachedApplicationFilePath; |
2104 | |
2105 | #if defined(Q_WS_WIN) |
2106 | d->cachedApplicationFilePath = QFileInfo(qAppFileName()).filePath(); |
2107 | return d->cachedApplicationFilePath; |
2108 | #elif defined(Q_OS_BLACKBERRY) |
2109 | if (!arguments().isEmpty()) { // args is never empty, but the navigator can change behaviour some day |
2110 | QFileInfo fileInfo(arguments().at(0)); |
2111 | const bool zygotized = fileInfo.exists(); |
2112 | if (zygotized) { |
2113 | // Handle the zygotized case: |
2114 | d->cachedApplicationFilePath = QDir::cleanPath(fileInfo.absoluteFilePath()); |
2115 | return d->cachedApplicationFilePath; |
2116 | } |
2117 | } |
2118 | |
2119 | // Handle the non-zygotized case: |
2120 | const size_t maximum_path = static_cast<size_t>(pathconf("/" ,_PC_PATH_MAX)); |
2121 | char buff[maximum_path+1]; |
2122 | if (_cmdname(buff)) { |
2123 | d->cachedApplicationFilePath = QDir::cleanPath(QString::fromLocal8Bit(buff)); |
2124 | return d->cachedApplicationFilePath; |
2125 | } else { |
2126 | qWarning("QCoreApplication::applicationFilePath: _cmdname() failed" ); |
2127 | // _cmdname() won't fail, but just in case, fallback to the old method |
2128 | QDir dir(QLatin1String("./app/native/" )); |
2129 | QStringList executables = dir.entryList(QDir::Executable | QDir::Files); |
2130 | if (!executables.empty()) { |
2131 | //We assume that there is only one executable in the folder |
2132 | d->cachedApplicationFilePath = dir.absoluteFilePath(executables.first()); |
2133 | return d->cachedApplicationFilePath; |
2134 | } else { |
2135 | return QString(); |
2136 | } |
2137 | } |
2138 | #elif defined(Q_WS_MAC) |
2139 | QString qAppFileName_str = qAppFileName(); |
2140 | if(!qAppFileName_str.isEmpty()) { |
2141 | QFileInfo fi(qAppFileName_str); |
2142 | d->cachedApplicationFilePath = fi.exists() ? fi.canonicalFilePath() : QString(); |
2143 | return d->cachedApplicationFilePath; |
2144 | } |
2145 | #endif |
2146 | #if defined(Q_OS_SYMBIAN) |
2147 | QString appPath; |
2148 | RProcess proc; |
2149 | TInt err = proc.Open(proc.Id()); |
2150 | if (err == KErrNone) { |
2151 | TFileName procName = proc.FileName(); |
2152 | appPath.append(QString(reinterpret_cast<const QChar*>(procName.Ptr()), procName.Length())); |
2153 | proc.Close(); |
2154 | } |
2155 | |
2156 | d->cachedApplicationFilePath = appPath; |
2157 | return d->cachedApplicationFilePath; |
2158 | |
2159 | #elif defined( Q_OS_UNIX ) |
2160 | # ifdef Q_OS_LINUX |
2161 | // Try looking for a /proc/<pid>/exe symlink first which points to |
2162 | // the absolute path of the executable |
2163 | QFileInfo pfi(QString::fromLatin1("/proc/%1/exe" ).arg(getpid())); |
2164 | if (pfi.exists() && pfi.isSymLink()) { |
2165 | d->cachedApplicationFilePath = pfi.canonicalFilePath(); |
2166 | return d->cachedApplicationFilePath; |
2167 | } |
2168 | # endif |
2169 | |
2170 | QString argv0 = QFile::decodeName(QByteArray(argv()[0])); |
2171 | QString absPath; |
2172 | |
2173 | if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) { |
2174 | /* |
2175 | If argv0 starts with a slash, it is already an absolute |
2176 | file path. |
2177 | */ |
2178 | absPath = argv0; |
2179 | } else if (argv0.contains(QLatin1Char('/'))) { |
2180 | /* |
2181 | If argv0 contains one or more slashes, it is a file path |
2182 | relative to the current directory. |
2183 | */ |
2184 | absPath = QDir::current().absoluteFilePath(argv0); |
2185 | } else { |
2186 | /* |
2187 | Otherwise, the file path has to be determined using the |
2188 | PATH environment variable. |
2189 | */ |
2190 | QByteArray pEnv = qgetenv("PATH" ); |
2191 | QDir currentDir = QDir::current(); |
2192 | QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1Char(':')); |
2193 | for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) { |
2194 | if ((*p).isEmpty()) |
2195 | continue; |
2196 | QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0); |
2197 | QFileInfo candidate_fi(candidate); |
2198 | if (candidate_fi.exists() && !candidate_fi.isDir()) { |
2199 | absPath = candidate; |
2200 | break; |
2201 | } |
2202 | } |
2203 | } |
2204 | |
2205 | absPath = QDir::cleanPath(absPath); |
2206 | |
2207 | QFileInfo fi(absPath); |
2208 | d->cachedApplicationFilePath = fi.exists() ? fi.canonicalFilePath() : QString(); |
2209 | return d->cachedApplicationFilePath; |
2210 | #endif |
2211 | } |
2212 | |
2213 | /*! |
2214 | \since 4.4 |
2215 | |
2216 | Returns the current process ID for the application. |
2217 | */ |
2218 | qint64 QCoreApplication::applicationPid() |
2219 | { |
2220 | #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) |
2221 | return GetCurrentProcessId(); |
2222 | #elif defined(Q_OS_VXWORKS) |
2223 | return (pid_t) taskIdCurrent; |
2224 | #else |
2225 | return getpid(); |
2226 | #endif |
2227 | } |
2228 | |
2229 | /*! |
2230 | \obsolete |
2231 | |
2232 | Use arguments().size() instead. |
2233 | */ |
2234 | int QCoreApplication::argc() |
2235 | { |
2236 | if (!self) { |
2237 | qWarning("QCoreApplication::argc: Please instantiate the QApplication object first" ); |
2238 | return 0; |
2239 | } |
2240 | return self->d_func()->argc; |
2241 | } |
2242 | |
2243 | |
2244 | /*! |
2245 | \obsolete |
2246 | |
2247 | Use arguments() instead. |
2248 | */ |
2249 | char **QCoreApplication::argv() |
2250 | { |
2251 | if (!self) { |
2252 | qWarning("QCoreApplication::argv: Please instantiate the QApplication object first" ); |
2253 | return 0; |
2254 | } |
2255 | return self->d_func()->argv; |
2256 | } |
2257 | |
2258 | /*! |
2259 | \since 4.1 |
2260 | |
2261 | Returns the list of command-line arguments. |
2262 | |
2263 | Usually arguments().at(0) is the program name, arguments().at(1) |
2264 | is the first argument, and arguments().last() is the last |
2265 | argument. See the note below about Windows. |
2266 | |
2267 | Calling this function is slow - you should store the result in a variable |
2268 | when parsing the command line. |
2269 | |
2270 | \warning On Unix, this list is built from the argc and argv parameters passed |
2271 | to the constructor in the main() function. The string-data in argv is |
2272 | interpreted using QString::fromLocal8Bit(); hence it is not possible to |
2273 | pass, for example, Japanese command line arguments on a system that runs in a |
2274 | Latin1 locale. Most modern Unix systems do not have this limitation, as they are |
2275 | Unicode-based. |
2276 | |
2277 | On NT-based Windows, this limitation does not apply either. |
2278 | On Windows, the arguments() are not built from the contents of argv/argc, as |
2279 | the content does not support Unicode. Instead, the arguments() are constructed |
2280 | from the return value of |
2281 | \l{http://msdn2.microsoft.com/en-us/library/ms683156(VS.85).aspx}{GetCommandLine()}. |
2282 | As a result of this, the string given by arguments().at(0) might not be |
2283 | the program name on Windows, depending on how the application was started. |
2284 | |
2285 | For Symbian applications started with \c RApaLsSession::StartApp one can specify |
2286 | arguments using \c CApaCommandLine::SetTailEndL function. Such arguments are only |
2287 | available via this method; they will not be passed to \c main function. Also note |
2288 | that only 8-bit string data set with \c CApaCommandLine::SetTailEndL is supported |
2289 | by this function. |
2290 | |
2291 | \sa applicationFilePath() |
2292 | */ |
2293 | |
2294 | QStringList QCoreApplication::arguments() |
2295 | { |
2296 | QStringList list; |
2297 | |
2298 | if (!self) { |
2299 | qWarning("QCoreApplication::arguments: Please instantiate the QApplication object first" ); |
2300 | return list; |
2301 | } |
2302 | #ifdef Q_OS_WIN |
2303 | QString cmdline = QString::fromWCharArray(GetCommandLine()); |
2304 | |
2305 | #if defined(Q_OS_WINCE) |
2306 | wchar_t tempFilename[MAX_PATH+1]; |
2307 | if (GetModuleFileName(0, tempFilename, MAX_PATH)) { |
2308 | tempFilename[MAX_PATH] = 0; |
2309 | cmdline.prepend(QLatin1Char('\"') + QString::fromWCharArray(tempFilename) + QLatin1String("\" " )); |
2310 | } |
2311 | #endif // Q_OS_WINCE |
2312 | |
2313 | list = qWinCmdArgs(cmdline); |
2314 | if (self->d_func()->application_type) { // GUI app? Skip known - see qapplication.cpp |
2315 | QStringList stripped; |
2316 | for (int a = 0; a < list.count(); ++a) { |
2317 | QString arg = list.at(a); |
2318 | QByteArray l1arg = arg.toLatin1(); |
2319 | if (l1arg == "-qdevel" || |
2320 | l1arg == "-qdebug" || |
2321 | l1arg == "-reverse" || |
2322 | l1arg == "-stylesheet" || |
2323 | l1arg == "-widgetcount" ) |
2324 | ; |
2325 | else if (l1arg.startsWith("-style=" ) || |
2326 | l1arg.startsWith("-qmljsdebugger=" )) |
2327 | ; |
2328 | else if (l1arg == "-style" || |
2329 | l1arg == "-qmljsdebugger" || |
2330 | l1arg == "-session" || |
2331 | l1arg == "-graphicssystem" || |
2332 | l1arg == "-testability" ) |
2333 | ++a; |
2334 | else |
2335 | stripped += arg; |
2336 | } |
2337 | list = stripped; |
2338 | } |
2339 | #else |
2340 | const int ac = self->d_func()->argc; |
2341 | char ** const av = self->d_func()->argv; |
2342 | for (int a = 0; a < ac; ++a) { |
2343 | list << QString::fromLocal8Bit(av[a]); |
2344 | } |
2345 | #endif |
2346 | |
2347 | return list; |
2348 | } |
2349 | |
2350 | /*! |
2351 | \property QCoreApplication::organizationName |
2352 | \brief the name of the organization that wrote this application |
2353 | |
2354 | The value is used by the QSettings class when it is constructed |
2355 | using the empty constructor. This saves having to repeat this |
2356 | information each time a QSettings object is created. |
2357 | |
2358 | On Mac, QSettings uses organizationDomain() as the organization |
2359 | if it's not an empty string; otherwise it uses |
2360 | organizationName(). On all other platforms, QSettings uses |
2361 | organizationName() as the organization. |
2362 | |
2363 | On BlackBerry this property is read-only. It is obtained from the |
2364 | BAR application descriptor file. |
2365 | |
2366 | \sa organizationDomain applicationName |
2367 | */ |
2368 | |
2369 | void QCoreApplication::setOrganizationName(const QString &orgName) |
2370 | { |
2371 | coreappdata()->orgName = orgName; |
2372 | } |
2373 | |
2374 | QString QCoreApplication::organizationName() |
2375 | { |
2376 | #ifdef Q_OS_BLACKBERRY |
2377 | coreappdata()->loadManifest(); |
2378 | #endif |
2379 | return coreappdata()->orgName; |
2380 | } |
2381 | |
2382 | /*! |
2383 | \property QCoreApplication::organizationDomain |
2384 | \brief the Internet domain of the organization that wrote this application |
2385 | |
2386 | The value is used by the QSettings class when it is constructed |
2387 | using the empty constructor. This saves having to repeat this |
2388 | information each time a QSettings object is created. |
2389 | |
2390 | On Mac, QSettings uses organizationDomain() as the organization |
2391 | if it's not an empty string; otherwise it uses organizationName(). |
2392 | On all other platforms, QSettings uses organizationName() as the |
2393 | organization. |
2394 | |
2395 | \sa organizationName applicationName applicationVersion |
2396 | */ |
2397 | void QCoreApplication::setOrganizationDomain(const QString &orgDomain) |
2398 | { |
2399 | coreappdata()->orgDomain = orgDomain; |
2400 | } |
2401 | |
2402 | QString QCoreApplication::organizationDomain() |
2403 | { |
2404 | return coreappdata()->orgDomain; |
2405 | } |
2406 | |
2407 | /*! |
2408 | \property QCoreApplication::applicationName |
2409 | \brief the name of this application |
2410 | |
2411 | The value is used by the QSettings class when it is constructed |
2412 | using the empty constructor. This saves having to repeat this |
2413 | information each time a QSettings object is created. |
2414 | |
2415 | On BlackBerry this property is read-only. It is obtained from the |
2416 | BAR application descriptor file. |
2417 | |
2418 | \sa organizationName organizationDomain applicationVersion |
2419 | */ |
2420 | void QCoreApplication::setApplicationName(const QString &application) |
2421 | { |
2422 | coreappdata()->application = application; |
2423 | } |
2424 | |
2425 | QString QCoreApplication::applicationName() |
2426 | { |
2427 | #ifdef Q_OS_BLACKBERRY |
2428 | coreappdata()->loadManifest(); |
2429 | #endif |
2430 | |
2431 | QString appname = coreappdata() ? coreappdata()->application : QString(); |
2432 | if (appname.isEmpty() && QCoreApplication::self) |
2433 | appname = QCoreApplication::self->d_func()->appName(); |
2434 | |
2435 | return appname; |
2436 | } |
2437 | |
2438 | /*! |
2439 | \property QCoreApplication::applicationVersion |
2440 | \since 4.4 |
2441 | \brief the version of this application |
2442 | |
2443 | On BlackBerry this property is read-only. It is obtained from the |
2444 | BAR application descriptor file. |
2445 | |
2446 | \sa applicationName organizationName organizationDomain |
2447 | */ |
2448 | void QCoreApplication::setApplicationVersion(const QString &version) |
2449 | { |
2450 | coreappdata()->applicationVersion = version; |
2451 | } |
2452 | |
2453 | QString QCoreApplication::applicationVersion() |
2454 | { |
2455 | #ifdef Q_OS_BLACKBERRY |
2456 | coreappdata()->loadManifest(); |
2457 | #endif |
2458 | return coreappdata()->applicationVersion; |
2459 | } |
2460 | |
2461 | #ifndef QT_NO_LIBRARY |
2462 | |
2463 | #if defined(Q_OS_SYMBIAN) |
2464 | void qt_symbian_installLibraryPaths(QString installPathPlugins, QStringList& libPaths) |
2465 | { |
2466 | // Add existing path on all drives for relative PluginsPath in Symbian |
2467 | QString tempPath = installPathPlugins; |
2468 | if (tempPath.at(tempPath.length() - 1) != QDir::separator()) { |
2469 | tempPath += QDir::separator(); |
2470 | } |
2471 | RFs& fs = qt_s60GetRFs(); |
2472 | TPtrC tempPathPtr(reinterpret_cast<const TText*> (tempPath.constData())); |
2473 | // Symbian searches should start from Y:. Fix start drive otherwise TFindFile starts from the session drive |
2474 | _LIT(KStartDir, "Y:" ); |
2475 | TFileName dirPath(KStartDir); |
2476 | dirPath.Append(tempPathPtr); |
2477 | TFindFile finder(fs); |
2478 | TInt err = finder.FindByDir(tempPathPtr, dirPath); |
2479 | while (err == KErrNone) { |
2480 | QString foundDir(reinterpret_cast<const QChar *>(finder.File().Ptr()), |
2481 | finder.File().Length()); |
2482 | foundDir = QDir(foundDir).canonicalPath(); |
2483 | if (!libPaths.contains(foundDir)) |
2484 | libPaths.append(foundDir); |
2485 | err = finder.Find(); |
2486 | } |
2487 | } |
2488 | #endif |
2489 | |
2490 | Q_GLOBAL_STATIC_WITH_ARGS(QMutex, libraryPathMutex, (QMutex::Recursive)) |
2491 | |
2492 | /*! |
2493 | Returns a list of paths that the application will search when |
2494 | dynamically loading libraries. |
2495 | |
2496 | Qt provides default library paths, but they can also be set using |
2497 | a \l{Using qt.conf}{qt.conf} file. Paths specified in this file |
2498 | will override default values. |
2499 | |
2500 | This list will include the installation directory for plugins if |
2501 | it exists (the default installation directory for plugins is \c |
2502 | INSTALL/plugins, where \c INSTALL is the directory where Qt was |
2503 | installed). The directory of the application executable (NOT the |
2504 | working directory) is always added, as well as the colon separated |
2505 | entries of the QT_PLUGIN_PATH environment variable. |
2506 | |
2507 | If you want to iterate over the list, you can use the \l foreach |
2508 | pseudo-keyword: |
2509 | |
2510 | \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 2 |
2511 | |
2512 | \sa setLibraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary, |
2513 | {How to Create Qt Plugins} |
2514 | */ |
2515 | QStringList QCoreApplication::libraryPaths() |
2516 | { |
2517 | QMutexLocker locker(libraryPathMutex()); |
2518 | if (!coreappdata()->app_libpaths) { |
2519 | QStringList *app_libpaths = coreappdata()->app_libpaths = new QStringList; |
2520 | QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); |
2521 | #if defined(Q_OS_SYMBIAN) |
2522 | if (installPathPlugins.at(1) != QChar(QLatin1Char(':'))) { |
2523 | qt_symbian_installLibraryPaths(installPathPlugins, *app_libpaths); |
2524 | } |
2525 | #else |
2526 | if (QFile::exists(installPathPlugins)) { |
2527 | // Make sure we convert from backslashes to slashes. |
2528 | installPathPlugins = QDir(installPathPlugins).canonicalPath(); |
2529 | if (!app_libpaths->contains(installPathPlugins)) |
2530 | app_libpaths->append(installPathPlugins); |
2531 | } |
2532 | #endif |
2533 | |
2534 | // If QCoreApplication is not yet instantiated, |
2535 | // make sure we add the application path when we construct the QCoreApplication |
2536 | if (self) self->d_func()->appendApplicationPathToLibraryPaths(); |
2537 | |
2538 | const QByteArray libPathEnv = qgetenv("QT_PLUGIN_PATH" ); |
2539 | if (!libPathEnv.isEmpty()) { |
2540 | #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) |
2541 | QLatin1Char pathSep(';'); |
2542 | #else |
2543 | QLatin1Char pathSep(':'); |
2544 | #endif |
2545 | QStringList paths = QString::fromLatin1(libPathEnv).split(pathSep, QString::SkipEmptyParts); |
2546 | for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) { |
2547 | QString canonicalPath = QDir(*it).canonicalPath(); |
2548 | if (!canonicalPath.isEmpty() |
2549 | && !app_libpaths->contains(canonicalPath)) { |
2550 | app_libpaths->append(canonicalPath); |
2551 | } |
2552 | } |
2553 | } |
2554 | } |
2555 | return *(coreappdata()->app_libpaths); |
2556 | } |
2557 | |
2558 | |
2559 | |
2560 | /*! |
2561 | |
2562 | Sets the list of directories to search when loading libraries to |
2563 | \a paths. All existing paths will be deleted and the path list |
2564 | will consist of the paths given in \a paths. |
2565 | |
2566 | In Symbian this function is only useful for setting paths for |
2567 | finding Qt extension plugin stubs, since the OS can only |
2568 | load libraries from the \c{/sys/bin} directory. |
2569 | |
2570 | \sa libraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary |
2571 | */ |
2572 | void QCoreApplication::setLibraryPaths(const QStringList &paths) |
2573 | { |
2574 | QMutexLocker locker(libraryPathMutex()); |
2575 | if (!coreappdata()->app_libpaths) |
2576 | coreappdata()->app_libpaths = new QStringList; |
2577 | *(coreappdata()->app_libpaths) = paths; |
2578 | locker.unlock(); |
2579 | QFactoryLoader::refreshAll(); |
2580 | } |
2581 | |
2582 | /*! |
2583 | Prepends \a path to the beginning of the library path list, ensuring that |
2584 | it is searched for libraries first. If \a path is empty or already in the |
2585 | path list, the path list is not changed. |
2586 | |
2587 | The default path list consists of a single entry, the installation |
2588 | directory for plugins. The default installation directory for plugins |
2589 | is \c INSTALL/plugins, where \c INSTALL is the directory where Qt was |
2590 | installed. |
2591 | |
2592 | In Symbian this function is only useful for adding paths for |
2593 | finding Qt extension plugin stubs, since the OS can only |
2594 | load libraries from the \c{/sys/bin} directory. |
2595 | |
2596 | \sa removeLibraryPath(), libraryPaths(), setLibraryPaths() |
2597 | */ |
2598 | void QCoreApplication::addLibraryPath(const QString &path) |
2599 | { |
2600 | if (path.isEmpty()) |
2601 | return; |
2602 | |
2603 | QMutexLocker locker(libraryPathMutex()); |
2604 | |
2605 | // make sure that library paths is initialized |
2606 | libraryPaths(); |
2607 | |
2608 | QString canonicalPath = QDir(path).canonicalPath(); |
2609 | if (!canonicalPath.isEmpty() |
2610 | && !coreappdata()->app_libpaths->contains(canonicalPath)) { |
2611 | coreappdata()->app_libpaths->prepend(canonicalPath); |
2612 | locker.unlock(); |
2613 | QFactoryLoader::refreshAll(); |
2614 | } |
2615 | } |
2616 | |
2617 | /*! |
2618 | Removes \a path from the library path list. If \a path is empty or not |
2619 | in the path list, the list is not changed. |
2620 | |
2621 | \sa addLibraryPath(), libraryPaths(), setLibraryPaths() |
2622 | */ |
2623 | void QCoreApplication::removeLibraryPath(const QString &path) |
2624 | { |
2625 | if (path.isEmpty()) |
2626 | return; |
2627 | |
2628 | QMutexLocker locker(libraryPathMutex()); |
2629 | |
2630 | // make sure that library paths is initialized |
2631 | libraryPaths(); |
2632 | |
2633 | QString canonicalPath = QDir(path).canonicalPath(); |
2634 | coreappdata()->app_libpaths->removeAll(canonicalPath); |
2635 | QFactoryLoader::refreshAll(); |
2636 | } |
2637 | |
2638 | #if defined(Q_OS_SYMBIAN) |
2639 | void QCoreApplicationPrivate::rebuildInstallLibraryPaths() |
2640 | { |
2641 | // check there is not a single fixed install path |
2642 | QString nativeInstallPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); |
2643 | if (nativeInstallPathPlugins.at(1) == QChar(QLatin1Char(':'))) |
2644 | return; |
2645 | QString installPathPlugins = QDir::cleanPath(nativeInstallPathPlugins); |
2646 | // look for the install path at the drive roots |
2647 | installPathPlugins.prepend(QChar(QLatin1Char(':'))); |
2648 | |
2649 | QMutexLocker locker(libraryPathMutex()); |
2650 | QStringList &app_libpaths = *coreappdata()->app_libpaths; |
2651 | // Build a new library path, copying non-installPath components, and replacing existing install path with new |
2652 | QStringList newPaths; |
2653 | bool installPathFound = false; |
2654 | foreach (QString path, app_libpaths) { |
2655 | if (path.mid(1).compare(installPathPlugins, Qt::CaseInsensitive) == 0) { |
2656 | // skip existing install paths, insert new install path when we find the first |
2657 | if (!installPathFound) |
2658 | qt_symbian_installLibraryPaths(nativeInstallPathPlugins, newPaths); |
2659 | installPathFound = true; |
2660 | } else { |
2661 | newPaths.append(path); |
2662 | } |
2663 | } |
2664 | app_libpaths = newPaths; |
2665 | } |
2666 | #endif |
2667 | |
2668 | #endif //QT_NO_LIBRARY |
2669 | |
2670 | /*! |
2671 | \typedef QCoreApplication::EventFilter |
2672 | |
2673 | A function with the following signature that can be used as an |
2674 | event filter: |
2675 | |
2676 | \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 3 |
2677 | |
2678 | \sa setEventFilter() |
2679 | */ |
2680 | |
2681 | /*! |
2682 | \fn EventFilter QCoreApplication::setEventFilter(EventFilter filter) |
2683 | |
2684 | Replaces the event filter function for the QCoreApplication with |
2685 | \a filter and returns the pointer to the replaced event filter |
2686 | function. Only the current event filter function is called. If you |
2687 | want to use both filter functions, save the replaced EventFilter |
2688 | in a place where yours can call it. |
2689 | |
2690 | The event filter function set here is called for all messages |
2691 | received by all threads meant for all Qt objects. It is \e not |
2692 | called for messages that are not meant for Qt objects. |
2693 | |
2694 | The event filter function should return true if the message should |
2695 | be filtered, (i.e. stopped). It should return false to allow |
2696 | processing the message to continue. |
2697 | |
2698 | By default, no event filter function is set (i.e., this function |
2699 | returns a null EventFilter the first time it is called). |
2700 | |
2701 | \note The filter function set here receives native messages, |
2702 | i.e. MSG or XEvent structs, that are going to Qt objects. It is |
2703 | called by QCoreApplication::filterEvent(). If the filter function |
2704 | returns false to indicate the message should be processed further, |
2705 | the native message can then be translated into a QEvent and |
2706 | handled by the standard Qt \l{QEvent} {event} filering, e.g. |
2707 | QObject::installEventFilter(). |
2708 | |
2709 | \note The filter function set here is different form the filter |
2710 | function set via QAbstractEventDispatcher::setEventFilter(), which |
2711 | gets all messages received by its thread, even messages meant for |
2712 | objects that are not handled by Qt. |
2713 | |
2714 | \sa QObject::installEventFilter(), QAbstractEventDispatcher::setEventFilter() |
2715 | */ |
2716 | QCoreApplication::EventFilter |
2717 | QCoreApplication::setEventFilter(QCoreApplication::EventFilter filter) |
2718 | { |
2719 | Q_D(QCoreApplication); |
2720 | EventFilter old = d->eventFilter; |
2721 | d->eventFilter = filter; |
2722 | return old; |
2723 | } |
2724 | |
2725 | /*! |
2726 | Sends \a message through the event filter that was set by |
2727 | setEventFilter(). If no event filter has been set, this function |
2728 | returns false; otherwise, this function returns the result of the |
2729 | event filter function in the \a result parameter. |
2730 | |
2731 | \sa setEventFilter() |
2732 | */ |
2733 | bool QCoreApplication::filterEvent(void *message, long *result) |
2734 | { |
2735 | Q_D(QCoreApplication); |
2736 | if (result) |
2737 | *result = 0; |
2738 | if (d->eventFilter) |
2739 | return d->eventFilter(message, result); |
2740 | #ifdef Q_OS_WIN |
2741 | return winEventFilter(reinterpret_cast<MSG *>(message), result); |
2742 | #else |
2743 | return false; |
2744 | #endif |
2745 | } |
2746 | |
2747 | /*! |
2748 | This function returns true if there are pending events; otherwise |
2749 | returns false. Pending events can be either from the window |
2750 | system or posted events using postEvent(). |
2751 | |
2752 | \sa QAbstractEventDispatcher::hasPendingEvents() |
2753 | */ |
2754 | bool QCoreApplication::hasPendingEvents() |
2755 | { |
2756 | QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); |
2757 | if (eventDispatcher) |
2758 | return eventDispatcher->hasPendingEvents(); |
2759 | return false; |
2760 | } |
2761 | |
2762 | #ifdef QT3_SUPPORT |
2763 | /*! \fn void QCoreApplication::lock() |
2764 | |
2765 | In Qt 3, this function locked the Qt library mutex, allowing |
2766 | non-GUI threads to perform basic printing operations using |
2767 | QPainter. |
2768 | |
2769 | In Qt 4, this is no longer supported, since painting is only |
2770 | supported from within a paint event handler. This function does |
2771 | nothing. |
2772 | |
2773 | \sa QWidget::paintEvent() |
2774 | */ |
2775 | |
2776 | /*! \fn void QCoreApplication::unlock(bool wakeUpGui) |
2777 | |
2778 | In Qt 3, this function unlocked the Qt library mutex. The mutex |
2779 | allowed non-GUI threads to perform basic printing operations |
2780 | using QPainter. |
2781 | |
2782 | In Qt 4, this is no longer supported, since painting is only |
2783 | supported from within a paint event handler. This function does |
2784 | nothing. |
2785 | */ |
2786 | |
2787 | /*! \fn bool QCoreApplication::locked() |
2788 | |
2789 | This function does nothing. It is there to keep old code working. |
2790 | It always returns false. |
2791 | |
2792 | See lock() for details. |
2793 | */ |
2794 | |
2795 | /*! \fn bool QCoreApplication::tryLock() |
2796 | |
2797 | This function does nothing. It is there to keep old code working. |
2798 | It always returns false. |
2799 | |
2800 | See lock() for details. |
2801 | */ |
2802 | |
2803 | /*! \fn void QCoreApplication::processOneEvent() |
2804 | \obsolete |
2805 | |
2806 | Waits for an event to occur, processes it, then returns. |
2807 | |
2808 | This function is useful for adapting Qt to situations where the |
2809 | event processing must be grafted onto existing program loops. |
2810 | |
2811 | Using this function in new applications may be an indication of design |
2812 | problems. |
2813 | |
2814 | \sa processEvents(), exec(), QTimer |
2815 | */ |
2816 | |
2817 | /*! \obsolete |
2818 | |
2819 | This function enters the main event loop (recursively). Do not call |
2820 | it unless you really know what you are doing. |
2821 | */ |
2822 | int QCoreApplication::enter_loop() |
2823 | { |
2824 | if (!QCoreApplicationPrivate::checkInstance("enter_loop" )) |
2825 | return -1; |
2826 | if (QThreadData::current() != self->d_func()->threadData) { |
2827 | qWarning("QCoreApplication::enter_loop: Must be called from the main thread" ); |
2828 | return -1; |
2829 | } |
2830 | QEventLoop eventLoop; |
2831 | int returnCode = eventLoop.exec(); |
2832 | return returnCode; |
2833 | } |
2834 | |
2835 | /*! \obsolete |
2836 | |
2837 | This function exits from a recursive call to the main event loop. |
2838 | Do not call it unless you are an expert. |
2839 | */ |
2840 | void QCoreApplication::exit_loop() |
2841 | { |
2842 | if (!QCoreApplicationPrivate::checkInstance("exit_loop" )) |
2843 | return; |
2844 | QThreadData *data = QThreadData::current(); |
2845 | if (data != self->d_func()->threadData) { |
2846 | qWarning("QCoreApplication::exit_loop: Must be called from the main thread" ); |
2847 | return; |
2848 | } |
2849 | if (!data->eventLoops.isEmpty()) |
2850 | data->eventLoops.top()->exit(); |
2851 | } |
2852 | |
2853 | /*! \obsolete |
2854 | |
2855 | Returns the current loop level. |
2856 | */ |
2857 | int QCoreApplication::loopLevel() |
2858 | { |
2859 | if (!QCoreApplicationPrivate::checkInstance("loopLevel" )) |
2860 | return -1; |
2861 | return self->d_func()->threadData->eventLoops.size(); |
2862 | } |
2863 | #endif |
2864 | |
2865 | /* |
2866 | \fn void QCoreApplication::watchUnixSignal(int signal, bool watch) |
2867 | \internal |
2868 | */ |
2869 | |
2870 | /*! |
2871 | \fn void QCoreApplication::unixSignal(int number) |
2872 | \internal |
2873 | |
2874 | This signal is emitted whenever a Unix signal is received by the |
2875 | application. The Unix signal received is specified by its \a number. |
2876 | */ |
2877 | |
2878 | /*! |
2879 | \fn void qAddPostRoutine(QtCleanUpFunction ptr) |
2880 | \relates QCoreApplication |
2881 | |
2882 | Adds a global routine that will be called from the QApplication |
2883 | destructor. This function is normally used to add cleanup routines |
2884 | for program-wide functionality. |
2885 | |
2886 | The function specified by \a ptr should take no arguments and should |
2887 | return nothing. For example: |
2888 | |
2889 | \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 4 |
2890 | |
2891 | Note that for an application- or module-wide cleanup, |
2892 | qAddPostRoutine() is often not suitable. For example, if the |
2893 | program is split into dynamically loaded modules, the relevant |
2894 | module may be unloaded long before the QApplication destructor is |
2895 | called. |
2896 | |
2897 | For modules and libraries, using a reference-counted |
2898 | initialization manager or Qt's parent-child deletion mechanism may |
2899 | be better. Here is an example of a private class that uses the |
2900 | parent-child mechanism to call a cleanup function at the right |
2901 | time: |
2902 | |
2903 | \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 5 |
2904 | |
2905 | By selecting the right parent object, this can often be made to |
2906 | clean up the module's data at the right moment. |
2907 | */ |
2908 | |
2909 | /*! |
2910 | \macro Q_DECLARE_TR_FUNCTIONS(context) |
2911 | \relates QCoreApplication |
2912 | |
2913 | The Q_DECLARE_TR_FUNCTIONS() macro declares and implements two |
2914 | translation functions, \c tr() and \c trUtf8(), with these |
2915 | signatures: |
2916 | |
2917 | \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 6 |
2918 | |
2919 | This macro is useful if you want to use QObject::tr() or |
2920 | QObject::trUtf8() in classes that don't inherit from QObject. |
2921 | |
2922 | Q_DECLARE_TR_FUNCTIONS() must appear at the very top of the |
2923 | class definition (before the first \c{public:} or \c{protected:}). |
2924 | For example: |
2925 | |
2926 | \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 7 |
2927 | |
2928 | The \a context parameter is normally the class name, but it can |
2929 | be any string. |
2930 | |
2931 | \sa Q_OBJECT, QObject::tr(), QObject::trUtf8() |
2932 | */ |
2933 | |
2934 | QT_END_NAMESPACE |
2935 | |