mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 10:52:49 +00:00

every comment about X11 and session management in general claims it was broken, not going to claim otherwise. everything that does not use KApplication shall not be involved into session management now and gets the middle finger (SIGTERM or SIGKILL) after 5 sec by klauncher when the session is done also session management has to be explicitly enabled by applications now, disabled by default Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
767 lines
22 KiB
C++
767 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 <X11/SM/SMlib.h>
|
|
# include <fixx11h.h>
|
|
#endif
|
|
|
|
KApplication* KApplication::KApp = 0L;
|
|
|
|
static const int s_quit_signals[] = {
|
|
SIGTERM,
|
|
SIGHUP,
|
|
SIGINT,
|
|
0
|
|
};
|
|
|
|
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;
|
|
}
|
|
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";
|
|
}
|
|
}
|
|
|
|
/*
|
|
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 = QString::fromLatin1("%1_%2").arg(QCoreApplication::applicationName()).arg(QCoreApplication::applicationPid());
|
|
}
|
|
d->pSessionConfig = new KConfig(
|
|
QString::fromLatin1("session/%1").arg(configName),
|
|
KConfig::SimpleConfig
|
|
);
|
|
}
|
|
return d->pSessionConfig;
|
|
}
|
|
|
|
bool KApplication::saveSession()
|
|
{
|
|
foreach (KMainWindow *window, KMainWindow::memberList()) {
|
|
if (!window->testAttribute(Qt::WA_WState_Hidden)) {
|
|
QCloseEvent e;
|
|
QApplication::sendEvent(window, &e);
|
|
if (!e.isAccepted()) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
foreach (QWidget* widget, QApplication::topLevelWidgets()) {
|
|
if (!widget || widget->isHidden() || widget->inherits("QMainWindow")) {
|
|
continue;
|
|
}
|
|
QCloseEvent e;
|
|
QApplication::sendEvent(widget, &e);
|
|
if (!e.isAccepted()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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"
|