mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 18:32:49 +00:00

comes with a warning, session management is tricky but it works like a charm now Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
780 lines
22 KiB
C++
780 lines
22 KiB
C++
/* 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 <config.h>
|
|
|
|
#include <QtCore/QDir>
|
|
#include <QtCore/QFile>
|
|
#include <QtCore/QTimer>
|
|
#include <QtCore/QList>
|
|
#include <QtCore/QMetaType>
|
|
#include <QtGui/QStyleFactory>
|
|
#include <QtGui/QWidget>
|
|
#include <QtGui/QCloseEvent>
|
|
#include <QtGui/QX11Info>
|
|
#include <QtDBus/QDBusInterface>
|
|
#include <QtDBus/QDBusConnectionInterface>
|
|
|
|
#include "kaboutdata.h"
|
|
#include "kcrash.h"
|
|
#include "kconfig.h"
|
|
#include "kcmdlineargs.h"
|
|
#include "kglobalsettings.h"
|
|
#include "kdebug.h"
|
|
#include "kglobal.h"
|
|
#include "kicon.h"
|
|
#include "kiconloader.h"
|
|
#include "klocale.h"
|
|
#include "kstandarddirs.h"
|
|
#include "kstandardshortcut.h"
|
|
#include "kurl.h"
|
|
#include "kwindowsystem.h"
|
|
#include "kde_file.h"
|
|
#include "kstartupinfo.h"
|
|
#include "kcomponentdata.h"
|
|
#include "kmainwindow.h"
|
|
#include "kmenu.h"
|
|
#include "kconfiggroup.h"
|
|
#include "kactioncollection.h"
|
|
#include "kdebugger.h"
|
|
#include "kapplication_adaptor.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef Q_WS_X11
|
|
# include <netwm.h>
|
|
# include <X11/Xlib.h>
|
|
# include <X11/Xutil.h>
|
|
# include <X11/Xatom.h>
|
|
# include <fixx11h.h>
|
|
#endif
|
|
|
|
KApplication* KApplication::KApp = 0L;
|
|
|
|
static const int s_quit_signals[] = {
|
|
SIGTERM,
|
|
SIGHUP,
|
|
SIGINT,
|
|
0
|
|
};
|
|
|
|
static QWidgetList s_asked;
|
|
|
|
static void quit_handler(int sig)
|
|
{
|
|
if (!qApp) {
|
|
KDE_signal(sig, SIG_DFL);
|
|
return;
|
|
}
|
|
|
|
if (qApp->type() == KAPPLICATION_GUI_TYPE) {
|
|
const QWidgetList toplevelwidgets = QApplication::topLevelWidgets();
|
|
if (!toplevelwidgets.isEmpty()) {
|
|
kDebug() << "closing top-level main windows";
|
|
foreach (QWidget* topwidget, toplevelwidgets) {
|
|
if (!topwidget || !topwidget->isWindow() || !topwidget->inherits("QMainWindow")) {
|
|
continue;
|
|
}
|
|
if (s_asked.contains(topwidget)) {
|
|
kDebug() << "already asked" << topwidget;
|
|
continue;
|
|
}
|
|
kDebug() << "closing" << topwidget;
|
|
if (!topwidget->close()) {
|
|
kDebug() << "not quiting because a top-level window did not close";
|
|
return;
|
|
}
|
|
}
|
|
kDebug() << "all top-level main windows closed";
|
|
}
|
|
}
|
|
KDE_signal(sig, SIG_DFL);
|
|
qApp->quit();
|
|
}
|
|
|
|
static void kRegisterSessionClient(const bool enable, const QString &serviceName)
|
|
{
|
|
if (serviceName.isEmpty()) {
|
|
return;
|
|
}
|
|
QDBusInterface sessionManager(
|
|
"org.kde.plasma-desktop", "/App", "local.PlasmaApp",
|
|
QDBusConnection::sessionBus()
|
|
);
|
|
if (sessionManager.isValid()) {
|
|
sessionManager.call(enable ? "registerClient" : "unregisterClient", serviceName);
|
|
} else {
|
|
kWarning() << "org.kde.plasma-desktop is not valid interface";
|
|
}
|
|
}
|
|
|
|
static QString kSessionConfigName()
|
|
{
|
|
return QString::fromLatin1("%1_%2").arg(QCoreApplication::applicationName()).arg(QCoreApplication::applicationPid());
|
|
}
|
|
|
|
/*
|
|
Private data
|
|
*/
|
|
class KApplicationPrivate
|
|
{
|
|
public:
|
|
KApplicationPrivate(KApplication* q, const QByteArray &cName)
|
|
: q(q)
|
|
, adaptor(nullptr)
|
|
, componentData(cName)
|
|
, startup_id("0")
|
|
, app_started_timer(nullptr)
|
|
, session_save(false)
|
|
, pSessionConfig(nullptr)
|
|
, bSessionManagement(false)
|
|
, debugger(nullptr)
|
|
{
|
|
}
|
|
|
|
KApplicationPrivate(KApplication* q, const KComponentData &cData)
|
|
: q(q)
|
|
, adaptor(nullptr)
|
|
, componentData(cData)
|
|
, startup_id("0")
|
|
, app_started_timer(nullptr)
|
|
, session_save(false)
|
|
, pSessionConfig(nullptr)
|
|
, bSessionManagement(false)
|
|
, debugger(nullptr)
|
|
{
|
|
}
|
|
|
|
KApplicationPrivate(KApplication *q)
|
|
: q(q)
|
|
, adaptor(nullptr)
|
|
, componentData(KCmdLineArgs::aboutData())
|
|
, startup_id("0")
|
|
, app_started_timer(nullptr)
|
|
, session_save(false)
|
|
, pSessionConfig(nullptr)
|
|
, bSessionManagement(false)
|
|
, debugger(nullptr)
|
|
{
|
|
}
|
|
|
|
void _k_x11FilterDestroyed();
|
|
void _k_checkAppStartedSlot();
|
|
void _k_aboutToQuitSlot();
|
|
|
|
void init();
|
|
void parseCommandLine( ); // Handle KDE arguments (Using KCmdLineArgs)
|
|
|
|
KApplication *q;
|
|
|
|
KApplicationAdaptor* adaptor;
|
|
QString serviceName;
|
|
KComponentData componentData;
|
|
QByteArray startup_id;
|
|
QTimer* app_started_timer;
|
|
|
|
bool session_save;
|
|
QString sessionKey;
|
|
KConfig* pSessionConfig; //instance specific application config object
|
|
bool bSessionManagement;
|
|
|
|
KDebugger* debugger;
|
|
};
|
|
|
|
static QList< QWeakPointer< QWidget > > *x11Filter = 0;
|
|
|
|
/**
|
|
* 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()
|
|
{
|
|
struct sigaction act;
|
|
act.sa_handler = SIG_IGN;
|
|
sigemptyset(&act.sa_mask);
|
|
act.sa_flags = 0;
|
|
sigaction(SIGPIPE, &act, 0);
|
|
}
|
|
|
|
void KApplication::installX11EventFilter( QWidget* filter )
|
|
{
|
|
if ( !filter )
|
|
return;
|
|
if (!x11Filter)
|
|
x11Filter = new QList< QWeakPointer< 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 QWeakPointer to something that's about to be deleted aborts
|
|
// x11Filter->removeAll( const_cast< QWidget* >( filter ));
|
|
QMutableListIterator< QWeakPointer< QWidget > > it( *x11Filter );
|
|
while (it.hasNext()) {
|
|
QWeakPointer< QWidget > wp = it.next();
|
|
if( wp.isNull() || wp.data() == filter )
|
|
it.remove();
|
|
}
|
|
if ( x11Filter->isEmpty() ) {
|
|
delete x11Filter;
|
|
x11Filter = 0;
|
|
}
|
|
}
|
|
|
|
bool KApplication::notify(QObject *receiver, QEvent *event)
|
|
{
|
|
QEvent::Type t = event->type();
|
|
if( t == QEvent::Show && receiver->isWidgetType())
|
|
{
|
|
QWidget* w = static_cast<QWidget*>(receiver);
|
|
#if defined Q_WS_X11
|
|
if (w->isTopLevel() && !startupId().isEmpty()) {
|
|
// TODO better done using window group leader?
|
|
KStartupInfo::setWindowStartupId(w->winId(), startupId());
|
|
#endif
|
|
}
|
|
if (w->isTopLevel() && !( w->windowFlags() & Qt::X11BypassWindowManagerHint )
|
|
&& w->windowType() != Qt::Popup && !event->spontaneous())
|
|
{
|
|
if (!d->app_started_timer) {
|
|
d->app_started_timer = new QTimer(this);
|
|
connect(d->app_started_timer, SIGNAL(timeout()), SLOT(_k_checkAppStartedSlot()));
|
|
}
|
|
if (!d->app_started_timer->isActive()) {
|
|
d->app_started_timer->setSingleShot(true);
|
|
d->app_started_timer->start(0);
|
|
}
|
|
}
|
|
}
|
|
return QApplication::notify(receiver, event);
|
|
}
|
|
|
|
void KApplicationPrivate::_k_checkAppStartedSlot()
|
|
{
|
|
#if defined Q_WS_X11
|
|
KStartupInfo::handleAutoAppStartedSending();
|
|
#endif
|
|
|
|
// at this point all collections should be set, now is the time to read ther configuration
|
|
// because it is not done anywhere else. unfortunately that magic also means any collections
|
|
// created afterwards will need an explicit settings read
|
|
foreach (KActionCollection* collection, KActionCollection::allCollections()) {
|
|
collection->readSettings();
|
|
}
|
|
}
|
|
|
|
KApplication::KApplication()
|
|
: QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv()),
|
|
d(new KApplicationPrivate(this))
|
|
{
|
|
setApplicationName(d->componentData.componentName());
|
|
setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
|
|
setApplicationVersion(d->componentData.aboutData()->version());
|
|
installSigpipeHandler();
|
|
d->init();
|
|
}
|
|
|
|
#ifdef Q_WS_X11
|
|
KApplication::KApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap)
|
|
: QApplication(dpy, KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), visual, colormap),
|
|
d(new KApplicationPrivate(this))
|
|
{
|
|
setApplicationName(d->componentData.componentName());
|
|
setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
|
|
setApplicationVersion(d->componentData.aboutData()->version());
|
|
installSigpipeHandler();
|
|
d->init();
|
|
}
|
|
|
|
KApplication::KApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap, const KComponentData &cData)
|
|
: QApplication(dpy, KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), visual, colormap),
|
|
d (new KApplicationPrivate(this, cData))
|
|
{
|
|
setApplicationName(d->componentData.componentName());
|
|
setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
|
|
setApplicationVersion(d->componentData.aboutData()->version());
|
|
installSigpipeHandler();
|
|
d->init();
|
|
}
|
|
#endif
|
|
|
|
KApplication::KApplication(const KComponentData &cData)
|
|
: QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv()),
|
|
d (new KApplicationPrivate(this, cData))
|
|
{
|
|
setApplicationName(d->componentData.componentName());
|
|
setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
|
|
setApplicationVersion(d->componentData.aboutData()->version());
|
|
installSigpipeHandler();
|
|
d->init();
|
|
}
|
|
|
|
#ifdef Q_WS_X11
|
|
KApplication::KApplication(Display *display, int& argc, char** argv, const QByteArray& rAppName)
|
|
: QApplication(display),
|
|
d(new KApplicationPrivate(this, rAppName))
|
|
{
|
|
setApplicationName(QString::fromLocal8Bit(rAppName.constData(), rAppName.size()));
|
|
installSigpipeHandler();
|
|
KCmdLineArgs::initIgnore(argc, argv, rAppName);
|
|
d->init();
|
|
}
|
|
#endif
|
|
|
|
void KApplicationPrivate::init()
|
|
{
|
|
if ((getuid() != geteuid()) ||
|
|
(getgid() != getegid()))
|
|
{
|
|
fprintf(stderr, "The KDE libraries are not designed to run with suid privileges.\n");
|
|
::exit(127);
|
|
}
|
|
|
|
|
|
KApplication::KApp = q;
|
|
|
|
// make sure the clipboard is created before setting the window icon (bug 209263)
|
|
(void) QApplication::clipboard();
|
|
|
|
#if defined Q_WS_X11
|
|
KStartupInfoId id = KStartupInfo::currentStartupIdEnv();
|
|
KStartupInfo::resetStartupEnv();
|
|
startup_id = id.id();
|
|
#endif
|
|
|
|
parseCommandLine();
|
|
|
|
// sanity checking, to make sure we've connected
|
|
QDBusConnection sessionBus = QDBusConnection::sessionBus();
|
|
QDBusConnectionInterface *bus = 0;
|
|
if (!sessionBus.isConnected() || !(bus = sessionBus.interface())) {
|
|
kFatal() << "Session bus not found, to circumvent this problem try the following command (with Linux and bash)\n"
|
|
<< "export $(dbus-launch)";
|
|
::exit(125);
|
|
}
|
|
|
|
extern bool s_kuniqueapplication_startCalled;
|
|
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("-") );
|
|
serviceName = reversedDomain + QCoreApplication::applicationName() + pidSuffix;
|
|
if ( bus->registerService(serviceName) == QDBusConnectionInterface::ServiceNotRegistered ) {
|
|
kError() << "Couldn't register name '" << serviceName << "' with DBUS - another process owns it already!";
|
|
::exit(126);
|
|
}
|
|
}
|
|
adaptor = new KApplicationAdaptor(q);
|
|
sessionBus.registerObject(QLatin1String("/MainApplication"), q,
|
|
QDBusConnection::ExportScriptableSlots |
|
|
QDBusConnection::ExportScriptableProperties |
|
|
QDBusConnection::ExportAdaptors);
|
|
|
|
// Trigger creation of locale.
|
|
(void) KGlobal::locale();
|
|
|
|
KSharedConfig::Ptr config = componentData.config();
|
|
QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
|
|
if (readOnly.isEmpty() && QCoreApplication::applicationName() != QLatin1String("kdialog"))
|
|
{
|
|
config->isConfigWritable(true);
|
|
}
|
|
|
|
if (q->type() == KAPPLICATION_GUI_TYPE)
|
|
{
|
|
#ifdef Q_WS_X11
|
|
// this is important since we fork() to launch the help (Matthias)
|
|
fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, FD_CLOEXEC);
|
|
#endif
|
|
|
|
// Trigger initial settings
|
|
KGlobalSettings::self()->activate(
|
|
KGlobalSettings::ApplySettings | KGlobalSettings::ListenForChanges
|
|
);
|
|
}
|
|
|
|
// too late to restart if the application is about to quit (e.g. if QApplication::quit() was
|
|
// called or SIGTERM was received)
|
|
q->connect(q, SIGNAL(aboutToQuit()), SLOT(_k_aboutToQuitSlot()));
|
|
|
|
KApplication::quitOnSignal();
|
|
KApplication::quitOnDisconnected();
|
|
|
|
qRegisterMetaType<KUrl>();
|
|
qRegisterMetaType<KUrl::List>();
|
|
}
|
|
|
|
KApplication* KApplication::kApplication()
|
|
{
|
|
return KApp;
|
|
}
|
|
|
|
KConfig* KApplication::sessionConfig()
|
|
{
|
|
if (!d->pSessionConfig) {
|
|
// create an instance specific config object
|
|
QString configName = d->sessionKey;
|
|
if (configName.isEmpty()) {
|
|
configName = kSessionConfigName();
|
|
}
|
|
d->pSessionConfig = new KConfig(
|
|
QString::fromLatin1("session/%1").arg(configName),
|
|
KConfig::SimpleConfig
|
|
);
|
|
}
|
|
return d->pSessionConfig;
|
|
}
|
|
|
|
bool KApplication::saveSession()
|
|
{
|
|
s_asked.clear();
|
|
foreach (QWidget* topwidget, QApplication::topLevelWidgets()) {
|
|
if (!topwidget || !topwidget->isWindow() || !topwidget->inherits("QMainWindow")) {
|
|
continue;
|
|
}
|
|
QCloseEvent e;
|
|
QApplication::sendEvent(topwidget, &e);
|
|
if (!e.isAccepted()) {
|
|
s_asked.clear();
|
|
return false;
|
|
}
|
|
s_asked.append(topwidget);
|
|
}
|
|
|
|
if (d->pSessionConfig) {
|
|
// the config is used for restoring and saving, set it up for saving
|
|
delete d->pSessionConfig;
|
|
d->pSessionConfig = new KConfig(
|
|
QString::fromLatin1("session/%1").arg(kSessionConfigName()),
|
|
KConfig::SimpleConfig
|
|
);
|
|
}
|
|
|
|
d->session_save = true;
|
|
KConfig* config = KApplication::kApplication()->sessionConfig();
|
|
if ( KMainWindow::memberList().count() ){
|
|
// According to Jochen Wilhelmy <digisnap@cs.tu-berlin.de>, this
|
|
// hook is useful for better document orientation
|
|
KMainWindow::memberList().first()->saveGlobalProperties(config);
|
|
}
|
|
int n = 0;
|
|
foreach (KMainWindow* mw, KMainWindow::memberList()) {
|
|
n++;
|
|
mw->savePropertiesInternal(config, n);
|
|
}
|
|
KConfigGroup group( config, "Number" );
|
|
group.writeEntry("NumberOfWindows", n );
|
|
if ( d->pSessionConfig ) {
|
|
d->pSessionConfig->sync();
|
|
}
|
|
d->session_save = false;
|
|
return true;
|
|
}
|
|
|
|
void KApplication::reparseConfiguration()
|
|
{
|
|
KGlobal::config()->reparseConfiguration();
|
|
}
|
|
|
|
void KApplication::quit()
|
|
{
|
|
QApplication::quit();
|
|
}
|
|
|
|
void KApplication::disableSessionManagement()
|
|
{
|
|
if (d->bSessionManagement) {
|
|
kRegisterSessionClient(false, d->serviceName);
|
|
}
|
|
d->bSessionManagement = false;
|
|
}
|
|
|
|
void KApplication::enableSessionManagement()
|
|
{
|
|
kRegisterSessionClient(true, d->serviceName);
|
|
d->bSessionManagement = true;
|
|
}
|
|
|
|
bool KApplication::sessionSaving() const
|
|
{
|
|
return d->session_save;
|
|
}
|
|
|
|
bool KApplication::isSessionRestored() const
|
|
{
|
|
return !d->sessionKey.isEmpty();
|
|
}
|
|
|
|
void KApplicationPrivate::parseCommandLine( )
|
|
{
|
|
KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
|
|
|
|
if (args && args->isSet("config"))
|
|
{
|
|
QString config = args->getOption("config");
|
|
componentData.setConfigName(config);
|
|
}
|
|
|
|
if ( q->type() != KApplication::Tty ) {
|
|
QString appicon;
|
|
if (args && args->isSet("icon")
|
|
&& !args->getOption("icon").trimmed().isEmpty()
|
|
&& !KIconLoader::global()->iconPath(args->getOption("icon"), -1, true).isEmpty())
|
|
{
|
|
appicon = args->getOption("icon");
|
|
}
|
|
if(appicon.isEmpty()) {
|
|
appicon = componentData.aboutData()->programIconName();
|
|
}
|
|
q->setWindowIcon(KIcon(appicon));
|
|
}
|
|
|
|
if (!args)
|
|
return;
|
|
|
|
if (qgetenv("KDE_DEBUG").isEmpty() && args->isSet("crashhandler")) {
|
|
// setup default crash handler
|
|
KCrash::setFlags(KCrash::Notify | KCrash::Log);
|
|
}
|
|
|
|
#ifdef Q_WS_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;
|
|
Atom netSupported = XInternAtom(QX11Info::display(), "_NET_SUPPORTED", False);
|
|
while (XGetWindowProperty(QX11Info::display(), QX11Info::appRootWindow(), netSupported,
|
|
0, 1, false, AnyPropertyType, &type, &format, &length, &after, &data) != Success || !length)
|
|
{
|
|
if (data) {
|
|
XFree(data);
|
|
}
|
|
data = nullptr;
|
|
XEvent event;
|
|
XWindowEvent(QX11Info::display(), QX11Info::appRootWindow(), PropertyChangeMask, &event);
|
|
}
|
|
if (data) {
|
|
XFree(data);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (args->isSet("session")) {
|
|
sessionKey = args->getOption("session");
|
|
}
|
|
|
|
if (args->isSet("debugger")) {
|
|
debugger = new KDebugger();
|
|
debugger->show();
|
|
}
|
|
}
|
|
|
|
KApplication::~KApplication()
|
|
{
|
|
if (d->debugger) {
|
|
delete d->debugger;
|
|
}
|
|
|
|
if (d->pSessionConfig) {
|
|
delete d->pSessionConfig;
|
|
}
|
|
|
|
delete d;
|
|
KApp = 0;
|
|
}
|
|
|
|
|
|
#ifdef Q_WS_X11
|
|
class KAppX11HackWidget: public QWidget
|
|
{
|
|
public:
|
|
bool publicx11Event( XEvent * e) { return x11Event( e ); }
|
|
};
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef Q_WS_X11
|
|
bool KApplication::x11EventFilter( XEvent *_event )
|
|
{
|
|
if (x11Filter) {
|
|
// either deep-copy or mutex
|
|
QListIterator< QWeakPointer< QWidget > > it( *x11Filter );
|
|
while (it.hasNext()) {
|
|
QWeakPointer< QWidget > wp = it.next();
|
|
if( !wp.isNull() )
|
|
if ( static_cast<KAppX11HackWidget*>( wp.data() )->publicx11Event(_event))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif // Q_WS_X11
|
|
|
|
void KApplication::updateUserTimestamp( int time )
|
|
{
|
|
#if defined Q_WS_X11
|
|
if( time == 0 )
|
|
{ // get current X timestamp
|
|
Window w = XCreateSimpleWindow( QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0, 0, 0 );
|
|
XSelectInput( QX11Info::display(), w, PropertyChangeMask );
|
|
unsigned char data[ 1 ];
|
|
XChangeProperty( QX11Info::display(), w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
|
|
XEvent ev;
|
|
XWindowEvent( QX11Info::display(), w, PropertyChangeMask, &ev );
|
|
time = ev.xproperty.time;
|
|
XDestroyWindow( QX11Info::display(), w );
|
|
}
|
|
if( QX11Info::appUserTime() == 0
|
|
|| NET::timestampCompare( time, QX11Info::appUserTime()) > 0 ) // time > appUserTime
|
|
QX11Info::setAppUserTime(time);
|
|
if( QX11Info::appTime() == 0
|
|
|| NET::timestampCompare( time, QX11Info::appTime()) > 0 ) // time > appTime
|
|
QX11Info::setAppTime(time);
|
|
#endif
|
|
}
|
|
|
|
unsigned long KApplication::userTimestamp() const
|
|
{
|
|
#if defined Q_WS_X11
|
|
return QX11Info::appUserTime();
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
void KApplication::quitOnSignal()
|
|
{
|
|
sigset_t handlermask;
|
|
::sigemptyset(&handlermask);
|
|
int counter = 0;
|
|
while (s_quit_signals[counter]) {
|
|
KDE_signal(s_quit_signals[counter], quit_handler);
|
|
::sigaddset(&handlermask, s_quit_signals[counter]);
|
|
counter++;
|
|
}
|
|
::sigprocmask(SIG_UNBLOCK, &handlermask, NULL);
|
|
}
|
|
|
|
void KApplication::quitOnDisconnected()
|
|
{
|
|
if (!qApp) {
|
|
kWarning() << "KApplication::quitOnDisconnected() called before application instance is created";
|
|
return;
|
|
}
|
|
QDBusConnection::sessionBus().connect(
|
|
QString(),
|
|
QString::fromLatin1("/org/freedesktop/DBus/Local"),
|
|
QString::fromLatin1("org.freedesktop.DBus.Local"),
|
|
QString::fromLatin1("Disconnected"),
|
|
qApp, SLOT(quit())
|
|
);
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
#ifdef Q_WS_X11
|
|
// set the app startup notification window property
|
|
KStartupInfo::setWindowStartupId(topWidget->winId(), startupId());
|
|
#endif
|
|
}
|
|
|
|
QByteArray KApplication::startupId() const
|
|
{
|
|
return d->startup_id;
|
|
}
|
|
|
|
void KApplication::setStartupId(const QByteArray &startup_id)
|
|
{
|
|
if (startup_id == d->startup_id) {
|
|
return;
|
|
}
|
|
#if defined Q_WS_X11
|
|
KStartupInfo::handleAutoAppStartedSending(); // finish old startup notification if needed
|
|
#endif
|
|
if (startup_id.isEmpty()) {
|
|
d->startup_id = "0";
|
|
} else {
|
|
d->startup_id = startup_id;
|
|
#if defined Q_WS_X11
|
|
KStartupInfoId id;
|
|
id.initId(startup_id);
|
|
long timestamp = id.timestamp();
|
|
if (timestamp != 0) {
|
|
updateUserTimestamp(timestamp);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void KApplication::clearStartupId()
|
|
{
|
|
d->startup_id = "0";
|
|
}
|
|
|
|
void KApplicationPrivate::_k_aboutToQuitSlot()
|
|
{
|
|
KCrash::setFlags(KCrash::flags() & ~KCrash::AutoRestart);
|
|
if (bSessionManagement) {
|
|
kRegisterSessionClient(false, serviceName);
|
|
}
|
|
}
|
|
|
|
#include "moc_kapplication.cpp"
|