1
/* This file is part of the KDE libraries
2
Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
3
Copyright (C) 1998, 1999, 2000 KDE Team
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License as published by the Free Software Foundation; either
8
version 2 of the License, or (at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to
17
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
Boston, MA 02110-1301, USA.
23
#undef QT_NO_TRANSLATION
24
#include <qtranslator.h>
25
#define QT_NO_TRANSLATION
26
#include <qtextedit.h>
27
#include <qdatetime.h>
31
#include <qlineedit.h>
32
#include <qmessagebox.h>
33
#include <qmetaobject.h>
35
#include <qsessionmanager.h>
36
#include <qstylefactory.h>
37
#include <qtextstream.h>
42
#include <QtDBus/QtDBus>
44
#undef QT_NO_TRANSLATION
45
#include "kapplication.h"
46
#define QT_NO_TRANSLATION
47
#include "kauthorized.h"
48
#include "kaboutdata.h"
49
#include "kcheckaccelerators.h"
52
#include "kcmdlineargs.h"
53
#include "kclipboard.h"
54
#include "kglobalsettings.h"
57
#include "kiconloader.h"
58
#include "klibloader.h"
60
#include "ksessionmanager.h"
61
#include "kstandarddirs.h"
62
#include "kstandardshortcut.h"
63
#include "ktoolinvocation.h"
66
#include <QtGui/qx11info_x11.h>
67
#include <kstartupinfo.h>
70
#include <sys/types.h>
71
#ifdef HAVE_SYS_STAT_H
81
#include <stdlib.h> // getenv(), srand(), rand()
90
//#ifndef Q_WS_QWS //FIXME(E): NetWM should talk to QWS...
100
#include <X11/Xutil.h>
101
#include <X11/Xatom.h>
102
#include <X11/SM/SMlib.h>
111
#include <Carbon/Carbon.h>
113
#include <QSystemTrayIcon>
117
#include <QDesktopWidget>
118
#include <QMetaObject>
119
#include <kcomponentdata.h>
121
KApplication* KApplication::KApp = 0L;
122
bool KApplication::loadedByKdeinit = false;
125
static Atom atom_DesktopWindow;
126
static Atom atom_NetSupported;
127
static Atom kde_xdnd_drop;
130
// duplicated from patched Qt, so that there won't be unresolved symbols if Qt gets
131
// replaced by unpatched one
132
KDEUI_EXPORT bool qt_qclipboard_bailout_hack = false;
134
template class QList<KSessionManager*>;
138
static int kde_xio_errhandler( Display * dpy )
140
return kapp->xioErrhandler( dpy );
143
static int kde_x_errhandler( Display *dpy, XErrorEvent *err )
145
return kapp->xErrhandler( dpy, err );
152
void KApplication_init_windows();
156
Private data to make keeping binary compatibility easier
158
class KApplication::Private
161
Private(const QByteArray &cName)
162
: componentData(cName),
163
checkAccelerators(0),
165
app_started_timer(0),
168
, oldIceIOErrorHandler(0)
169
, oldXErrorHandler(0)
170
, oldXIOErrorHandler(0)
175
Private(const KComponentData &cData)
176
: componentData(cData),
177
checkAccelerators(0),
179
app_started_timer(0),
182
, oldIceIOErrorHandler(0)
183
, oldXErrorHandler(0)
184
, oldXIOErrorHandler(0)
190
: componentData(KCmdLineArgs::aboutData()),
191
checkAccelerators(0),
193
app_started_timer( 0 ),
194
session_save( false )
196
,oldIceIOErrorHandler( 0 )
197
,oldXErrorHandler( 0 )
198
,oldXIOErrorHandler( 0 )
207
KComponentData componentData;
208
KCheckAccelerators* checkAccelerators;
209
QByteArray startup_id;
210
QTimer* app_started_timer;
213
IceIOErrorHandler oldIceIOErrorHandler;
214
int (*oldXErrorHandler)(Display*,XErrorEvent*);
215
int (*oldXIOErrorHandler)(Display*);
219
QString pSessionConfigFile;
223
static QList<const QWidget*> *x11Filter = 0;
226
* Installs a handler for the SIGPIPE signal. It is thrown when you write to
227
* a pipe or socket that has been closed.
228
* The handler is installed automatically in the constructor, but you may
229
* need it if your application or component does not have a KApplication
232
static void installSigpipeHandler()
235
struct sigaction act;
236
act.sa_handler = SIG_IGN;
237
sigemptyset( &act.sa_mask );
239
sigaction( SIGPIPE, &act, 0 );
243
void KApplication::installX11EventFilter( QWidget* filter )
248
x11Filter = new QList<const QWidget *>;
249
connect ( filter, SIGNAL( destroyed() ), this, SLOT( x11FilterDestroyed() ) );
250
x11Filter->append( filter );
253
void KApplication::x11FilterDestroyed()
255
removeX11EventFilter( static_cast< const QWidget* >( sender()));
258
void KApplication::removeX11EventFilter( const QWidget* filter )
260
if ( !x11Filter || !filter )
262
x11Filter->removeAll( filter );
263
if ( x11Filter->isEmpty() ) {
269
bool KApplication::notify(QObject *receiver, QEvent *event)
271
QEvent::Type t = event->type();
272
if( t == QEvent::Show && receiver->isWidgetType())
274
QWidget* w = static_cast< QWidget* >( receiver );
276
if( w->isTopLevel() && !startupId().isEmpty()) // TODO better done using window group leader?
277
KStartupInfo::setWindowStartupId( w->winId(), startupId());
279
if( w->isTopLevel() && !( w->windowFlags() & Qt::X11BypassWindowManagerHint ) && w->windowType() != Qt::Popup && !event->spontaneous())
281
if( d->app_started_timer == NULL )
283
d->app_started_timer = new QTimer( this );
284
connect( d->app_started_timer, SIGNAL( timeout()), SLOT( checkAppStartedSlot()));
286
if( !d->app_started_timer->isActive()) {
287
d->app_started_timer->setSingleShot( true );
288
d->app_started_timer->start( 0 );
292
return QApplication::notify(receiver, event);
295
void KApplication::checkAppStartedSlot()
298
KStartupInfo::handleAutoAppStartedSending();
303
Auxiliary function to calculate a a session config name used for the
304
instance specific config object.
305
Syntax: "session/<appname>_<sessionId>"
307
QString KApplication::sessionConfigName() const
309
#ifdef QT_NO_SESSIONMANAGER
310
#error QT_NO_SESSIONMANAGER was set, this will not compile. Reconfigure Qt with Session management support.
312
QString sessKey = sessionKey();
313
if ( sessKey.isEmpty() && !d->sessionKey.isEmpty() )
314
sessKey = d->sessionKey;
315
return QString(QLatin1String("session/%1_%2_%3")).arg(applicationName()).arg(sessionId()).arg(sessKey);
319
static SmcConn mySmcConnection = 0;
321
// FIXME(E): Implement for Qt Embedded
322
// Possibly "steal" XFree86's libSM?
325
KApplication::KApplication(bool GUIenabled)
326
: QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), GUIenabled),
329
read_app_startup_id();
330
setApplicationName(QLatin1String(d->componentData.componentName()));
331
setOrganizationDomain( KCmdLineArgs::about->organizationDomain() );
332
installSigpipeHandler();
337
KApplication::KApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap)
338
: QApplication(dpy, KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), visual, colormap),
341
read_app_startup_id();
342
setApplicationName(QLatin1String(d->componentData.componentName()));
343
setOrganizationDomain( KCmdLineArgs::about->organizationDomain() );
344
installSigpipeHandler();
348
KApplication::KApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap, const KComponentData &cData)
349
: QApplication(dpy, KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), visual, colormap),
350
d (new Private(cData))
352
read_app_startup_id();
353
setApplicationName(QLatin1String(d->componentData.componentName()));
354
setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
355
installSigpipeHandler();
360
KApplication::KApplication(bool GUIenabled, const KComponentData &cData)
361
: QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), GUIenabled),
362
d (new Private(cData))
364
read_app_startup_id();
365
setApplicationName(QLatin1String(d->componentData.componentName()));
366
setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
367
installSigpipeHandler();
372
KApplication::KApplication(Display *display, int& argc, char** argv, const QByteArray& rAppName,
374
: QApplication(display),
375
d(new Private(rAppName))
377
Q_UNUSED(GUIenabled);
378
read_app_startup_id();
379
setApplicationName(QLatin1String(rAppName));
380
installSigpipeHandler();
381
KCmdLineArgs::initIgnore(argc, argv, rAppName.data());
386
int KApplication::xioErrhandler( Display* dpy )
392
d->oldXIOErrorHandler( dpy );
401
int KApplication::xErrhandler( Display* dpy, void* err_ )
402
{ // no idea how to make forward decl. for XErrorEvent
404
XErrorEvent* err = static_cast< XErrorEvent* >( err_ );
407
// add KDE specific stuff here
408
d->oldXErrorHandler( dpy, err );
414
void KApplication::iceIOErrorHandler( _IceConn *conn )
419
if ( d->oldIceIOErrorHandler != NULL )
420
(*d->oldIceIOErrorHandler)( conn );
425
class KDETranslator : public QTranslator
428
KDETranslator(QObject *parent) : QTranslator(parent)
430
setObjectName(QLatin1String("kdetranslator"));
433
virtual QString translate(const char* context,
434
const char *sourceText,
435
const char* message) const
437
return KGlobal::locale()->translateQt(context, sourceText, message);
441
void KApplication::init()
443
if ((getuid() != geteuid()) ||
444
(getgid() != getegid()))
446
fprintf(stderr, "The KDE libraries are not designed to run with suid privileges.\n");
450
if ( type() == GuiClient )
452
QStringList plugins = KGlobal::dirs()->resourceDirs( "qtplugins" );
453
QStringList::Iterator it = plugins.begin();
454
while (it != plugins.end()) {
455
addLibraryPath( *it );
464
(void) KClipboardSynchronizer::self();
466
extern KDECORE_EXPORT bool kde_kdebug_enable_dbus_interface;
467
kde_kdebug_enable_dbus_interface = true;
469
QApplication::setDesktopSettingsAware( false );
471
#ifdef Q_WS_X11 //FIXME(E)
472
// create all required atoms in _one_ roundtrip to the X server
473
if ( type() == GuiClient ) {
477
Atom atoms_return[max];
480
atoms[n] = &atom_DesktopWindow;
481
names[n++] = (char *) "KDE_DESKTOP_WINDOW";
483
atoms[n] = &atom_NetSupported;
484
names[n++] = (char *) "_NET_SUPPORTED";
486
atoms[n] = &kde_xdnd_drop;
487
names[n++] = (char *) "XdndDrop";
489
XInternAtoms( QX11Info::display(), names, n, false, atoms_return );
491
for (int i = 0; i < n; i++ )
492
*atoms[i] = atoms_return[i];
497
// sanity checking, to make sure we've connected
498
extern void qDBusBindToApplication();
499
qDBusBindToApplication();
500
QDBusConnectionInterface *bus = 0;
501
if (!QDBusConnection::sessionBus().isConnected() || !(bus = QDBusConnection::sessionBus().interface())) {
502
kFatal(101) << "Session bus not found" << endl;
506
extern bool s_kuniqueapplication_startCalled;
507
if ( !s_kuniqueapplication_startCalled ) // don't register again if KUniqueApplication did so already
509
QStringList parts = organizationDomain().split(QLatin1Char('.'), QString::SkipEmptyParts);
510
QString reversedDomain;
512
reversedDomain = QLatin1String("local.");
514
foreach (const QString& s, parts)
516
reversedDomain.prepend(QLatin1Char('.'));
517
reversedDomain.prepend(s);
519
const QString pidSuffix = QString::number( getpid() ).prepend( QLatin1String("-") );
520
const QString serviceName = reversedDomain + applicationName() + pidSuffix;
521
if ( bus->registerService(serviceName) == QDBusConnectionInterface::ServiceNotRegistered ) {
522
kError(101) << "Couldn't register name '" << serviceName << "' with DBUS - another process owns it already!" << endl;
526
QDBusConnection::sessionBus().registerObject(QLatin1String("/MainApplication"), this,
527
QDBusConnection::ExportScriptableSlots |
528
QDBusConnection::ExportScriptableProperties |
529
QDBusConnection::ExportAdaptors);
531
// Trigger creation of locale.
532
(void) KGlobal::locale();
534
KSharedConfig::Ptr config = d->componentData.config();
535
QByteArray readOnly = getenv("KDE_HOME_READONLY");
536
if (readOnly.isEmpty() && applicationName() != QLatin1String("kdialog"))
538
if (KAuthorized::authorize(QLatin1String("warn_unwritable_config")))
539
config->checkConfigFilesWritable(true);
542
if (type() == GuiClient)
545
// this is important since we fork() to launch the help (Matthias)
546
fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, FD_CLOEXEC);
547
// set up the fancy (=robust and error ignoring ) KDE xio error handlers (Matthias)
548
d->oldXErrorHandler = XSetErrorHandler( kde_x_errhandler );
549
d->oldXIOErrorHandler = XSetIOErrorHandler( kde_xio_errhandler );
552
// Trigger initial settings
553
KGlobalSettings::self();
555
d->checkAccelerators = new KCheckAccelerators( this );
557
connect(KToolInvocation::self(), SIGNAL(kapplication_hook(QStringList&, QByteArray&)),
558
this, SLOT(slot_KToolInvication_hook(QStringList&,QByteArray&)));
562
if (type() == GuiClient) {
563
QSystemTrayIcon *trayIcon;
564
QPixmap pixmap = KIconLoader::global()->loadIcon( KCmdLineArgs::appName(),
565
K3Icon::NoGroup, K3Icon::SizeEnormous, K3Icon::DefaultState, 0L, false );
566
if (!pixmap.isNull() && QSystemTrayIcon::isSystemTrayAvailable())
568
trayIcon = new QSystemTrayIcon(this);
569
trayIcon->setIcon(QIcon(pixmap));
570
/* it's counter-intuitive, but once you do setIcon it's already set the
571
dock icon... ->show actually shows an icon in the menu bar too :P */
578
// save and restore the RTL setting, as installTranslator calls qt_detectRTLLanguage,
579
// which makes it impossible to use the -reverse cmdline switch with KDE apps
580
// FIXME is this still needed? it looks like QApplication takes care of this
581
bool rtl = isRightToLeft();
582
installTranslator(new KDETranslator(this));
583
setLayoutDirection( rtl ? Qt::RightToLeft:Qt::LeftToRight);
584
if (i18nc( "Dear Translator! Translate this string to the string 'LTR' in "
585
"left-to-right languages (as English) or to 'RTL' in right-to-left "
586
"languages (such as Hebrew and Arabic) to get proper widget layout.",
587
"LTR" ) == QLatin1String("RTL"))
589
setLayoutDirection( rtl ? Qt::RightToLeft:Qt::LeftToRight);
592
bSessionManagement = true;
595
KApplication_init_windows();
599
KConfig* KApplication::sessionConfig()
601
if (!pSessionConfig) // create an instance specific config object
602
pSessionConfig = new KConfig( sessionConfigName(), false, false);
603
return pSessionConfig;
606
void KApplication::reparseConfiguration()
608
KGlobal::config()->reparseConfiguration();
611
void KApplication::quit()
613
QApplication::quit();
616
void KApplication::disableSessionManagement() {
617
bSessionManagement = false;
620
void KApplication::enableSessionManagement() {
621
bSessionManagement = true;
623
// Session management support in Qt/KDE is awfully broken.
624
// If konqueror disables session management right after its startup,
625
// and enables it later (preloading stuff), it won't be properly
626
// saved on session shutdown.
627
// I'm not actually sure why it doesn't work, but saveState()
628
// doesn't seem to be called on session shutdown, possibly
629
// because disabling session management after konqueror startup
630
// disabled it somehow. Forcing saveState() here for this application
632
if( mySmcConnection ) {
633
SmcRequestSaveYourself( mySmcConnection, SmSaveLocal, False,
638
IceFlush(SmcGetIceConnection(mySmcConnection));
643
void KApplication::commitData( QSessionManager& sm )
645
d->session_save = true;
646
bool canceled = false;
648
foreach (KSessionManager *it, KSessionManager::sessionClients()) {
649
if ( ( canceled = !it->commitData( sm ) ) )
656
if ( sm.allowsInteraction() ) {
657
QWidgetList donelist, todolist;
661
todolist = QApplication::topLevelWidgets();
663
for ( int i = 0; i < todolist.size(); ++i ) {
664
w = todolist.at( i );
668
if ( donelist.contains( w ) )
671
if ( !w->isHidden() && !w->inherits( "KMainWindow" ) ) {
674
if ( !e.isAccepted() )
677
donelist.append( w );
679
//grab the new list that was just modified by our closeevent
680
goto commitDataRestart;
685
if ( !bSessionManagement )
686
sm.setRestartHint( QSessionManager::RestartNever );
688
sm.setRestartHint( QSessionManager::RestartIfRunning );
689
d->session_save = false;
692
void KApplication::saveState( QSessionManager& sm )
694
d->session_save = true;
696
static bool firstTime = true;
697
mySmcConnection = (SmcConn) sm.handle();
699
if ( !bSessionManagement ) {
700
sm.setRestartHint( QSessionManager::RestartNever );
701
d->session_save = false;
705
sm.setRestartHint( QSessionManager::RestartIfRunning );
709
d->session_save = false;
710
return; // no need to save the state.
713
// remove former session config if still existing, we want a new
714
// and fresh one. Note that we do not delete the config file here,
715
// this is done by the session manager when it executes the
716
// discard commands. In fact it would be harmful to remove the
717
// file here, as the session might be stored under a different
718
// name, meaning the user still might need it eventually.
719
if ( pSessionConfig ) {
720
delete pSessionConfig;
724
// tell the session manager about our new lifecycle
725
QStringList restartCommand = sm.restartCommand();
727
QByteArray multiHead = getenv("KDE_MULTIHEAD");
728
if (multiHead.toLower() == "true") {
729
// if multihead is enabled, we save our -display argument so that
730
// we are restored onto the correct head... one problem with this
731
// is that the display is hard coded, which means we cannot restore
732
// to a different display (ie. if we are in a university lab and try,
733
// try to restore a multihead session, our apps could be started on
734
// someone else's display instead of our own)
735
QByteArray displayname = getenv("DISPLAY");
736
if (! displayname.isNull()) {
737
// only store the command if we actually have a DISPLAY
738
// environment variable
739
restartCommand.append(QLatin1String("-display"));
740
restartCommand.append(QLatin1String(displayname));
742
sm.setRestartCommand( restartCommand );
746
// finally: do session management
747
emit saveYourself(); // for compatibility
748
bool canceled = false;
749
foreach(KSessionManager* it, KSessionManager::sessionClients()) {
751
canceled = !it->saveState( sm );
754
// if we created a new session config object, register a proper discard command
755
if ( pSessionConfig ) {
756
pSessionConfig->sync();
758
discard << QLatin1String("rm") << KStandardDirs::locateLocal("config", sessionConfigName());
759
sm.setDiscardCommand( discard );
761
sm.setDiscardCommand( QStringList( QLatin1String("") ) );
767
// FIXME(E): Implement for Qt Embedded
769
d->session_save = false;
772
bool KApplication::sessionSaving() const
774
return d->session_save;
777
void KApplication::parseCommandLine( )
779
KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
781
if ( type() != Tty ) {
782
if (args && args->isSet("icon"))
784
QPixmap largeIcon = DesktopIcon(QFile::decodeName(args->getOption("icon")));
785
QIcon icon = windowIcon();
786
icon.addPixmap(largeIcon, QIcon::Normal, QIcon::On);
790
QIcon icon = windowIcon();
791
QPixmap largeIcon = DesktopIcon(QFile::decodeName(d->componentData.componentName()));
792
icon.addPixmap(largeIcon, QIcon::Normal, QIcon::On);
800
if (args->isSet("config"))
802
QString config = QString::fromLocal8Bit(args->getOption("config"));
803
d->componentData.setConfigName(config);
806
if (args->isSet("style"))
808
extern KDEUI_EXPORT QString kde_overrideStyle; // see KGlobalSettings. Should we have a static setter?
809
QStringList styles = QStyleFactory::keys();
810
QString reqStyle(QLatin1String(args->getOption("style").toLower()));
812
for (QStringList::ConstIterator it = styles.begin(); it != styles.end(); ++it)
813
if ((*it).toLower() == reqStyle) {
814
kde_overrideStyle = *it;
818
if (kde_overrideStyle.isEmpty())
819
fprintf(stderr, "%s", i18n("The style %1 was not found\n", reqStyle).toLocal8Bit().data());
822
bool nocrashhandler = (getenv("KDE_DEBUG") != NULL);
823
if (!nocrashhandler && args->isSet("crashhandler"))
825
// set default crash handler / set emergency save function to nothing
826
KCrash::setCrashHandler(KCrash::defaultCrashHandler);
827
KCrash::setEmergencySaveFunction(NULL);
829
KCrash::setApplicationName(QLatin1String(args->appName()));
833
if ( args->isSet( "waitforwm" ) ) {
835
(void) desktop(); // trigger desktop creation, we need PropertyNotify events for the root window
837
unsigned long length, after;
839
while ( XGetWindowProperty( QX11Info::display(), QX11Info::appRootWindow(), atom_NetSupported,
840
0, 1, false, AnyPropertyType, &type, &format,
841
&length, &after, &data ) != Success || !length ) {
845
XWindowEvent( QX11Info::display(), QX11Info::appRootWindow(), PropertyChangeMask, &event );
851
// FIXME(E): Implement for Qt Embedded
854
if (args->isSet("smkey"))
856
d->sessionKey = QLatin1String(args->getOption("smkey"));
861
extern void kDebugCleanup();
863
KApplication::~KApplication()
865
// First call the static deleters and then call KLibLoader::cleanup()
866
// The static deleters may delete libraries for which they need KLibLoader.
867
// KLibLoader will take care of the remaining ones.
868
KGlobal::deleteStaticDeleters();
871
if ( d->oldXErrorHandler != NULL )
872
XSetErrorHandler( d->oldXErrorHandler );
873
if ( d->oldXIOErrorHandler != NULL )
874
XSetIOErrorHandler( d->oldXIOErrorHandler );
875
if ( d->oldIceIOErrorHandler != NULL )
876
IceSetIOErrorHandler( d->oldIceIOErrorHandler );
885
// FIXME(E): Implement for Qt Embedded
891
class KAppX11HackWidget: public QWidget
894
bool publicx11Event( XEvent * e) { return x11Event( e ); }
901
bool KApplication::x11EventFilter( XEvent *_event )
903
switch ( _event->type ) {
906
#if KDE_IS_VERSION( 3, 90, 90 )
907
#warning This should be already in Qt, check.
909
// Workaround for focus stealing prevention not working when dragging e.g. text from KWrite
910
// to KDesktop -> the dialog asking for filename doesn't get activated. This is because
911
// Qt-3.2.x doesn't have concept of qt_x_user_time at all, and Qt-3.3.0b1 passes the timestamp
912
// in the XdndDrop message in incorrect field (and doesn't update qt_x_user_time either).
913
// Patch already sent, future Qt version should have this fixed.
914
if( _event->xclient.message_type == kde_xdnd_drop )
915
{ // if the message is XdndDrop
916
if( _event->xclient.data.l[ 1 ] == 1 << 24 // and it's broken the way it's in Qt-3.2.x
917
&& _event->xclient.data.l[ 2 ] == 0
918
&& _event->xclient.data.l[ 4 ] == 0
919
&& _event->xclient.data.l[ 3 ] != 0 )
921
if( QX11Info::appUserTime() == 0
922
|| NET::timestampCompare( _event->xclient.data.l[ 3 ], QX11Info::appUserTime() ) > 0 )
923
{ // and the timestamp looks reasonable
924
QX11Info::setAppUserTime(_event->xclient.data.l[ 3 ]); // update our qt_x_user_time from it
927
else // normal DND, only needed until Qt updates qt_x_user_time from XdndDrop
929
if( QX11Info::appUserTime() == 0
930
|| NET::timestampCompare( _event->xclient.data.l[ 2 ], QX11Info::appUserTime() ) > 0 )
931
{ // the timestamp looks reasonable
932
QX11Info::setAppUserTime(_event->xclient.data.l[ 2 ]); // update our qt_x_user_time from it
941
foreach (const QWidget *w, *x11Filter) {
942
if (((KAppX11HackWidget*) w)->publicx11Event(_event))
951
void KApplication::updateUserTimestamp( int time )
955
{ // get current X timestamp
956
Window w = XCreateSimpleWindow( QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0, 0, 0 );
957
XSelectInput( QX11Info::display(), w, PropertyChangeMask );
958
unsigned char data[ 1 ];
959
XChangeProperty( QX11Info::display(), w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
961
XWindowEvent( QX11Info::display(), w, PropertyChangeMask, &ev );
962
time = ev.xproperty.time;
963
XDestroyWindow( QX11Info::display(), w );
965
if( QX11Info::appUserTime() == 0
966
|| NET::timestampCompare( time, QX11Info::appUserTime()) > 0 ) // time > appUserTime
967
QX11Info::setAppUserTime(time);
971
unsigned long KApplication::userTimestamp() const
974
return QX11Info::appUserTime();
980
void KApplication::updateRemoteUserTimestamp( const QString& service, int time )
984
time = QX11Info::appUserTime();
985
QDBusInterface(service, QLatin1String("/MainApplication"),
986
QString(QLatin1String("org.kde.KApplication")))
987
.call(QLatin1String("updateUserTimestamp"), time);
992
QString KApplication::tempSaveName( const QString& pFilename )
996
if( QDir::isRelativePath(pFilename) )
998
kWarning(101) << "Relative filename passed to KApplication::tempSaveName" << endl;
999
aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
1002
aFilename = pFilename;
1004
QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
1005
if( !aAutosaveDir.exists() )
1007
if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
1009
// Last chance: use temp dir
1010
aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
1014
aFilename.replace( QLatin1String("/"), QLatin1String("\\!") )
1015
.prepend( QLatin1Char('#') )
1016
.append( QLatin1Char('#') )
1017
.prepend( QLatin1Char('/') ).prepend( aAutosaveDir.absolutePath() );
1023
QString KApplication::checkRecoverFile( const QString& pFilename,
1028
if( QDir::isRelativePath(pFilename) )
1030
kWarning(101) << "Relative filename passed to KApplication::tempSaveName" << endl;
1031
aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
1034
aFilename = pFilename;
1036
QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
1037
if( !aAutosaveDir.exists() )
1039
if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
1041
// Last chance: use temp dir
1042
aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
1046
aFilename.replace( QLatin1String("/"), QLatin1String("\\!") )
1047
.prepend( QLatin1Char('#') )
1048
.append( QLatin1Char('#') )
1049
.prepend( QLatin1Char('/') )
1050
.prepend( aAutosaveDir.absolutePath() );
1052
if( QFile( aFilename ).exists() )
1065
void KApplication::setTopWidget( QWidget *topWidget )
1070
// set the specified caption
1071
if ( !topWidget->inherits("KMainWindow") ) { // KMainWindow does this already for us
1072
topWidget->setWindowTitle(KGlobal::caption());
1075
#if defined Q_WS_X11
1076
//#ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded
1077
// set the app startup notification window property
1078
KStartupInfo::setWindowStartupId( topWidget->winId(), startupId());
1082
QByteArray KApplication::startupId() const
1084
return d->startup_id;
1087
void KApplication::setStartupId( const QByteArray& startup_id )
1089
if( startup_id == d->startup_id )
1091
#if defined Q_WS_X11
1092
KStartupInfo::handleAutoAppStartedSending(); // finish old startup notification if needed
1094
if( startup_id.isEmpty())
1095
d->startup_id = "0";
1098
d->startup_id = startup_id;
1099
#if defined Q_WS_X11
1101
id.initId( startup_id );
1102
long timestamp = id.timestamp();
1103
if( timestamp != 0 )
1104
updateUserTimestamp( timestamp );
1109
// read the startup notification env variable, save it and unset it in order
1110
// not to propagate it to processes started from this app
1111
void KApplication::read_app_startup_id()
1113
#if defined Q_WS_X11
1114
KStartupInfoId id = KStartupInfo::currentStartupIdEnv();
1115
KStartupInfo::resetStartupEnv();
1116
d->startup_id = id.id();
1120
// Hook called by KToolInvocation
1121
void KApplication::slot_KToolInvication_hook(QStringList& envs,QByteArray& startup_id)
1124
if (QX11Info::display()) {
1125
QByteArray dpystring(XDisplayString(QX11Info::display()));
1126
envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
1127
} else if( getenv( "DISPLAY" )) {
1128
QByteArray dpystring( getenv( "DISPLAY" ));
1129
envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
1132
if(startup_id.isEmpty())
1133
startup_id = KStartupInfo::createNewStartupId();
1136
Q_UNUSED(startup_id);
1140
void KApplication::setSynchronizeClipboard(bool synchronize)
1142
KClipboardSynchronizer::self()->setSynchronizing(synchronize);
1143
KClipboardSynchronizer::self()->setReverseSynchronizing(synchronize);
1146
#include "kapplication.moc"