diff --git a/src/kdeui/kaction.cpp b/src/kdeui/kaction.cpp index 2b48e1cd..286b8f12 100644 --- a/src/kdeui/kaction.cpp +++ b/src/kdeui/kaction.cpp @@ -1,296 +1,241 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Reginald Stadlbauer (C) 1999 Simon Hausmann (C) 2000 Nicolas Hadacek (C) 2000 Kurt Granroth (C) 2000 Michael Koch (C) 2001 Holger Freyther (C) 2002 Ellis Whitehead (C) 2002 Joseph Wenninger (C) 2005-2006 Hamish Rodda This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kaction.h" #include "kaction_p.h" #include "klocalizedstring.h" #include "kauthobjectdecorator.h" #include #include #include #include #include //--------------------------------------------------------------------- // KActionPrivate //--------------------------------------------------------------------- void KActionPrivate::init(KAction *q_ptr) { q = q_ptr; QObject::connect(q, SIGNAL(triggered(bool)), q, SLOT(slotTriggered())); q->setProperty("isShortcutConfigurable", true); decorator = new KAuth::ObjectDecorator(q); QObject::connect(decorator, SIGNAL(authorized(KAuth::Action)), q, SIGNAL(authorized(KAuth::Action))); QObject::connect(KGlobalAccel::self(), SIGNAL(globalShortcutChanged(QAction*,QKeySequence)), q, SLOT(_k_emitActionGlobalShortcutChanged(QAction*,QKeySequence))); } void KActionPrivate::slotTriggered() { #ifdef KDE3_SUPPORT emit q->activated(); #endif emit q->triggered(QApplication::mouseButtons(), QApplication::keyboardModifiers()); } void KActionPrivate::_k_emitActionGlobalShortcutChanged(QAction *action, const QKeySequence &seq) { if (action == q) { // reemit the legacy KAction::globalShortcutChanged // TODO: completely remove this method when KAction::globalShortcutChanged signal will be removed emit q->globalShortcutChanged(seq); } } //--------------------------------------------------------------------- // KAction //--------------------------------------------------------------------- KAction::KAction(QObject *parent) : QWidgetAction(parent), d(new KActionPrivate) { d->init(this); } KAction::KAction(const QString &text, QObject *parent) : QWidgetAction(parent), d(new KActionPrivate) { d->init(this); setText(text); } KAction::KAction(const QIcon &icon, const QString &text, QObject *parent) : QWidgetAction(parent), d(new KActionPrivate) { d->init(this); setIcon(icon); setText(text); } KAction::~KAction() { - KGestureMap::self()->removeAllGestures(this); delete d; } bool KAction::isShortcutConfigurable() const { return property("isShortcutConfigurable").toBool(); } void KAction::setShortcutConfigurable(bool b) { setProperty("isShortcutConfigurable", b); } KShortcut KAction::shortcut(ShortcutTypes type) const { Q_ASSERT(type); if (type == DefaultShortcut) { QList shortcuts = property("defaultShortcuts").value >(); return KShortcut(shortcuts); } QKeySequence primary = shortcuts().value(0); QKeySequence secondary = shortcuts().value(1); return KShortcut(primary, secondary); } void KAction::setShortcut(const KShortcut &shortcut, ShortcutTypes type) { Q_ASSERT(type); if (type & DefaultShortcut) { setProperty("defaultShortcuts", QVariant::fromValue(shortcut.toList())); } if (type & ActiveShortcut) { QAction::setShortcuts(shortcut); } } void KAction::setShortcut(const QKeySequence &keySeq, ShortcutTypes type) { Q_ASSERT(type); if (type & DefaultShortcut) { setProperty("defaultShortcuts", QVariant::fromValue(QList() << keySeq)); } if (type & ActiveShortcut) { QAction::setShortcut(keySeq); } } void KAction::setShortcuts(const QList &shortcuts, ShortcutTypes type) { setShortcut(KShortcut(shortcuts), type); } KShortcut KAction::globalShortcut(ShortcutTypes type) const { Q_ASSERT(type); if (type == DefaultShortcut) { return KGlobalAccel::self()->defaultShortcut(this); } return KGlobalAccel::self()->shortcut(this); } void KAction::setGlobalShortcut(const KShortcut &shortcut, ShortcutTypes type, GlobalShortcutLoading load) { Q_ASSERT(type); if ((type & DefaultShortcut) && globalShortcut(DefaultShortcut) != shortcut) { KGlobalAccel::self()->setDefaultShortcut(this, shortcut, static_cast(load)); } if ((type & ActiveShortcut) && globalShortcut(ActiveShortcut) != shortcut) { KGlobalAccel::self()->setShortcut(this, shortcut, static_cast(load)); } } #ifndef KDELIBS4SUPPORT_NO_DEPRECATED bool KAction::globalShortcutAllowed() const { return isGlobalShortcutEnabled(); } #endif bool KAction::isGlobalShortcutEnabled() const { return KGlobalAccel::self()->hasShortcut(this); } #ifndef KDELIBS4SUPPORT_NO_DEPRECATED void KAction::setGlobalShortcutAllowed(bool allowed, GlobalShortcutLoading /* load */) { if (allowed) { //### no-op } else { forgetGlobalShortcut(); } } #endif void KAction::forgetGlobalShortcut() { if (isGlobalShortcutEnabled()) { KGlobalAccel::self()->removeAllShortcuts(this); } } -KShapeGesture KAction::shapeGesture(ShortcutTypes type) const -{ - Q_ASSERT(type); - if (type & DefaultShortcut) { - return KGestureMap::self()->defaultShapeGesture(this); - } else { - return KGestureMap::self()->shapeGesture(this); - } -} - -KRockerGesture KAction::rockerGesture(ShortcutTypes type) const -{ - Q_ASSERT(type); - if (type & DefaultShortcut) { - return KGestureMap::self()->defaultRockerGesture(this); - } else { - return KGestureMap::self()->rockerGesture(this); - } -} - -void KAction::setShapeGesture(const KShapeGesture &gest, ShortcutTypes type) -{ - Q_ASSERT(type); - - if (type & DefaultShortcut) { - KGestureMap::self()->setDefaultShapeGesture(this, gest); - } - - if (type & ActiveShortcut) { - if (KGestureMap::self()->findAction(gest)) { - kDebug(283) << "New mouse gesture already in use, won't change gesture."; - return; - } - KGestureMap::self()->setShapeGesture(this, gest); - } -} - -void KAction::setRockerGesture(const KRockerGesture &gest, ShortcutTypes type) -{ - Q_ASSERT(type); - - if (type & DefaultShortcut) { - KGestureMap::self()->setDefaultRockerGesture(this, gest); - } - - if (type & ActiveShortcut) { - if (KGestureMap::self()->findAction(gest)) { - kDebug(283) << "New mouse gesture already in use, won't change gesture."; - return; - } - KGestureMap::self()->setRockerGesture(this, gest); - } -} - void KAction::setHelpText(const QString &text) { setStatusTip(text); setToolTip(text); if (whatsThis().isEmpty()) { setWhatsThis(text); } } KAuth::Action KAction::authAction() const { return d->decorator->authAction(); } void KAction::setAuthAction(const QString &actionName) { d->decorator->setAuthAction(actionName); } void KAction::setAuthAction(const KAuth::Action &action) { d->decorator->setAuthAction(action); } #include "moc_kaction.cpp" diff --git a/src/kdeui/kaction_p.h b/src/kdeui/kaction_p.h index 99091a75..d45fc3cf 100644 --- a/src/kdeui/kaction_p.h +++ b/src/kdeui/kaction_p.h @@ -1,54 +1,53 @@ /* This file is part of the KDE libraries Copyright (c) 2007 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KACTION_P_H #define KACTION_P_H #include "kaction.h" #include "kglobalaccel.h" -#include "kgesturemap_p.h" #include #include class KAction; namespace KAuth { class ObjectDecorator; } class KActionPrivate { public: KActionPrivate() : q(nullptr), decorator(nullptr) { } void slotTriggered(); void _k_emitActionGlobalShortcutChanged(QAction *action, const QKeySequence &seq); void authStatusChanged(KAuth::Action::AuthStatus status); void init(KAction *q_ptr); KAction *q; KAuth::ObjectDecorator *decorator; }; #endif diff --git a/src/kdeui/kapplication.cpp b/src/kdeui/kapplication.cpp index a367f0e0..353f37fe 100644 --- a/src/kdeui/kapplication.cpp +++ b/src/kdeui/kapplication.cpp @@ -1,1000 +1,998 @@ /* This file is part of the KDE libraries Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) Copyright (C) 1998, 1999, 2000 KDE Team This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kapplication.h" #include "kdeversion.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kauthorized.h" #include "k4aboutdata.h" #include "kcrash.h" #include "kconfig.h" #include "kcmdlineargs.h" #include "kglobalsettings.h" #include "kdebug.h" #include #include "klocale.h" #include "klocalizedstring.h" #include "ksessionmanager.h" #include "ktoolinvocation.h" #include "kgesturemap_p.h" #include "kurl.h" #include "kmessage.h" #include "kmessageboxmessagehandler.h" #include #include #if HAVE_X11 #include #endif #include #include #if HAVE_SYS_STAT_H #include #endif #include #ifndef Q_OS_WIN #include "kwindowsystem.h" #endif #include #include // srand(), rand() #include #if HAVE_X11 #include #endif #if HAVE_PATHS_H #include #endif #if HAVE_X11 #include #include #include #include #include #include #endif #ifdef Q_OS_MAC // ick #undef Status #include #include #include #include #endif #ifdef Q_OS_UNIX #include #endif #include #include #include KApplication *KApplication::KApp = nullptr; #if HAVE_X11 static Atom atom_DesktopWindow; static Atom atom_NetSupported; static Atom kde_xdnd_drop; #endif template class QList; #ifdef Q_OS_WIN void KApplication_init_windows(); #endif static KApplicationPrivate *kapp_priv = nullptr; /* Private data to make keeping binary compatibility easier */ class KApplicationPrivate { public: KApplicationPrivate(KApplication *q, const QByteArray &cName) : q(q) , componentData(cName) , session_save(false) #if HAVE_X11 , oldIceIOErrorHandler(nullptr) , oldXErrorHandler(nullptr) , oldXIOErrorHandler(nullptr) , isX11(false) #endif , pSessionConfig(nullptr) , bSessionManagement(true) { kapp_priv = this; } KApplicationPrivate(KApplication *q, const KComponentData &cData) : q(q) , componentData(cData) , session_save(false) #if HAVE_X11 , oldIceIOErrorHandler(nullptr) , oldXErrorHandler(nullptr) , oldXIOErrorHandler(nullptr) , isX11(false) #endif , pSessionConfig(nullptr) , bSessionManagement(true) { kapp_priv = this; } KApplicationPrivate(KApplication *q) : q(q) , componentData(KCmdLineArgs::aboutData()) , session_save(false) #if HAVE_X11 , oldIceIOErrorHandler(nullptr) , oldXErrorHandler(nullptr) , oldXIOErrorHandler(nullptr) , isX11(false) #endif , pSessionConfig(nullptr) , bSessionManagement(true) { kapp_priv = this; } ~KApplicationPrivate() { } #ifndef KDE3_SUPPORT KConfig *config() { return KSharedConfig::openConfig().data(); } #endif #if HAVE_X11 int xErrhandler(Display *, void *); int xioErrhandler(Display *); void iceIOErrorHandler(_IceConn *conn); #endif void _k_x11FilterDestroyed(); void _k_slot_KToolInvocation_hook(QStringList &, QByteArray &); void init(bool GUIenabled = true); void parseCommandLine(); // Handle KDE arguments (Using KCmdLineArgs) KApplication *q; KComponentData componentData; bool session_save; #if HAVE_X11 IceIOErrorHandler oldIceIOErrorHandler; int (*oldXErrorHandler)(Display *, XErrorEvent *); int (*oldXIOErrorHandler)(Display *); bool isX11; #endif QString sessionKey; QString pSessionConfigFile; KConfig *pSessionConfig; //instance specific application config object bool bSessionManagement; }; #if HAVE_X11 extern "C" { static int kde_xio_errhandler(Display *dpy) { return kapp_priv->xioErrhandler(dpy); } static int kde_x_errhandler(Display *dpy, XErrorEvent *err) { return kapp_priv->xErrhandler(dpy, err); } } #endif static QList< QPointer< QWidget > > *x11Filter = nullptr; /** * Installs a handler for the SIGPIPE signal. It is thrown when you write to * a pipe or socket that has been closed. * The handler is installed automatically in the constructor, but you may * need it if your application or component does not have a KApplication * instance. */ static void installSigpipeHandler() { #ifdef Q_OS_UNIX struct sigaction act; act.sa_handler = SIG_IGN; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGPIPE, &act, nullptr); #endif } void KApplication::installX11EventFilter(QWidget *filter) { if (!filter) { return; } if (!x11Filter) { x11Filter = new QList< QPointer< QWidget > >; } connect(filter, SIGNAL(destroyed()), this, SLOT(_k_x11FilterDestroyed())); x11Filter->append(filter); } void KApplicationPrivate::_k_x11FilterDestroyed() { q->removeX11EventFilter(static_cast< const QWidget * >(q->sender())); } void KApplication::removeX11EventFilter(const QWidget *filter) { if (!x11Filter || !filter) { return; } // removeAll doesn't work, creating QPointer to something that's about to be deleted aborts // x11Filter->removeAll( const_cast< QWidget* >( filter )); for (QMutableListIterator< QPointer< QWidget > > it(*x11Filter); it.hasNext(); ) { QWidget *w = it.next().data(); if (w == filter || w == nullptr) { it.remove(); } } if (x11Filter->isEmpty()) { delete x11Filter; x11Filter = nullptr; } } #if HAVE_X11 static SmcConn mySmcConnection = nullptr; #else // FIXME(E): Implement for Qt Embedded // Possibly "steal" XFree86's libSM? #endif KApplication::KApplication(bool GUIenabled) : QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), GUIenabled), d(new KApplicationPrivate(this)) { setApplicationName(d->componentData.componentName()); setOrganizationDomain(d->componentData.aboutData()->organizationDomain()); installSigpipeHandler(); d->init(GUIenabled); } KApplication::KApplication(bool GUIenabled, const KComponentData &cData) : QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), GUIenabled), d(new KApplicationPrivate(this, cData)) { setApplicationName(d->componentData.componentName()); setOrganizationDomain(d->componentData.aboutData()->organizationDomain()); installSigpipeHandler(); d->init(GUIenabled); } #if HAVE_X11 int KApplicationPrivate::xioErrhandler(Display *dpy) { oldXIOErrorHandler(dpy); exit(1); return 0; } int KApplicationPrivate::xErrhandler(Display *dpy, void *err_) { XErrorEvent *err = static_cast< XErrorEvent * >(err_); if (kapp) { // add KDE specific stuff here oldXErrorHandler(dpy, err); } const QByteArray fatalXError = qgetenv("KDE_FATAL_X_ERROR"); if (!fatalXError.isEmpty()) { abort(); } return 0; } void KApplicationPrivate::iceIOErrorHandler(_IceConn *conn) { if (oldIceIOErrorHandler != nullptr) { (*oldIceIOErrorHandler)(conn); } exit(1); } #endif // (only called by KUniqueApplication, no need to export) bool s_kuniqueapplication_startCalled = false; void KApplicationPrivate::init(bool GUIenabled) { Q_UNUSED(GUIenabled) if ((getuid() != geteuid()) || (getgid() != getegid())) { fprintf(stderr, "The KDE libraries are not designed to run with suid privileges.\n"); ::exit(127); } #ifdef Q_OS_MAC mac_initialize_dbus(); #endif KApplication::KApp = q; extern KDELIBS4SUPPORT_DEPRECATED_EXPORT bool kde_kdebug_enable_dbus_interface; kde_kdebug_enable_dbus_interface = true; parseCommandLine(); QGuiApplication::setDesktopSettingsAware(false); QGuiApplication::setFallbackSessionManagementEnabled(false); #if HAVE_X11 isX11 = (QGuiApplication::platformName() == QStringLiteral("xcb")); if (isX11) { // create all required atoms in _one_ roundtrip to the X server const int max = 20; Atom *atoms[max]; char *names[max]; Atom atoms_return[max]; int n = 0; atoms[n] = &atom_DesktopWindow; names[n++] = (char *) "KDE_DESKTOP_WINDOW"; atoms[n] = &atom_NetSupported; names[n++] = (char *) "_NET_SUPPORTED"; atoms[n] = &kde_xdnd_drop; names[n++] = (char *) "XdndDrop"; XInternAtoms(QX11Info::display(), names, n, false, atoms_return); for (int i = 0; i < n; i++) { *atoms[i] = atoms_return[i]; } } #endif // sanity checking, to make sure we've connected extern void qDBusBindToApplication(); qDBusBindToApplication(); QDBusConnectionInterface *bus = nullptr; if (!QDBusConnection::sessionBus().isConnected() || !(bus = QDBusConnection::sessionBus().interface())) { kFatal(240) << "Session bus not found" << endl << "To circumvent this problem try the following command (with Linux and bash)" << endl << "export $(dbus-launch)"; ::exit(125); } if (bus && !s_kuniqueapplication_startCalled) { // don't register again if KUniqueApplication did so already QStringList parts = q->organizationDomain().split(QLatin1Char('.'), QString::SkipEmptyParts); QString reversedDomain; if (parts.isEmpty()) { reversedDomain = QLatin1String("local."); } else foreach (const QString &s, parts) { reversedDomain.prepend(QLatin1Char('.')); reversedDomain.prepend(s); } const QString pidSuffix = QString::number(getpid()).prepend(QLatin1String("-")); const QString serviceName = reversedDomain + q->applicationName() + pidSuffix; if (bus->registerService(serviceName) == QDBusConnectionInterface::ServiceNotRegistered) { kError(240) << "Couldn't register name '" << serviceName << "' with DBUS - another process owns it already!" << endl; ::exit(126); } } QDBusConnection::sessionBus().registerObject(QLatin1String("/MainApplication"), q, QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportScriptableProperties | QDBusConnection::ExportAdaptors); // Trigger creation of locale. (void) KLocale::global(); KSharedConfig::Ptr config = componentData.config(); QByteArray readOnly = qgetenv("KDE_HOME_READONLY"); if (readOnly.isEmpty() && q->applicationName() != QLatin1String("kdialog")) { if (KAuthorized::authorize(QLatin1String("warn_unwritable_config"))) { config->isConfigWritable(true); } } #if HAVE_X11 if (isX11) { // this is important since we fork() to launch the help (Matthias) fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, FD_CLOEXEC); // set up the fancy (=robust and error ignoring ) KDE xio error handlers (Matthias) oldXErrorHandler = XSetErrorHandler(kde_x_errhandler); oldXIOErrorHandler = XSetIOErrorHandler(kde_xio_errhandler); } #endif // Trigger initial settings KGlobalSettings::self()->activate(); KMessage::setMessageHandler(new KMessageBoxMessageHandler(nullptr)); - KGestureMap::self()->installEventFilterOnMe(q); - q->connect(KToolInvocation::self(), SIGNAL(kapplication_hook(QStringList&,QByteArray&)), q, SLOT(_k_slot_KToolInvocation_hook(QStringList&,QByteArray&))); q->connect(q, SIGNAL(commitDataRequest(QSessionManager&)), q, SLOT(commitData(QSessionManager&))); q->connect(q, SIGNAL(saveStateRequest(QSessionManager&)), q, SLOT(saveState(QSessionManager&))); #ifdef Q_OS_MAC // This is a QSystemTrayIcon instead of K* because we can't be sure q is a QWidget QSystemTrayIcon *trayIcon; //krazy:exclude=qclasses if (QSystemTrayIcon::isSystemTrayAvailable()) { //krazy:exclude=qclasses trayIcon = new QSystemTrayIcon(q); //krazy:exclude=qclasses trayIcon->setIcon(q->windowIcon()); /* it's counter-intuitive, but once you do setIcon it's already set the dock icon... ->show actually shows an icon in the menu bar too :P */ // trayIcon->show(); } #endif qRegisterMetaType(); qRegisterMetaType >(); qRegisterMetaType >(); #ifdef Q_OS_WIN KApplication_init_windows(); #endif } KApplication *KApplication::kApplication() { return KApp; } KConfig *KApplication::sessionConfig() { return KConfigGui::sessionConfig(); } void KApplication::reparseConfiguration() { KSharedConfig::openConfig()->reparseConfiguration(); } void KApplication::quit() { QApplication::quit(); } void KApplication::disableSessionManagement() { d->bSessionManagement = false; } void KApplication::enableSessionManagement() { d->bSessionManagement = true; #if HAVE_X11 if (!d->isX11) { return; } // Session management support in Qt/KDE is awfully broken. // If konqueror disables session management right after its startup, // and enables it later (preloading stuff), it won't be properly // saved on session shutdown. // I'm not actually sure why it doesn't work, but saveState() // doesn't seem to be called on session shutdown, possibly // because disabling session management after konqueror startup // disabled it somehow. Forcing saveState() here for this application // seems to fix it. if (mySmcConnection) { SmcRequestSaveYourself(mySmcConnection, SmSaveLocal, False, SmInteractStyleAny, False, False); // flush the request IceFlush(SmcGetIceConnection(mySmcConnection)); } #endif } void KApplication::commitData(QSessionManager &sm) { d->session_save = true; bool canceled = false; foreach (KSessionManager *it, KSessionManager::sessionClients()) { if ((canceled = !it->commitData(sm))) { break; } } if (canceled) { sm.cancel(); } if (sm.allowsInteraction()) { QWidgetList donelist, todolist; QWidget *w; commitDataRestart: todolist = QApplication::topLevelWidgets(); for (int i = 0; i < todolist.size(); ++i) { w = todolist.at(i); if (!w) { break; } if (donelist.contains(w)) { continue; } // leave KMainWindows alone because they are handled by KMWSessionManager if (!w->isHidden() && !w->inherits("KMainWindow")) { QCloseEvent e; sendEvent(w, &e); if (!e.isAccepted()) { canceled = true; break; } donelist.append(w); //grab the new list that was just modified by our closeevent goto commitDataRestart; } } } if (!d->bSessionManagement) { sm.setRestartHint(QSessionManager::RestartNever); } else { sm.setRestartHint(QSessionManager::RestartIfRunning); } if (canceled) { sm.cancel(); } d->session_save = false; } #if HAVE_X11 && QT_VERSION < QT_VERSION_CHECK(5, 0, 0) static void checkRestartVersion(QSessionManager &sm) { Display *dpy = QX11Info::display(); Atom type; int format; unsigned long nitems, after; unsigned char *data; if (dpy != NULL && XGetWindowProperty(dpy, RootWindow(dpy, 0), XInternAtom(dpy, "KDE_SESSION_VERSION", False), 0, 1, False, AnyPropertyType, &type, &format, &nitems, &after, &data) == Success) { if (type == XA_CARDINAL && format == 32) { int version = *(long *) data; if (version == KDE_VERSION_MAJOR) { // we run in our native session XFree(data); return; // no need to wrap } } XFree(data); } if (getenv("KDE_SESSION_VERSION") != NULL && atoi(getenv("KDE_SESSION_VERSION")) == KDE_VERSION_MAJOR) { return; // we run in our native session, no need to wrap } #define NUM_TO_STRING2( num ) #num #define NUM_TO_STRING( num ) NUM_TO_STRING2( num ) QString wrapper = QStandardPaths::findExecutable("kde" NUM_TO_STRING(KDE_VERSION_MAJOR)); // "kde4", etc. #undef NUM_TO_STRING #undef NUM_TO_STRING2 if (!wrapper.isEmpty()) { QStringList restartCommand = sm.restartCommand(); restartCommand.prepend(wrapper); sm.setRestartCommand(restartCommand); } } #endif // HAVE_X11 void KApplication::saveState(QSessionManager &sm) { d->session_save = true; #ifdef __GNUC__ #warning TODO: QSessionManager::handle() is gone in Qt5! #endif #if HAVE_X11 && QT_VERSION < QT_VERSION_CHECK(5, 0, 0) static bool firstTime = true; mySmcConnection = (SmcConn) sm.handle(); if (!d->bSessionManagement) { sm.setRestartHint(QSessionManager::RestartNever); d->session_save = false; return; } else { sm.setRestartHint(QSessionManager::RestartIfRunning); } if (firstTime) { firstTime = false; d->session_save = false; return; // no need to save the state. } // remove former session config if still existing, we want a new // and fresh one. Note that we do not delete the config file here, // this is done by the session manager when it executes the // discard commands. In fact it would be harmful to remove the // file here, as the session might be stored under a different // name, meaning the user still might need it eventually. delete d->pSessionConfig; d->pSessionConfig = 0; // tell the session manager about our new lifecycle QStringList restartCommand = sm.restartCommand(); QByteArray multiHead = qgetenv("KDE_MULTIHEAD"); if (multiHead.toLower() == "true") { // if multihead is enabled, we save our -display argument so that // we are restored onto the correct head... one problem with this // is that the display is hard coded, which means we cannot restore // to a different display (ie. if we are in a university lab and try, // try to restore a multihead session, our apps could be started on // someone else's display instead of our own) QByteArray displayname = qgetenv("DISPLAY"); if (! displayname.isNull()) { // only store the command if we actually have a DISPLAY // environment variable restartCommand.append(QLatin1String("-display")); restartCommand.append(QLatin1String(displayname)); } sm.setRestartCommand(restartCommand); } checkRestartVersion(sm); // finally: do session management emit saveYourself(); // for compatibility bool canceled = false; foreach (KSessionManager *it, KSessionManager::sessionClients()) { if (canceled) { break; } canceled = !it->saveState(sm); } // if we created a new session config object, register a proper discard command if (KConfigGui::hasSessionConfig()) { KConfigGui::sessionConfig()->sync(); QStringList discard; discard << QLatin1String("rm") << QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/' + KConfigGui::sessionConfigName(); sm.setDiscardCommand(discard); } else { sm.setDiscardCommand(QStringList(QLatin1String(""))); } if (canceled) { sm.cancel(); } #else Q_UNUSED(sm); #endif d->session_save = false; } bool KApplication::sessionSaving() const { return d->session_save; } void KApplicationPrivate::parseCommandLine() { KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde"); if (args && args->isSet("style")) { extern QString kde_overrideStyle; // see KGlobalSettings QString reqStyle(args->getOption("style").toLower()); if (QStyleFactory::keys().contains(reqStyle, Qt::CaseInsensitive)) { kde_overrideStyle = reqStyle; } else { qWarning() << i18n("The style '%1' was not found", reqStyle); } } if (args && args->isSet("config")) { QString config = args->getOption("config"); componentData.setConfigName(config); } if (args && args->isSet("icon")) { q->setWindowIcon(QIcon::fromTheme(args->getOption("icon"))); } else { q->setWindowIcon(QIcon::fromTheme(componentData.aboutData()->programIconName())); } if (!args) { return; } if (!args->isSet("crashhandler")) { // disable drkonqi (the old way) KCrash::setDrKonqiEnabled(false); } #if HAVE_X11 if (args->isSet("waitforwm")) { Atom type; (void) q->desktop(); // trigger desktop creation, we need PropertyNotify events for the root window int format; unsigned long length, after; unsigned char *data; while (XGetWindowProperty(QX11Info::display(), QX11Info::appRootWindow(), atom_NetSupported, 0, 1, false, AnyPropertyType, &type, &format, &length, &after, &data) != Success || !length) { if (data) { XFree(data); } XEvent event; XWindowEvent(QX11Info::display(), QX11Info::appRootWindow(), PropertyChangeMask, &event); } if (data) { XFree(data); } } #endif #ifndef Q_OS_WIN if (args->isSet("smkey")) { sessionKey = args->getOption("smkey"); } #endif } extern void kDebugCleanup(); KApplication::~KApplication() { #if HAVE_X11 if (d->isX11) { if (d->oldXErrorHandler != nullptr) { XSetErrorHandler(d->oldXErrorHandler); } if (d->oldXIOErrorHandler != nullptr) { XSetIOErrorHandler(d->oldXIOErrorHandler); } if (d->oldIceIOErrorHandler != nullptr) { IceSetIOErrorHandler(d->oldIceIOErrorHandler); } } #endif delete d; KApp = nullptr; #if HAVE_X11 mySmcConnection = nullptr; #endif } #ifdef __GNUC__ #warning TODO kapp->installX11EventFilter needs to be ported to nativeEvent filters. #endif #if 0 // replaced with QWidget::nativeEvent in Qt5 class KAppX11HackWidget: public QWidget { public: bool publicx11Event(XEvent *e) { return x11Event(e); // no such method anymore! } }; bool KApplication::x11EventFilter(XEvent *_event) { if (x11Filter) { foreach (const QPointer< QWidget > &wp, *x11Filter) { if (QWidget *w = wp.data()) if (static_cast(w)->publicx11Event(_event)) { return true; } } } return false; } #endif void KApplication::updateUserTimestamp(int time) { KUserTimestamp::updateUserTimestamp(time); } unsigned long KApplication::userTimestamp() const { return KUserTimestamp::userTimestamp(); } void KApplication::updateRemoteUserTimestamp(const QString &service, int time) { #if HAVE_X11 if (!d->isX11) { return; } Q_ASSERT(service.contains('.')); if (time == 0) { time = QX11Info::appUserTime(); } QDBusInterface(service, QLatin1String("/MainApplication"), QString(QLatin1String("org.kde.KApplication"))) .call(QLatin1String("updateUserTimestamp"), time); #endif } #ifndef KDELIBS4SUPPORT_NO_DEPRECATED QString KApplication::tempSaveName(const QString &pFilename) { QString aFilename; if (QDir::isRelativePath(pFilename)) { kWarning(240) << "Relative filename passed to KApplication::tempSaveName"; aFilename = QFileInfo(QDir(QLatin1String(".")), pFilename).absoluteFilePath(); } else { aFilename = pFilename; } QDir aAutosaveDir(QDir::homePath() + QLatin1String("/autosave/")); if (!aAutosaveDir.exists()) { if (!aAutosaveDir.mkdir(aAutosaveDir.absolutePath())) { // Last chance: use temp dir aAutosaveDir.setPath(QDir::tempPath()); } } aFilename.replace('/', QLatin1String("\\!")) .prepend(QLatin1Char('#')) .append(QLatin1Char('#')) .prepend(QLatin1Char('/')).prepend(aAutosaveDir.absolutePath()); return aFilename; } #endif QString KApplication::checkRecoverFile(const QString &pFilename, bool &bRecover) { QString aFilename; if (QDir::isRelativePath(pFilename)) { kWarning(240) << "Relative filename passed to KApplication::tempSaveName"; aFilename = QFileInfo(QDir(QLatin1String(".")), pFilename).absoluteFilePath(); } else { aFilename = pFilename; } QDir aAutosaveDir(QDir::homePath() + QLatin1String("/autosave/")); if (!aAutosaveDir.exists()) { if (!aAutosaveDir.mkdir(aAutosaveDir.absolutePath())) { // Last chance: use temp dir aAutosaveDir.setPath(QDir::tempPath()); } } aFilename.replace(QLatin1String("/"), QLatin1String("\\!")) .prepend(QLatin1Char('#')) .append(QLatin1Char('#')) .prepend(QLatin1Char('/')) .prepend(aAutosaveDir.absolutePath()); if (QFile(aFilename).exists()) { bRecover = true; return aFilename; } else { bRecover = false; return pFilename; } } void KApplication::setTopWidget(QWidget *topWidget) { if (!topWidget) { return; } // set the specified caption if (!topWidget->inherits("KMainWindow")) { // KMainWindow does this already for us topWidget->setWindowTitle(KGlobal::caption()); } #if HAVE_X11 // set the app startup notification window property KStartupInfo::setWindowStartupId(topWidget->winId(), startupId()); #endif } QByteArray KApplication::startupId() const { return KStartupInfo::startupId(); } void KApplication::setStartupId(const QByteArray &startup_id) { KStartupInfo::setStartupId(startup_id); } void KApplication::clearStartupId() { KStartupInfo::setStartupId("0"); } // Hook called by KToolInvocation void KApplicationPrivate::_k_slot_KToolInvocation_hook(QStringList &envs, QByteArray &startup_id) { #if HAVE_X11 if (!isX11) { return; } if (QX11Info::display()) { QByteArray dpystring(XDisplayString(QX11Info::display())); envs << QLatin1String("DISPLAY=") + dpystring; } else { const QByteArray dpystring(qgetenv("DISPLAY")); if (!dpystring.isEmpty()) { envs << QLatin1String("DISPLAY=") + dpystring; } } if (startup_id.isEmpty()) { startup_id = KStartupInfo::createNewStartupId(); } #else Q_UNUSED(envs); Q_UNUSED(startup_id); #endif } #include "moc_kapplication.cpp"