KDELibs4Support

kapplication.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 1997 Matthias Kalle Dalheimer ([email protected])
3  Copyright (C) 1998, 1999, 2000 KDE Team
4 
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.
9 
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.
14 
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.
19  */
20 
21 #include "kapplication.h"
22 
23 #include "kdeversion.h"
24 #include <config-kdelibs4support.h>
25 
26 #include <QDir>
27 #include <QFile>
28 #include <QSessionManager>
29 #include <QStyleFactory>
30 #include <QTimer>
31 #include <QWidget>
32 #include <QPointer>
33 #include <QList>
34 #include <QDBusConnection>
35 #include <QDBusConnectionInterface>
36 #include <QDBusInterface>
37 #include <QMetaType>
38 
39 #include "kauthorized.h"
40 #include "k4aboutdata.h"
41 #include "kcrash.h"
42 #include "kconfig.h"
43 #include "kcmdlineargs.h"
44 #include "kglobalsettings.h"
45 #include "kdebug.h"
46 #include <kglobal.h>
47 #include "klocale.h"
48 #include "klocalizedstring.h"
49 #include "ksessionmanager.h"
50 #include "ktoolinvocation.h"
51 #include "kurl.h"
52 #include "kmessage.h"
53 #include "kmessageboxmessagehandler.h"
54 #include <kconfiggui.h>
55 #include <kusertimestamp.h>
56 
57 #if HAVE_X11
58 #include <qx11info_x11.h>
59 #endif
60 #include <kstartupinfo.h>
61 
62 #include <sys/types.h>
63 #if HAVE_SYS_STAT_H
64 #include <sys/stat.h>
65 #endif
66 #include <sys/wait.h>
67 
68 #ifndef Q_OS_WIN
69 #include "kwindowsystem.h"
70 #endif
71 
72 #include <fcntl.h>
73 #include <stdlib.h> // srand(), rand()
74 #include <unistd.h>
75 #if HAVE_X11
76 #include <netwm.h>
77 #endif
78 
79 #if HAVE_PATHS_H
80 #include <paths.h>
81 #endif
82 
83 #if HAVE_X11
84 #include <X11/Xlib.h>
85 #include <X11/Xutil.h>
86 #include <X11/Xatom.h>
87 #include <X11/SM/SMlib.h>
88 #include <fixx11h.h>
89 
90 #include <QX11Info>
91 #endif
92 
93 #ifdef Q_OS_MAC
94 // ick
95 #undef Status
96 #include <Carbon/Carbon.h>
97 #include <QImage>
98 #include <ksystemtrayicon.h>
99 #include <kkernel_mac.h>
100 #endif
101 
102 #ifdef Q_OS_UNIX
103 #include <signal.h>
104 #endif
105 
106 #include <qstandardpaths.h>
107 #include <QActionEvent>
108 
110 
111 #if HAVE_X11
112 static Atom atom_DesktopWindow;
113 static Atom atom_NetSupported;
114 static Atom kde_xdnd_drop;
115 #endif
116 
117 template class QList<KSessionManager *>;
118 
119 #ifdef Q_OS_WIN
120 void KApplication_init_windows();
121 #endif
122 
123 static KApplicationPrivate *kapp_priv = nullptr;
124 
125 /*
126  Private data to make keeping binary compatibility easier
127  */
128 class KApplicationPrivate
129 {
130 public:
131  KApplicationPrivate(KApplication *q, const QByteArray &cName)
132  : q(q)
133  , componentData(cName)
134  , session_save(false)
135 #if HAVE_X11
136  , oldIceIOErrorHandler(nullptr)
137  , oldXErrorHandler(nullptr)
138  , oldXIOErrorHandler(nullptr)
139  , isX11(false)
140 #endif
141  , pSessionConfig(nullptr)
142  , bSessionManagement(true)
143  {
144  kapp_priv = this;
145  }
146 
147  KApplicationPrivate(KApplication *q, const KComponentData &cData)
148  : q(q)
149  , componentData(cData)
150  , session_save(false)
151 #if HAVE_X11
152  , oldIceIOErrorHandler(nullptr)
153  , oldXErrorHandler(nullptr)
154  , oldXIOErrorHandler(nullptr)
155  , isX11(false)
156 #endif
157  , pSessionConfig(nullptr)
158  , bSessionManagement(true)
159  {
160  kapp_priv = this;
161  }
162 
163  KApplicationPrivate(KApplication *q)
164  : q(q)
165  , componentData(KCmdLineArgs::aboutData())
166  , session_save(false)
167 #if HAVE_X11
168  , oldIceIOErrorHandler(nullptr)
169  , oldXErrorHandler(nullptr)
170  , oldXIOErrorHandler(nullptr)
171  , isX11(false)
172 #endif
173  , pSessionConfig(nullptr)
174  , bSessionManagement(true)
175  {
176  kapp_priv = this;
177  }
178 
179  ~KApplicationPrivate()
180  {
181  }
182 
183 #ifndef KDE3_SUPPORT
184  KConfig *config()
185  {
186  return KSharedConfig::openConfig().data();
187  }
188 #endif
189 
190 #if HAVE_X11
191  int xErrhandler(Display *, void *);
192  int xioErrhandler(Display *);
193  void iceIOErrorHandler(_IceConn *conn);
194 #endif
195 
196  void _k_x11FilterDestroyed();
197  void _k_slot_KToolInvocation_hook(QStringList &, QByteArray &);
198 
199  void init(bool GUIenabled = true);
200  void parseCommandLine(); // Handle KDE arguments (Using KCmdLineArgs)
201 
202  KApplication *q;
203  KComponentData componentData;
204  bool session_save;
205 
206 #if HAVE_X11
207  IceIOErrorHandler oldIceIOErrorHandler;
208  int (*oldXErrorHandler)(Display *, XErrorEvent *);
209  int (*oldXIOErrorHandler)(Display *);
210  bool isX11;
211 #endif
212 
213  QString sessionKey;
214  QString pSessionConfigFile;
215 
216  KConfig *pSessionConfig; //instance specific application config object
217  bool bSessionManagement;
218 };
219 
220 #if HAVE_X11
221 
222 extern "C" {
223  static int kde_xio_errhandler(Display *dpy)
224  {
225  return kapp_priv->xioErrhandler(dpy);
226  }
227 
228  static int kde_x_errhandler(Display *dpy, XErrorEvent *err)
229  {
230  return kapp_priv->xErrhandler(dpy, err);
231  }
232 }
233 #endif
234 
235 static QList< QPointer< QWidget > > *x11Filter = nullptr;
236 
237 /**
238  * Installs a handler for the SIGPIPE signal. It is thrown when you write to
239  * a pipe or socket that has been closed.
240  * The handler is installed automatically in the constructor, but you may
241  * need it if your application or component does not have a KApplication
242  * instance.
243  */
244 static void installSigpipeHandler()
245 {
246 #ifdef Q_OS_UNIX
247  struct sigaction act;
248  act.sa_handler = SIG_IGN;
249  sigemptyset(&act.sa_mask);
250  act.sa_flags = 0;
251  sigaction(SIGPIPE, &act, nullptr);
252 #endif
253 }
254 
256 {
257  if (!filter) {
258  return;
259  }
260  if (!x11Filter) {
261  x11Filter = new QList< QPointer< QWidget > >;
262  }
263  connect(filter, SIGNAL(destroyed()), this, SLOT(_k_x11FilterDestroyed()));
264  x11Filter->append(filter);
265 }
266 
267 void KApplicationPrivate::_k_x11FilterDestroyed()
268 {
269  q->removeX11EventFilter(static_cast< const QWidget * >(q->sender()));
270 }
271 
273 {
274  if (!x11Filter || !filter) {
275  return;
276  }
277  // removeAll doesn't work, creating QPointer to something that's about to be deleted aborts
278  // x11Filter->removeAll( const_cast< QWidget* >( filter ));
279  for (QMutableListIterator< QPointer< QWidget > > it(*x11Filter);
280  it.hasNext();
281  ) {
282  QWidget *w = it.next().data();
283  if (w == filter || w == nullptr) {
284  it.remove();
285  }
286  }
287  if (x11Filter->isEmpty()) {
288  delete x11Filter;
289  x11Filter = nullptr;
290  }
291 }
292 
293 #if HAVE_X11
294 static SmcConn mySmcConnection = nullptr;
295 #else
296 // FIXME(E): Implement for Qt Embedded
297 // Possibly "steal" XFree86's libSM?
298 #endif
299 
301  : QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), GUIenabled),
302  d(new KApplicationPrivate(this))
303 {
304  setApplicationName(d->componentData.componentName());
305  setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
306  installSigpipeHandler();
307  d->init(GUIenabled);
308 }
309 
310 KApplication::KApplication(bool GUIenabled, const KComponentData &cData)
311  : QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), GUIenabled),
312  d(new KApplicationPrivate(this, cData))
313 {
314  setApplicationName(d->componentData.componentName());
315  setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
316  installSigpipeHandler();
317  d->init(GUIenabled);
318 }
319 
320 #if HAVE_X11
321 int KApplicationPrivate::xioErrhandler(Display *dpy)
322 {
323  oldXIOErrorHandler(dpy);
324  exit(1);
325  return 0;
326 }
327 
328 int KApplicationPrivate::xErrhandler(Display *dpy, void *err_)
329 {
330  XErrorEvent *err = static_cast< XErrorEvent * >(err_);
331  if (kapp) {
332  // add KDE specific stuff here
333  oldXErrorHandler(dpy, err);
334  }
335  const QByteArray fatalXError = qgetenv("KDE_FATAL_X_ERROR");
336  if (!fatalXError.isEmpty()) {
337  abort();
338  }
339  return 0;
340 }
341 
342 void KApplicationPrivate::iceIOErrorHandler(_IceConn *conn)
343 {
344  if (oldIceIOErrorHandler != nullptr) {
345  (*oldIceIOErrorHandler)(conn);
346  }
347  exit(1);
348 }
349 #endif
350 
351 // (only called by KUniqueApplication, no need to export)
352 bool s_kuniqueapplication_startCalled = false;
353 
354 void KApplicationPrivate::init(bool GUIenabled)
355 {
356  Q_UNUSED(GUIenabled)
357  if ((getuid() != geteuid()) ||
358  (getgid() != getegid())) {
359  fprintf(stderr, "The KDE libraries are not designed to run with suid privileges.\n");
360  ::exit(127);
361  }
362 
363 #ifdef Q_OS_MAC
364  mac_initialize_dbus();
365 #endif
366 
367  KApplication::KApp = q;
368 
369  extern KDELIBS4SUPPORT_DEPRECATED_EXPORT bool kde_kdebug_enable_dbus_interface;
370  kde_kdebug_enable_dbus_interface = true;
371 
372  parseCommandLine();
373 
376 
377 #if HAVE_X11
378  isX11 = (QGuiApplication::platformName() == QStringLiteral("xcb"));
379  if (isX11) {
380  // create all required atoms in _one_ roundtrip to the X server
381  const int max = 20;
382  Atom *atoms[max];
383  char *names[max];
384  Atom atoms_return[max];
385  int n = 0;
386 
387  atoms[n] = &atom_DesktopWindow;
388  names[n++] = (char *) "KDE_DESKTOP_WINDOW";
389 
390  atoms[n] = &atom_NetSupported;
391  names[n++] = (char *) "_NET_SUPPORTED";
392 
393  atoms[n] = &kde_xdnd_drop;
394  names[n++] = (char *) "XdndDrop";
395 
396  XInternAtoms(QX11Info::display(), names, n, false, atoms_return);
397 
398  for (int i = 0; i < n; i++) {
399  *atoms[i] = atoms_return[i];
400  }
401  }
402 #endif
403 
404  // sanity checking, to make sure we've connected
405  extern void qDBusBindToApplication();
406  qDBusBindToApplication();
407  QDBusConnectionInterface *bus = nullptr;
408  if (!QDBusConnection::sessionBus().isConnected() || !(bus = QDBusConnection::sessionBus().interface())) {
409  kFatal(240) << "Session bus not found" << endl <<
410  "To circumvent this problem try the following command (with Linux and bash)" << endl <<
411  "export $(dbus-launch)";
412  ::exit(125);
413  }
414 
415  if (bus && !s_kuniqueapplication_startCalled) { // don't register again if KUniqueApplication did so already
416  QStringList parts = q->organizationDomain().split(QLatin1Char('.'), QString::SkipEmptyParts);
417  QString reversedDomain;
418  if (parts.isEmpty()) {
419  reversedDomain = QLatin1String("local.");
420  } else
421  foreach (const QString &s, parts) {
422  reversedDomain.prepend(QLatin1Char('.'));
423  reversedDomain.prepend(s);
424  }
425  const QString pidSuffix = QString::number(getpid()).prepend(QLatin1String("-"));
426  const QString serviceName = reversedDomain + q->applicationName() + pidSuffix;
428  kError(240) << "Couldn't register name '" << serviceName << "' with DBUS - another process owns it already!" << endl;
429  ::exit(126);
430  }
431  }
436 
437  // Trigger creation of locale.
438  (void) KLocale::global();
439 
440  KSharedConfig::Ptr config = componentData.config();
441  QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
442  if (readOnly.isEmpty() && q->applicationName() != QLatin1String("kdialog")) {
443  if (KAuthorized::authorize(QLatin1String("warn_unwritable_config"))) {
444  config->isConfigWritable(true);
445  }
446  }
447 
448 #if HAVE_X11
449  if (isX11) {
450  // this is important since we fork() to launch the help (Matthias)
451  fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, FD_CLOEXEC);
452  // set up the fancy (=robust and error ignoring ) KDE xio error handlers (Matthias)
453  oldXErrorHandler = XSetErrorHandler(kde_x_errhandler);
454  oldXIOErrorHandler = XSetIOErrorHandler(kde_xio_errhandler);
455  }
456 #endif
457 
458  // Trigger initial settings
460 
462 
463  q->connect(KToolInvocation::self(), SIGNAL(kapplication_hook(QStringList&,QByteArray&)),
464  q, SLOT(_k_slot_KToolInvocation_hook(QStringList&,QByteArray&)));
465 
466  q->connect(q, SIGNAL(commitDataRequest(QSessionManager&)),
467  q, SLOT(commitData(QSessionManager&)));
468  q->connect(q, SIGNAL(saveStateRequest(QSessionManager&)),
469  q, SLOT(saveState(QSessionManager&)));
470 
471 
472 #ifdef Q_OS_MAC
473  // This is a QSystemTrayIcon instead of K* because we can't be sure q is a QWidget
474  QSystemTrayIcon *trayIcon; //krazy:exclude=qclasses
475  if (QSystemTrayIcon::isSystemTrayAvailable()) { //krazy:exclude=qclasses
476  trayIcon = new QSystemTrayIcon(q); //krazy:exclude=qclasses
477  trayIcon->setIcon(q->windowIcon());
478  /* it's counter-intuitive, but once you do setIcon it's already set the
479  dock icon... ->show actually shows an icon in the menu bar too :P */
480  // trayIcon->show();
481  }
482 #endif
483 
484  qRegisterMetaType<KUrl>();
485  qRegisterMetaType<QList<KUrl> >();
486  qRegisterMetaType<QList<QUrl> >();
487 
488 #ifdef Q_OS_WIN
489  KApplication_init_windows();
490 #endif
491 }
492 
494 {
495  return KApp;
496 }
497 
499 {
500  return KConfigGui::sessionConfig();
501 }
502 
503 void KApplication::reparseConfiguration()
504 {
505  KSharedConfig::openConfig()->reparseConfiguration();
506 }
507 
508 void KApplication::quit()
509 {
511 }
512 
514 {
515  d->bSessionManagement = false;
516 }
517 
519 {
520  d->bSessionManagement = true;
521 #if HAVE_X11
522  if (!d->isX11) {
523  return;
524  }
525  // Session management support in Qt/KDE is awfully broken.
526  // If konqueror disables session management right after its startup,
527  // and enables it later (preloading stuff), it won't be properly
528  // saved on session shutdown.
529  // I'm not actually sure why it doesn't work, but saveState()
530  // doesn't seem to be called on session shutdown, possibly
531  // because disabling session management after konqueror startup
532  // disabled it somehow. Forcing saveState() here for this application
533  // seems to fix it.
534  if (mySmcConnection) {
535  SmcRequestSaveYourself(mySmcConnection, SmSaveLocal, False,
536  SmInteractStyleAny,
537  False, False);
538 
539  // flush the request
540  IceFlush(SmcGetIceConnection(mySmcConnection));
541  }
542 #endif
543 }
544 
546 {
547  d->session_save = true;
548  bool canceled = false;
549 
550  foreach (KSessionManager *it, KSessionManager::sessionClients()) {
551  if ((canceled = !it->commitData(sm))) {
552  break;
553  }
554  }
555 
556  if (canceled) {
557  sm.cancel();
558  }
559 
560  if (sm.allowsInteraction()) {
561  QWidgetList donelist, todolist;
562  QWidget *w;
563 
564  commitDataRestart:
565  todolist = QApplication::topLevelWidgets();
566 
567  for (int i = 0; i < todolist.size(); ++i) {
568  w = todolist.at(i);
569  if (!w) {
570  break;
571  }
572 
573  if (donelist.contains(w)) {
574  continue;
575  }
576 
577  // leave KMainWindows alone because they are handled by KMWSessionManager
578  if (!w->isHidden() && !w->inherits("KMainWindow")) {
579  QCloseEvent e;
580  sendEvent(w, &e);
581  if (!e.isAccepted()) {
582  canceled = true;
583  break;
584  }
585 
586  donelist.append(w);
587 
588  //grab the new list that was just modified by our closeevent
589  goto commitDataRestart;
590  }
591  }
592  }
593 
594  if (!d->bSessionManagement) {
596  } else {
598  }
599 
600  if (canceled) {
601  sm.cancel();
602  }
603  d->session_save = false;
604 }
605 
606 #if HAVE_X11 && QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
607 static void checkRestartVersion(QSessionManager &sm)
608 {
609  Display *dpy = QX11Info::display();
610  Atom type;
611  int format;
612  unsigned long nitems, after;
613  unsigned char *data;
614  if (dpy != NULL && XGetWindowProperty(dpy, RootWindow(dpy, 0), XInternAtom(dpy, "KDE_SESSION_VERSION", False),
615  0, 1, False, AnyPropertyType, &type, &format, &nitems, &after, &data) == Success) {
616  if (type == XA_CARDINAL && format == 32) {
617  int version = *(long *) data;
618  if (version == KDE_VERSION_MAJOR) { // we run in our native session
619  XFree(data);
620  return; // no need to wrap
621  }
622  }
623  XFree(data);
624  }
625  if (getenv("KDE_SESSION_VERSION") != NULL && atoi(getenv("KDE_SESSION_VERSION")) == KDE_VERSION_MAJOR) {
626  return; // we run in our native session, no need to wrap
627  }
628 #define NUM_TO_STRING2( num ) #num
629 #define NUM_TO_STRING( num ) NUM_TO_STRING2( num )
630  QString wrapper = QStandardPaths::findExecutable("kde" NUM_TO_STRING(KDE_VERSION_MAJOR)); // "kde4", etc.
631 #undef NUM_TO_STRING
632 #undef NUM_TO_STRING2
633  if (!wrapper.isEmpty()) {
634  QStringList restartCommand = sm.restartCommand();
635  restartCommand.prepend(wrapper);
636  sm.setRestartCommand(restartCommand);
637  }
638 }
639 #endif // HAVE_X11
640 
642 {
643  d->session_save = true;
644 #ifdef __GNUC__
645 #warning TODO: QSessionManager::handle() is gone in Qt5!
646 #endif
647 #if HAVE_X11 && QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
648  static bool firstTime = true;
649  mySmcConnection = (SmcConn) sm.handle();
650 
651  if (!d->bSessionManagement) {
653  d->session_save = false;
654  return;
655  } else {
657  }
658 
659  if (firstTime) {
660  firstTime = false;
661  d->session_save = false;
662  return; // no need to save the state.
663  }
664 
665  // remove former session config if still existing, we want a new
666  // and fresh one. Note that we do not delete the config file here,
667  // this is done by the session manager when it executes the
668  // discard commands. In fact it would be harmful to remove the
669  // file here, as the session might be stored under a different
670  // name, meaning the user still might need it eventually.
671  delete d->pSessionConfig;
672  d->pSessionConfig = 0;
673 
674  // tell the session manager about our new lifecycle
675  QStringList restartCommand = sm.restartCommand();
676 
677  QByteArray multiHead = qgetenv("KDE_MULTIHEAD");
678  if (multiHead.toLower() == "true") {
679  // if multihead is enabled, we save our -display argument so that
680  // we are restored onto the correct head... one problem with this
681  // is that the display is hard coded, which means we cannot restore
682  // to a different display (ie. if we are in a university lab and try,
683  // try to restore a multihead session, our apps could be started on
684  // someone else's display instead of our own)
685  QByteArray displayname = qgetenv("DISPLAY");
686  if (! displayname.isNull()) {
687  // only store the command if we actually have a DISPLAY
688  // environment variable
689  restartCommand.append(QLatin1String("-display"));
690  restartCommand.append(QLatin1String(displayname));
691  }
692  sm.setRestartCommand(restartCommand);
693  }
694 
695  checkRestartVersion(sm);
696 
697  // finally: do session management
698  emit saveYourself(); // for compatibility
699  bool canceled = false;
700  foreach (KSessionManager *it, KSessionManager::sessionClients()) {
701  if (canceled) {
702  break;
703  }
704  canceled = !it->saveState(sm);
705  }
706 
707  // if we created a new session config object, register a proper discard command
710  QStringList discard;
712  sm.setDiscardCommand(discard);
713  } else {
715  }
716 
717  if (canceled) {
718  sm.cancel();
719  }
720 #else
721  Q_UNUSED(sm);
722 #endif
723  d->session_save = false;
724 }
725 
727 {
728  return d->session_save;
729 }
730 
731 void KApplicationPrivate::parseCommandLine()
732 {
733  KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
734 
735  if (args && args->isSet("style")) {
736  extern QString kde_overrideStyle; // see KGlobalSettings
737  QString reqStyle(args->getOption("style").toLower());
739  kde_overrideStyle = reqStyle;
740  } else {
741  qWarning() << i18n("The style '%1' was not found", reqStyle);
742  }
743  }
744 
745  if (args && args->isSet("config")) {
746  QString config = args->getOption("config");
747  componentData.setConfigName(config);
748  }
749 
750  if (args && args->isSet("icon")) {
751  q->setWindowIcon(QIcon::fromTheme(args->getOption("icon")));
752  } else {
753  q->setWindowIcon(QIcon::fromTheme(componentData.aboutData()->programIconName()));
754  }
755 
756  if (!args) {
757  return;
758  }
759 
760  if (!args->isSet("crashhandler")) {
761  // disable drkonqi (the old way)
763  }
764 
765 #if HAVE_X11
766  if (args->isSet("waitforwm")) {
767  Atom type;
768  (void) q->desktop(); // trigger desktop creation, we need PropertyNotify events for the root window
769  int format;
770  unsigned long length, after;
771  unsigned char *data;
772  while (XGetWindowProperty(QX11Info::display(), QX11Info::appRootWindow(), atom_NetSupported,
773  0, 1, false, AnyPropertyType, &type, &format,
774  &length, &after, &data) != Success || !length) {
775  if (data) {
776  XFree(data);
777  }
778  XEvent event;
779  XWindowEvent(QX11Info::display(), QX11Info::appRootWindow(), PropertyChangeMask, &event);
780  }
781  if (data) {
782  XFree(data);
783  }
784  }
785 #endif
786 
787 #ifndef Q_OS_WIN
788  if (args->isSet("smkey")) {
789  sessionKey = args->getOption("smkey");
790  }
791 #endif
792 }
793 
794 extern void kDebugCleanup();
795 
796 KApplication::~KApplication()
797 {
798 #if HAVE_X11
799  if (d->isX11) {
800  if (d->oldXErrorHandler != nullptr) {
801  XSetErrorHandler(d->oldXErrorHandler);
802  }
803  if (d->oldXIOErrorHandler != nullptr) {
804  XSetIOErrorHandler(d->oldXIOErrorHandler);
805  }
806  if (d->oldIceIOErrorHandler != nullptr) {
807  IceSetIOErrorHandler(d->oldIceIOErrorHandler);
808  }
809  }
810 #endif
811 
812  delete d;
813  KApp = nullptr;
814 
815 #if HAVE_X11
816  mySmcConnection = nullptr;
817 #endif
818 }
819 
820 #ifdef __GNUC__
821 #warning TODO kapp->installX11EventFilter needs to be ported to nativeEvent filters.
822 #endif
823 #if 0 // replaced with QWidget::nativeEvent in Qt5
824 class KAppX11HackWidget: public QWidget
825 {
826 public:
827  bool publicx11Event(XEvent *e)
828  {
829  return x11Event(e); // no such method anymore!
830  }
831 };
832 bool KApplication::x11EventFilter(XEvent *_event)
833 {
834  if (x11Filter) {
835  foreach (const QPointer< QWidget > &wp, *x11Filter) {
836  if (QWidget *w = wp.data())
837  if (static_cast<KAppX11HackWidget *>(w)->publicx11Event(_event)) {
838  return true;
839  }
840  }
841  }
842 
843  return false;
844 }
845 #endif
846 
848 {
849  KUserTimestamp::updateUserTimestamp(time);
850 }
851 
852 unsigned long KApplication::userTimestamp() const
853 {
854  return KUserTimestamp::userTimestamp();
855 }
856 
857 void KApplication::updateRemoteUserTimestamp(const QString &service, int time)
858 {
859 #if HAVE_X11
860  if (!d->isX11) {
861  return;
862  }
863  Q_ASSERT(service.contains('.'));
864  if (time == 0) {
865  time = QX11Info::appUserTime();
866  }
867  QDBusInterface(service, QLatin1String("/MainApplication"),
868  QString(QLatin1String("org.kde.KApplication")))
869  .call(QLatin1String("updateUserTimestamp"), time);
870 #endif
871 }
872 
873 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
875 {
876  QString aFilename;
877 
878  if (QDir::isRelativePath(pFilename)) {
879  kWarning(240) << "Relative filename passed to KApplication::tempSaveName";
880  aFilename = QFileInfo(QDir(QLatin1String(".")), pFilename).absoluteFilePath();
881  } else {
882  aFilename = pFilename;
883  }
884 
885  QDir aAutosaveDir(QDir::homePath() + QLatin1String("/autosave/"));
886  if (!aAutosaveDir.exists()) {
887  if (!aAutosaveDir.mkdir(aAutosaveDir.absolutePath())) {
888  // Last chance: use temp dir
889  aAutosaveDir.setPath(QDir::tempPath());
890  }
891  }
892 
893  aFilename.replace('/', QLatin1String("\\!"))
894  .prepend(QLatin1Char('#'))
895  .append(QLatin1Char('#'))
896  .prepend(QLatin1Char('/')).prepend(aAutosaveDir.absolutePath());
897 
898  return aFilename;
899 }
900 #endif
901 
903  bool &bRecover)
904 {
905  QString aFilename;
906 
907  if (QDir::isRelativePath(pFilename)) {
908  kWarning(240) << "Relative filename passed to KApplication::tempSaveName";
909  aFilename = QFileInfo(QDir(QLatin1String(".")), pFilename).absoluteFilePath();
910  } else {
911  aFilename = pFilename;
912  }
913 
914  QDir aAutosaveDir(QDir::homePath() + QLatin1String("/autosave/"));
915  if (!aAutosaveDir.exists()) {
916  if (!aAutosaveDir.mkdir(aAutosaveDir.absolutePath())) {
917  // Last chance: use temp dir
918  aAutosaveDir.setPath(QDir::tempPath());
919  }
920  }
921 
922  aFilename.replace(QLatin1String("/"), QLatin1String("\\!"))
923  .prepend(QLatin1Char('#'))
924  .append(QLatin1Char('#'))
925  .prepend(QLatin1Char('/'))
926  .prepend(aAutosaveDir.absolutePath());
927 
928  if (QFile(aFilename).exists()) {
929  bRecover = true;
930  return aFilename;
931  } else {
932  bRecover = false;
933  return pFilename;
934  }
935 }
936 
938 {
939  if (!topWidget) {
940  return;
941  }
942 
943  // set the specified caption
944  if (!topWidget->inherits("KMainWindow")) { // KMainWindow does this already for us
945  topWidget->setWindowTitle(KGlobal::caption());
946  }
947 
948 #if HAVE_X11
949  // set the app startup notification window property
951 #endif
952 }
953 
955 {
956  return KStartupInfo::startupId();
957 }
958 
959 void KApplication::setStartupId(const QByteArray &startup_id)
960 {
961  KStartupInfo::setStartupId(startup_id);
962 }
963 
965 {
967 }
968 
969 // Hook called by KToolInvocation
970 void KApplicationPrivate::_k_slot_KToolInvocation_hook(QStringList &envs, QByteArray &startup_id)
971 {
972 #if HAVE_X11
973  if (!isX11) {
974  return;
975  }
976  if (QX11Info::display()) {
977  QByteArray dpystring(XDisplayString(QX11Info::display()));
978  envs << QLatin1String("DISPLAY=") + dpystring;
979  } else {
980  const QByteArray dpystring(qgetenv("DISPLAY"));
981  if (!dpystring.isEmpty()) {
982  envs << QLatin1String("DISPLAY=") + dpystring;
983  }
984  }
985 
986  if (startup_id.isEmpty()) {
987  startup_id = KStartupInfo::createNewStartupId();
988  }
989 #else
990  Q_UNUSED(envs);
991  Q_UNUSED(startup_id);
992 #endif
993 }
994 
995 #include "moc_kapplication.cpp"
QString caption()
Returns a text for the window caption.
Definition: kglobal.cpp:175
Controls and provides information to all KDE applications.
Definition: kapplication.h:76
static QString tempSaveName(const QString &pFilename)
Get a file name in order to make a temporary copy of your document.
QString & append(QChar ch)
bool isHidden() const const
T * data() const const
QString writableLocation(QStandardPaths::StandardLocation type)
QByteArray toLower() const const
virtual bool saveState(QSessionManager &sm)
See QApplication::saveState() for documentation.
static QString checkRecoverFile(const QString &pFilename, bool &bRecover)
Check whether an auto-save file exists for the document you want to open.
static KCmdLineArgs * parsedArgs(const QByteArray &id=QByteArray())
Access parsed arguments.
QString & prepend(QChar ch)
void setStartupId(const QByteArray &startup_id)
QStringList restartCommand() const const
A class for command-line argument handling.
Definition: kcmdlineargs.h:286
bool isNull() const const
bool registerObject(const QString &path, QObject *object, QDBusConnection::RegisterOptions options)
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
Q_SCRIPTABLE void updateUserTimestamp(int time=0)
bool isEmpty() const const
QString findExecutable(const QString &executableName, const QStringList &paths)
KApplication(bool GUIenabled=true)
This constructor is the one you should use.
#define KDE_VERSION_MAJOR
Major version of KDE, at compile time.
Definition: kdeversion.h:55
QDBusConnection sessionBus()
void setOrganizationDomain(const QString &orgDomain)
void disableSessionManagement()
Disables session management for this application.
bool exists() const const
static KGlobalSettings * self()
Return the KGlobalSettings singleton.
void enableSessionManagement()
Enables session management for this application, formerly disabled by calling disableSessionManagemen...
QString homePath()
The file contains macros and functions related to the KDE version.
static KApplication * KApp
Current application object.
Definition: kapplication.h:411
static KApplication * kApplication()
Returns the current application object.
QString sessionKey() const const
bool isSet(const QByteArray &option) const
Read out a boolean option or check for the presence of string option.
KSharedConfigPtr config()
Returns the general config object.
Definition: kglobal.cpp:102
static void setWindowStartupId(WId window, const QByteArray &id)
static QByteArray startupId()
static void setStartupId(const QByteArray &startup_id)
void exit(int returnCode)
QStringList keys()
void setFallbackSessionManagementEnabled(bool enabled)
QString number(int n, int base)
bool exists() const const
Provides highlevel access to session management on a per-object base.
bool sync() override
void append(const T &value)
PartitionTable::TableType type
bool isAccepted() const const
KCOREADDONS_EXPORT void setMessageHandler(KMessageHandler *handler)
QString tempPath()
QByteArray startupId() const
bool inherits(const char *className) const const
void saveYourself()
CaseInsensitive
bool isEmpty() const const
QString absoluteFilePath() const const
bool isEmpty() const const
bool sendEvent(QObject *receiver, QEvent *event)
void commitData(QSessionManager &sm)
Slot connected to QGuiApplication::commitDataRequest() to implement highlevel handling of session man...
void setTopWidget(QWidget *topWidget)
Sets the top widget of the application.
void setRestartHint(QSessionManager::RestartHint hint)
WId winId() const const
bool allowsInteraction()
static KLocale * global()
Return the global KLocale instance.
Definition: klocale.cpp:309
void commitDataRequest(QSessionManager &manager)
void setRestartCommand(const QStringList &command)
virtual bool commitData(QSessionManager &sm)
See QApplication::commitData() for documentation.
QString toLower() const const
void saveState(QSessionManager &sm)
Slot connected to QGuiApplication::saveStateRequest() to implement highlevel handling of session mana...
void removeX11EventFilter(const QWidget *filter)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isRelativePath(const QString &path)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QCA_EXPORT void init()
void updateRemoteUserTimestamp(const QString &service, int time=0)
Updates the last user action timestamp in the application registered to DBUS with id service to the g...
QString i18n(const char *text, const TYPE &arg...)
if(recurs()&&!first)
QString & replace(int position, int n, QChar after)
bool sessionSaving() const
QDBusMessage call(const QString &method, Args &&...args)
static QByteArray createNewStartupId()
virtual bool event(QEvent *e) override
void saveStateRequest(QSessionManager &manager)
QString absolutePath() const const
bool mkdir(const QString &dirName) const const
unsigned int version()
Returns the encoded number of KDE&#39;s version, see the KDE_VERSION macro.
Definition: kdeversion.cpp:24
void setWindowTitle(const QString &)
KCONFIGCORE_EXPORT bool authorize(const QString &action)
void setDesktopSettingsAware(bool on)
KCONFIGGUI_EXPORT KConfig * sessionConfig()
KCRASH_EXPORT void setDrKonqiEnabled(bool enabled)
bool isSystemTrayAvailable()
QString getOption(const QByteArray &option) const
Read out a string option.
void prepend(const T &value)
QIcon fromTheme(const QString &name)
KConfig * sessionConfig()
QDBusReply< QDBusConnectionInterface::RegisterServiceReply > registerService(const QString &serviceName, QDBusConnectionInterface::ServiceQueueOptions qoption, QDBusConnectionInterface::ServiceReplacementOptions roption)
void activate()
Makes all globally applicable settings take effect and starts listening for changes to these settings...
This is a convience KMessageHandler that use KMessageBox.
unsigned long userTimestamp() const
void clearStartupId()
void setDiscardCommand(const QStringList &command)
KCONFIGGUI_EXPORT QString sessionConfigName()
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KCONFIGGUI_EXPORT bool hasSessionConfig()
QString platformName()
void installX11EventFilter(QWidget *filter)
Per component data.
void destroyed(QObject *obj)
QWidgetList topLevelWidgets()
void setPath(const QString &path)
void setIcon(const QIcon &icon)
void setApplicationName(const QString &application)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Dec 6 2021 22:50:57 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.