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

KDE's Doxygen guidelines are available online.