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());
738  if (QStyleFactory::keys().contains(reqStyle, Qt::CaseInsensitive)) {
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"
unsigned long userTimestamp() const
void append(const T &value)
void setRestartHint(QSessionManager::RestartHint hint)
void setDiscardCommand(const QStringList &command)
bool isNull() const const
KConfig * sessionConfig()
bool exists() const const
Controls and provides information to all KDE applications.
Definition: kapplication.h:76
QByteArray toLower() const const
void clearStartupId()
QTextStream & endl(QTextStream &stream)
QString number(int n, int base)
void setFallbackSessionManagementEnabled(bool enabled)
QStringList restartCommand() const const
static KApplication * KApp
Current application object.
Definition: kapplication.h:411
void disableSessionManagement()
Disables session management for this application.
CaseInsensitive
QString getOption(const QByteArray &option) const
Read out a string option.
Type type(const QSqlDatabase &db)
static KApplication * kApplication()
Returns the current application object.
static KGlobalSettings * self()
Return the KGlobalSettings singleton.
QCA_EXPORT void init()
KCOREADDONS_EXPORT void setMessageHandler(KMessageHandler *handler)
bool isSystemTrayAvailable()
QString & prepend(QChar ch)
QIcon fromTheme(const QString &name)
static void setStartupId(const QByteArray &startup_id)
bool inherits(const char *className) const const
void setIcon(const QIcon &icon)
bool mkdir(const QString &dirName) const const
static KCmdLineArgs * parsedArgs(const QByteArray &id=QByteArray())
Access parsed arguments.
QString writableLocation(QStandardPaths::StandardLocation type)
bool isSet(const QByteArray &option) const
Read out a boolean option or check for the presence of string option.
void saveYourself()
virtual bool saveState(QSessionManager &sm)
See QApplication::saveState() for documentation.
bool registerObject(const QString &path, QObject *object, QDBusConnection::RegisterOptions options)
QDBusMessage call(const QString &method, Args &&... args)
QString homePath()
KCONFIGGUI_EXPORT bool hasSessionConfig()
bool sync() override
QString caption()
Returns a text for the window caption.
Definition: kglobal.cpp:175
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setOrganizationDomain(const QString &orgDomain)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
void commitData(QSessionManager &sm)
Slot connected to QGuiApplication::commitDataRequest() to implement highlevel handling of session man...
Provides highlevel access to session management on a per-object base.
static QString checkRecoverFile(const QString &pFilename, bool &bRecover)
Check whether an auto-save file exists for the document you want to open.
virtual bool commitData(QSessionManager &sm)
See QApplication::commitData() for documentation.
QString tempPath()
void setPath(const QString &path)
QString findExecutable(const QString &executableName, const QStringList &paths)
void destroyed(QObject *obj)
void prepend(const T &value)
QString i18n(const char *text, const TYPE &arg...)
QDBusConnection sessionBus()
KApplication(bool GUIenabled=true)
This constructor is the one you should use.
QString absoluteFilePath() const const
A class for command-line argument handling.
Definition: kcmdlineargs.h:286
bool sendEvent(QObject *receiver, QEvent *event)
void removeX11EventFilter(const QWidget *filter)
bool isAccepted() const const
bool isEmpty() const const
void enableSessionManagement()
Enables session management for this application, formerly disabled by calling disableSessionManagemen...
void setWindowTitle(const QString &)
bool sessionSaving() const
The file contains macros and functions related to the KDE version.
static QByteArray createNewStartupId()
static void setWindowStartupId(WId window, const QByteArray &id)
bool isEmpty() const const
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
QStringList keys()
KSharedConfigPtr config()
Returns the general config object.
Definition: kglobal.cpp:102
void setDesktopSettingsAware(bool on)
QString absolutePath() const const
Per component data.
void setApplicationName(const QString &application)
void activate()
Makes all globally applicable settings take effect and starts listening for changes to these settings...
QString & replace(int position, int n, QChar after)
KCONFIGCORE_EXPORT bool authorize(const QString &action)
KCRASH_EXPORT void setDrKonqiEnabled(bool enabled)
QString toLower() const const
bool isEmpty() const const
#define KDE_VERSION_MAJOR
Major version of KDE, at compile time.
Definition: kdeversion.h:55
unsigned int version()
Returns the encoded number of KDE's version, see the KDE_VERSION macro.
Definition: kdeversion.cpp:24
void setTopWidget(QWidget *topWidget)
Sets the top widget of the application.
static KLocale * global()
Return the global KLocale instance.
Definition: klocale.cpp:309
KCONFIGGUI_EXPORT QString sessionConfigName()
void setRestartCommand(const QStringList &command)
bool allowsInteraction()
This is a convience KMessageHandler that use KMessageBox.
void installX11EventFilter(QWidget *filter)
QWidgetList topLevelWidgets()
Q_SCRIPTABLE Q_NOREPLY void abort()
WId winId() const const
void saveState(QSessionManager &sm)
Slot connected to QGuiApplication::saveStateRequest() to implement highlevel handling of session mana...
bool isRelativePath(const QString &path)
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...
static QString tempSaveName(const QString &pFilename)
Get a file name in order to make a temporary copy of your document.
static QByteArray startupId()
KCONFIGGUI_EXPORT KConfig * sessionConfig()
T * data() const const
bool isHidden() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString & append(QChar ch)
void setStartupId(const QByteArray &startup_id)
QDBusReply< QDBusConnectionInterface::RegisterServiceReply > registerService(const QString &serviceName, QDBusConnectionInterface::ServiceQueueOptions qoption, QDBusConnectionInterface::ServiceReplacementOptions roption)
QByteArray startupId() const
Q_SCRIPTABLE void updateUserTimestamp(int time=0)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Jun 27 2022 04:06:18 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.