26 #include <QtCore/QDir>
27 #include <QtCore/QFile>
28 #include <QtGui/QSessionManager>
29 #include <QtGui/QStyleFactory>
30 #include <QtCore/QTimer>
31 #include <QtGui/QWidget>
32 #include <QtCore/QList>
33 #include <QtDBus/QtDBus>
34 #include <QtCore/QMetaType>
58 #include <QtGui/qx11info_x11.h>
62 #include <sys/types.h>
63 #ifdef HAVE_SYS_STAT_H
86 #include <X11/Xutil.h>
87 #include <X11/Xatom.h>
88 #include <X11/SM/SMlib.h>
97 #include <Carbon/Carbon.h>
107 #include <QtGui/QActionEvent>
120 template class QList<KSessionManager*>;
126 return kapp->xioErrhandler( dpy );
131 return kapp->xErrhandler( dpy, err );
144 class KApplicationPrivate
147 KApplicationPrivate(
KApplication* q,
const QByteArray &cName)
149 , componentData(cName)
151 , app_started_timer(0)
152 , session_save(false)
154 , oldIceIOErrorHandler(0)
155 , oldXErrorHandler(0)
156 , oldXIOErrorHandler(0)
158 , pSessionConfig( 0 )
159 , bSessionManagement( true )
165 , componentData(cData)
167 , app_started_timer(0)
168 , session_save(false)
170 , oldIceIOErrorHandler(0)
171 , oldXErrorHandler(0)
172 , oldXIOErrorHandler(0)
174 , pSessionConfig( 0 )
175 , bSessionManagement( true )
183 , app_started_timer( 0 )
184 , session_save( false )
186 , oldIceIOErrorHandler( 0 )
187 , oldXErrorHandler( 0 )
188 , oldXIOErrorHandler( 0 )
190 , pSessionConfig( 0 )
191 , bSessionManagement( true )
195 ~KApplicationPrivate()
203 void _k_x11FilterDestroyed();
204 void _k_checkAppStartedSlot();
205 void _k_slot_KToolInvocation_hook(
QStringList&, QByteArray&);
207 QString sessionConfigName()
const;
208 void init(
bool GUIenabled=
true);
209 void parseCommandLine( );
210 static void preqapplicationhack();
211 static void preread_app_startup_id();
212 void read_app_startup_id();
216 QByteArray startup_id;
217 QTimer* app_started_timer;
221 IceIOErrorHandler oldIceIOErrorHandler;
222 int (*oldXErrorHandler)(Display*,XErrorEvent*);
223 int (*oldXIOErrorHandler)(Display*);
230 bool bSessionManagement;
246 struct sigaction act;
247 act.sa_handler = SIG_IGN;
248 sigemptyset( &act.sa_mask );
250 sigaction( SIGPIPE, &act, 0 );
259 x11Filter =
new QList< QWeakPointer< QWidget > >;
260 connect ( filter, SIGNAL(destroyed()),
this, SLOT(_k_x11FilterDestroyed()) );
261 x11Filter->append( filter );
264 void KApplicationPrivate::_k_x11FilterDestroyed()
266 q->removeX11EventFilter( static_cast< const QWidget* >(q->sender()));
271 if ( !x11Filter || !filter )
275 for( QMutableListIterator< QWeakPointer< QWidget > > it( *x11Filter );
279 if( w == filter || w == NULL )
282 if ( x11Filter->isEmpty() ) {
290 QEvent::Type t =
event->type();
291 if( t == QEvent::Show && receiver->isWidgetType())
295 if( w->isTopLevel() && !
startupId().isEmpty())
298 if( w->isTopLevel() && !( w->windowFlags() & Qt::X11BypassWindowManagerHint ) && w->windowType() != Qt::Popup && !
event->spontaneous())
300 if( d->app_started_timer == NULL )
302 d->app_started_timer =
new QTimer(
this );
303 connect( d->app_started_timer, SIGNAL(
timeout()), SLOT(_k_checkAppStartedSlot()));
305 if( !d->app_started_timer->isActive()) {
306 d->app_started_timer->setSingleShot(
true );
307 d->app_started_timer->start( 0 );
314 void KApplicationPrivate::_k_checkAppStartedSlot()
326 QString KApplicationPrivate::sessionConfigName()
const
328 #ifdef QT_NO_SESSIONMANAGER
329 #error QT_NO_SESSIONMANAGER was set, this will not compile. Reconfigure Qt with Session management support.
331 QString sessKey = q->sessionKey();
332 if ( sessKey.isEmpty() && !sessionKey.isEmpty() )
333 sessKey = sessionKey;
334 return QString(QLatin1String(
"session/%1_%2_%3")).arg(q->applicationName()).arg(q->sessionId()).arg(sessKey);
346 d(new KApplicationPrivate(this))
348 d->read_app_startup_id();
350 setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
358 d(new KApplicationPrivate(this))
360 d->read_app_startup_id();
362 setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
369 d (new KApplicationPrivate(this, cData))
371 d->read_app_startup_id();
373 setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
381 d (new KApplicationPrivate(this, cData))
383 d->read_app_startup_id();
385 setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
393 :
QApplication((KApplicationPrivate::preqapplicationhack(),display)),
394 d(new KApplicationPrivate(this, rAppName))
396 Q_UNUSED(GUIenabled);
397 d->read_app_startup_id();
400 KCmdLineArgs::initIgnore(argc, argv, rAppName.data());
407 void KApplicationPrivate::preqapplicationhack()
409 preread_app_startup_id();
419 d->oldXIOErrorHandler( dpy );
431 XErrorEvent* err =
static_cast< XErrorEvent*
>( err_ );
435 d->oldXErrorHandler( dpy, err );
437 const QByteArray fatalXError = qgetenv(
"KDE_FATAL_X_ERROR");
438 if (!fatalXError.isEmpty()) {
450 if ( d->oldIceIOErrorHandler != NULL )
451 (*d->oldIceIOErrorHandler)( conn );
456 void KApplicationPrivate::init(
bool GUIenabled)
458 if ((getuid() != geteuid()) ||
459 (getgid() != getegid()))
461 fprintf(stderr,
"The KDE libraries are not designed to run with suid privileges.\n");
469 KApplication::KApp = q;
473 (void) QApplication::clipboard();
476 kde_kdebug_enable_dbus_interface =
true;
483 QApplication::setDesktopSettingsAware(
false );
487 if ( q->type() == KApplication::GuiClient ) {
491 Atom atoms_return[max];
495 names[n++] = (
char *)
"KDE_DESKTOP_WINDOW";
498 names[n++] = (
char *)
"_NET_SUPPORTED";
501 names[n++] = (
char *)
"XdndDrop";
503 XInternAtoms( QX11Info::display(), names, n,
false, atoms_return );
505 for (
int i = 0; i < n; i++ )
506 *atoms[i] = atoms_return[i];
512 extern void qDBusBindToApplication();
513 qDBusBindToApplication();
514 QDBusConnectionInterface *bus = 0;
515 if (!QDBusConnection::sessionBus().isConnected() || !(bus = QDBusConnection::sessionBus().interface())) {
516 kFatal(240) <<
"Session bus not found" << endl <<
517 "To circumvent this problem try the following command (with Linux and bash)" << endl <<
518 "export $(dbus-launch)";
523 if ( bus && !s_kuniqueapplication_startCalled )
525 QStringList parts = q->organizationDomain().split(QLatin1Char(
'.'), QString::SkipEmptyParts);
528 reversedDomain = QLatin1String(
"local.");
530 foreach (
const QString& s, parts)
532 reversedDomain.prepend(QLatin1Char(
'.'));
533 reversedDomain.prepend(s);
535 const QString pidSuffix = QString::number( getpid() ).prepend( QLatin1String(
"-") );
536 const QString serviceName = reversedDomain + q->applicationName() + pidSuffix;
537 if ( bus->registerService(serviceName) == QDBusConnectionInterface::ServiceNotRegistered ) {
538 kError(240) <<
"Couldn't register name '" << serviceName <<
"' with DBUS - another process owns it already!" << endl;
542 QDBusConnection::sessionBus().registerObject(QLatin1String(
"/MainApplication"), q,
543 QDBusConnection::ExportScriptableSlots |
544 QDBusConnection::ExportScriptableProperties |
545 QDBusConnection::ExportAdaptors);
551 QByteArray readOnly = qgetenv(
"KDE_HOME_READONLY");
552 if (readOnly.isEmpty() && q->applicationName() != QLatin1String(
"kdialog"))
558 if (q->type() == KApplication::GuiClient)
562 fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, FD_CLOEXEC);
577 q, SLOT(_k_slot_KToolInvocation_hook(
QStringList&,QByteArray&)));
581 if (q->type() == KApplication::GuiClient) {
584 if (QSystemTrayIcon::isSystemTrayAvailable())
587 trayIcon->setIcon(q->windowIcon());
595 qRegisterMetaType<KUrl>();
596 qRegisterMetaType<KUrl::List>();
610 if (!d->pSessionConfig)
612 return d->pSessionConfig;
626 d->bSessionManagement =
false;
630 d->bSessionManagement =
true;
641 if( mySmcConnection ) {
642 SmcRequestSaveYourself( mySmcConnection, SmSaveLocal, False,
647 IceFlush(SmcGetIceConnection(mySmcConnection));
654 d->session_save =
true;
655 bool canceled =
false;
665 if ( sm.allowsInteraction() ) {
666 QWidgetList donelist, todolist;
670 todolist = QApplication::topLevelWidgets();
672 for (
int i = 0; i < todolist.size(); ++i ) {
673 w = todolist.at( i );
677 if ( donelist.contains( w ) )
680 if ( !w->isHidden() && !w->inherits(
"KMainWindow" ) ) {
683 if ( !e.isAccepted() )
686 donelist.append( w );
689 goto commitDataRestart;
694 if ( !d->bSessionManagement )
695 sm.setRestartHint( QSessionManager::RestartNever );
697 sm.setRestartHint( QSessionManager::RestartIfRunning );
698 d->session_save =
false;
704 Display* dpy = QX11Info::display();
707 unsigned long nitems, after;
709 if( dpy != NULL && XGetWindowProperty( dpy, RootWindow( dpy, 0 ), XInternAtom( dpy,
"KDE_SESSION_VERSION", False ),
710 0, 1, False, AnyPropertyType, &type, &format, &nitems, &after, &data ) == Success ) {
711 if( type == XA_CARDINAL && format == 32 ) {
720 if( getenv(
"KDE_SESSION_VERSION" ) != NULL && atoi( getenv(
"KDE_SESSION_VERSION" )) ==
KDE_VERSION_MAJOR )
722 #define NUM_TO_STRING2( num ) #num
723 #define NUM_TO_STRING( num ) NUM_TO_STRING2( num )
726 #undef NUM_TO_STRING2
727 if( !wrapper.isEmpty()) {
729 restartCommand.prepend( wrapper );
730 sm.setRestartCommand( restartCommand );
737 d->session_save =
true;
739 static bool firstTime =
true;
740 mySmcConnection = (SmcConn) sm.handle();
742 if ( !d->bSessionManagement ) {
743 sm.setRestartHint( QSessionManager::RestartNever );
744 d->session_save =
false;
748 sm.setRestartHint( QSessionManager::RestartIfRunning );
752 d->session_save =
false;
762 delete d->pSessionConfig;
763 d->pSessionConfig = 0;
768 QByteArray multiHead = qgetenv(
"KDE_MULTIHEAD");
769 if (multiHead.toLower() ==
"true") {
776 QByteArray displayname = qgetenv(
"DISPLAY");
777 if (! displayname.isNull()) {
780 restartCommand.append(QLatin1String(
"-display"));
781 restartCommand.append(QLatin1String(displayname));
783 sm.setRestartCommand( restartCommand );
792 bool canceled =
false;
799 if ( d->pSessionConfig ) {
800 d->pSessionConfig->sync();
803 sm.setDiscardCommand( discard );
805 sm.setDiscardCommand(
QStringList( QLatin1String(
"") ) );
811 d->session_save =
false;
816 return d->session_save;
819 void KApplicationPrivate::parseCommandLine( )
823 if (args && args->
isSet(
"style"))
827 if (QStyleFactory::keys().contains(reqStyle, Qt::CaseInsensitive))
828 kde_overrideStyle = reqStyle;
830 qWarning() <<
i18n(
"The style '%1' was not found", reqStyle);
833 if (args && args->
isSet(
"config"))
836 componentData.setConfigName(config);
839 if ( q->type() != KApplication::Tty ) {
840 if (args && args->
isSet(
"icon"))
845 q->setWindowIcon(
KIcon(componentData.aboutData()->programIconName()));
852 bool nocrashhandler = (!qgetenv(
"KDE_DEBUG").isEmpty());
853 if (!nocrashhandler && args->
isSet(
"crashhandler"))
860 if (!QCoreApplication::applicationDirPath().isEmpty()) {
865 if ( args->
isSet(
"waitforwm" ) ) {
869 unsigned long length, after;
871 while ( XGetWindowProperty( QX11Info::display(), QX11Info::appRootWindow(),
atom_NetSupported,
872 0, 1,
false, AnyPropertyType, &type, &format,
873 &length, &after, &data ) != Success || !length ) {
877 XWindowEvent( QX11Info::display(), QX11Info::appRootWindow(), PropertyChangeMask, &event );
885 if (args->
isSet(
"smkey"))
897 if ( d->oldXErrorHandler != NULL )
898 XSetErrorHandler( d->oldXErrorHandler );
899 if ( d->oldXIOErrorHandler != NULL )
900 XSetIOErrorHandler( d->oldXIOErrorHandler );
901 if ( d->oldIceIOErrorHandler != NULL )
902 IceSetIOErrorHandler( d->oldIceIOErrorHandler );
915 class KAppX11HackWidget:
public QWidget
918 bool publicx11Event( XEvent * e) {
return x11Event( e ); }
928 foreach (
const QWeakPointer< QWidget >& wp, *x11Filter) {
930 if ( static_cast<KAppX11HackWidget*>( w )->publicx11Event(_event))
944 Window w = XCreateSimpleWindow( QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0, 0, 0 );
945 XSelectInput( QX11Info::display(), w, PropertyChangeMask );
946 unsigned char data[ 1 ];
947 XChangeProperty( QX11Info::display(), w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
949 XWindowEvent( QX11Info::display(), w, PropertyChangeMask, &ev );
950 time = ev.xproperty.time;
951 XDestroyWindow( QX11Info::display(), w );
953 if( QX11Info::appUserTime() == 0
955 QX11Info::setAppUserTime(time);
956 if( QX11Info::appTime() == 0
958 QX11Info::setAppTime(time);
965 return QX11Info::appUserTime();
974 Q_ASSERT(service.contains(
'.'));
976 time = QX11Info::appUserTime();
977 QDBusInterface(service, QLatin1String(
"/MainApplication"),
978 QString(QLatin1String(
"org.kde.KApplication")))
979 .call(QLatin1String(
"updateUserTimestamp"), time);
984 #ifndef KDE_NO_DEPRECATED
989 if( QDir::isRelativePath(pFilename) )
991 kWarning(240) <<
"Relative filename passed to KApplication::tempSaveName";
992 aFilename = QFileInfo( QDir( QLatin1String(
".") ), pFilename ).absoluteFilePath();
995 aFilename = pFilename;
997 QDir aAutosaveDir( QDir::homePath() + QLatin1String(
"/autosave/") );
998 if( !aAutosaveDir.exists() )
1000 if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
1003 aAutosaveDir.setPath(
KGlobal::dirs()->saveLocation(
"tmp") );
1007 aFilename.replace(
'/', QLatin1String(
"\\!") )
1008 .prepend( QLatin1Char(
'#') )
1009 .append( QLatin1Char(
'#') )
1010 .prepend( QLatin1Char(
'/') ).prepend( aAutosaveDir.absolutePath() );
1022 if( QDir::isRelativePath(pFilename) )
1024 kWarning(240) <<
"Relative filename passed to KApplication::tempSaveName";
1025 aFilename = QFileInfo( QDir( QLatin1String(
".") ), pFilename ).absoluteFilePath();
1028 aFilename = pFilename;
1030 QDir aAutosaveDir( QDir::homePath() + QLatin1String(
"/autosave/") );
1031 if( !aAutosaveDir.exists() )
1033 if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
1036 aAutosaveDir.setPath(
KGlobal::dirs()->saveLocation(
"tmp") );
1040 aFilename.replace( QLatin1String(
"/"), QLatin1String(
"\\!") )
1041 .prepend( QLatin1Char(
'#') )
1042 .append( QLatin1Char(
'#') )
1043 .prepend( QLatin1Char(
'/') )
1044 .prepend( aAutosaveDir.absolutePath() );
1046 if( QFile( aFilename ).exists() )
1065 if ( !topWidget->inherits(
"KMainWindow") ) {
1077 return d->startup_id;
1082 if( startup_id == d->startup_id )
1084 #if defined Q_WS_X11
1087 if( startup_id.isEmpty())
1088 d->startup_id =
"0";
1091 d->startup_id = startup_id;
1092 #
if defined Q_WS_X11
1095 long timestamp =
id.timestamp();
1096 if( timestamp != 0 )
1104 d->startup_id =
"0";
1110 void KApplicationPrivate::preread_app_startup_id()
1112 #if defined Q_WS_X11
1121 void KApplicationPrivate::read_app_startup_id()
1123 #if defined Q_WS_X11
1131 void KApplicationPrivate::_k_slot_KToolInvocation_hook(
QStringList& envs,QByteArray& startup_id)
1134 if (QX11Info::display()) {
1135 QByteArray dpystring(XDisplayString(QX11Info::display()));
1136 envs << QLatin1String(
"DISPLAY=") + dpystring;
1138 const QByteArray dpystring( qgetenv(
"DISPLAY" ));
1139 if(!dpystring.isEmpty())
1140 envs << QLatin1String(
"DISPLAY=") + dpystring;
1143 if(startup_id.isEmpty())
1147 Q_UNUSED(startup_id);
1157 #include "kapplication.moc"