1/*
2 SPDX-FileCopyrightText: 2001-2003 Lubos Lunak <l.lunak@kde.org>
3
4 SPDX-License-Identifier: MIT
5*/
6
7#ifndef KSTARTUPINFO_H
8#define KSTARTUPINFO_H
9
10#include <kwindowsystem_export.h>
11
12#include <QChildEvent>
13#include <QObject>
14#include <QString>
15#include <QWidgetList> // for WId
16#include <QWindow>
17
18#include <sys/types.h>
19
20typedef struct _XDisplay Display;
21
22struct xcb_connection_t;
23
24class KStartupInfoId;
25class KStartupInfoData;
26
27/*!
28 * \class KStartupInfo
29 * \inmodule KWindowSystem
30 * \brief Class for manipulating the application startup notification.
31 *
32 * This class can be used to send information about started application,
33 * change the information and receive this information. For detailed
34 * description, see \l https://invent.kde.org/frameworks/kwindowsystem/-/blob/master/docs/README.kstartupinfo.
35 *
36 * You usually don't need to use this class for sending the notification
37 * information, as KDE libraries should do this when an application is
38 * started (e.g. KRun class).
39 *
40 * For receiving the startup notification info, create an instance and connect
41 * to its slots. It will automatically detect started applications and when
42 * they are ready.
43 *
44 * \sa KStartupInfoId
45 * \sa KStartupInfoData
46 */
47class KWINDOWSYSTEM_EXPORT KStartupInfo : public QObject
48{
49 Q_OBJECT
50public:
51 /*!
52 * \brief Manual notification that the application has started.
53 *
54 * If you do not map a (toplevel) window, then startup
55 * notification will not disappear for the application
56 * until a timeout. You can use this as an alternative
57 * method in this case.
58 */
59 static void appStarted();
60
61 /*!
62 * \brief Sends explicit notification that the startup notification
63 * with \a startup_id should end.
64 */
65 static void appStarted(const QByteArray &startup_id);
66
67 /*!
68 * \brief Sets a new value for the application startup notification
69 * window property for newly created toplevel windows.
70 *
71 * \a startup_id The startup notification identifier.
72 *
73 * \sa KStartupInfo::setNewStartupId
74 */
75 static void setStartupId(const QByteArray &startup_id);
76
77 /*!
78 * \brief Use this function if the application got a request with startup
79 * notification from outside (for example, when KUniqueApplication::newInstance()
80 * is called, or e.g. when KHelpCenter opens a new URL in its window).
81 *
82 * The \a window can be either an already existing and visible window,
83 * or a new one, before being shown. Note that this function is usually
84 * needed only when a window is reused.
85 *
86 * \a startup_id the startup notification identifier
87 */
88 static void setNewStartupId(QWindow *window, const QByteArray &startup_id);
89
90 /*!
91 * \brief Creates and returns a new startup id. The id includes properly setup
92 * user timestamp.
93 *
94 * On the X11 platform the current timestamp will be fetched from the
95 * X-Server. If the caller has an adequate timestamp (e.g. from a QMouseEvent)
96 * it should prefer using createNewStartupIdForTimestamp to not trigger a
97 * roundtrip to the X-Server.
98 *
99 * \sa createNewStartupIdForTimestamp
100 */
101 static QByteArray createNewStartupId();
102 /*!
103 * \brief Creates and returns new startup id with \a timestamp
104 * as user timestamp part.
105 *
106 * \a timestamp The timestamp for the startup id.
107 *
108 * \sa createNewStartupId
109 * \since 5.5
110 **/
111 static QByteArray createNewStartupIdForTimestamp(quint32 timestamp);
112
113 enum {
114 CleanOnCantDetect = 1 << 0,
115 DisableKWinModule = 1 << 1,
116 AnnounceSilenceChanges = 1 << 2,
117 };
118
119 /*!
120 * \brief Creates an instance that will receive the startup notifications,
121 * as a child of \a parent.
122 *
123 * The various \a flags passed may be:
124 * \value CleanOnCantDetect
125 * When a new unknown window appears, all startup
126 * notifications for applications that are not compliant with
127 * the startup protocol are removed.
128 * \value DisableKWinModule
129 * KWinModule, which is normally used to detect new windows,
130 * is disabled. With this flag, checkStartup() must be
131 * called in order to check newly mapped windows.
132 * \value AnnounceSilenceChanges
133 * Normally, startup notifications are "removed"
134 * when they're silenced, and "recreated" when they're resumed.
135 * With this flag, the change is normally announced with gotStartupChange().
136 */
137 explicit KStartupInfo(int flags, QObject *parent = nullptr);
138
139 ~KStartupInfo() override;
140 /*!
141 * \brief Sends given notification data about started application
142 * with the given startup identification.
143 *
144 * If no notification for this identification
145 * exists yet, it is created, otherwise it's updated. Note that the name field
146 * in data is required.
147 *
148 * Returns \c true if successful, \c false otherwise
149 *
150 * \a id The id of the application.
151 *
152 * \a data The application's data.
153 *
154 * \sa KStartupInfoId
155 * \sa KStartupInfoData
156 */
157 static bool sendStartup(const KStartupInfoId &id, const KStartupInfoData &data);
158
159 /*!
160 * \brief Like sendStartup, uses \a conn instead of
161 * QX11Info::connection() for sending the info.
162 *
163 * Returns \c true if successful, \c false otherwise.
164 *
165 * \a conn The xcb connection of the application. Note that the name field
166 * in data is required.
167 *
168 * \a screen The x11 screen the connection belongs to.
169 *
170 * \a id The id of the application.
171 *
172 * \a data The application's data.
173 *
174 * \since 5.18
175 */
176 static bool sendStartupXcb(xcb_connection_t *conn, int screen, const KStartupInfoId &id, const KStartupInfoData &data);
177
178 /*!
179 * \brief Sends given notification data about started application
180 * with the given startup identification.
181 *
182 * This is used for updating the notification
183 * info, if no notification for this identification exists, it's ignored.
184 *
185 * Returns \c true if successful, \c false otherwise.
186 *
187 * \a id The id of the application.
188 *
189 * \a data The application's data.
190 *
191 * \sa KStartupInfoId
192 * \sa KStartupInfoData
193 */
194 static bool sendChange(const KStartupInfoId &id, const KStartupInfoData &data);
195
196 /*!
197 * \brief Like sendChange, uses \a conn instead of
198 * QX11Info::connection() for sending the info.
199 *
200 * Returns \c true if successful, \c false otherwise.
201 *
202 * \a conn The xcb connection of the application.
203 *
204 * \a screen The x11 screen the connection belongs to.
205 *
206 * \a id The id of the application.
207 *
208 * \a data The application's data.
209 *
210 * \since 5.18
211 */
212 static bool sendChangeXcb(xcb_connection_t *conn, int screen, const KStartupInfoId &id, const KStartupInfoData &data);
213
214 /*!
215 * \brief Ends startup notification with the given identification.
216 *
217 * Returns \c true if successful, \c false otherwise
218 *
219 * \a id The id of the application.
220 */
221 static bool sendFinish(const KStartupInfoId &id);
222
223 /*!
224 * \brief Like sendFinish , uses \a conn instead of
225 * QX11Info::connection() for sending the info.
226 *
227 * Returns \c true if successful, \c false otherwise.
228 *
229 * \a conn The xcb connection of the application.
230 *
231 * \a screen The x11 screen the connection belongs to.
232 *
233 * \a id The id of the application.
234 *
235 * \since 5.18
236 */
237 static bool sendFinishXcb(xcb_connection_t *conn, int screen, const KStartupInfoId &id);
238
239 /*!
240 * \brief Ends startup notification with the given identification and the given data
241 * (e.g.\ PIDs of processes for this startup notification that exited).
242 *
243 * Returns \c true if successful, \c false otherwise
244 *
245 * \a id The id of the application.
246 *
247 * \a data The application's data.
248 */
249 static bool sendFinish(const KStartupInfoId &id, const KStartupInfoData &data);
250
251 /*!
252 * \brief Like sendFinish , uses \a conn instead of
253 * QX11Info::connection() for sending the info.
254 *
255 * Returns \c true if successful, \c false otherwise.
256 *
257 * \a conn The xcb connection of the application.
258 *
259 * \a screen The x11 screen the connection belongs to.
260 *
261 * \a id The id of the application.
262 *
263 * \a data The application's data.
264 *
265 * \since 5.18
266 */
267 static bool sendFinishXcb(xcb_connection_t *conn, int screen, const KStartupInfoId &id, const KStartupInfoData &data);
268
269 /*!
270 * \brief Unsets the startup notification environment variable.
271 */
272 static void resetStartupEnv();
273 /*!
274 * \enum KStartupInfo::startup_t
275 * \value NoMatch
276 * The window doesn't match any existing startup notification.
277 * \value Match
278 * The window matches an existing startup notification.
279 * \value CantDetect
280 * Unable to detect if the window matches any existing
281 * startup notification.
282 */
283 enum startup_t { NoMatch, Match, CantDetect };
284 /*!
285 * \brief Checks if the given window \a w matches any existing startup notification.
286 */
287 startup_t checkStartup(WId w);
288 /*!
289 * \brief Checks if the given window \a w matches any existing startup notification,
290 * if yes, returns the identification in \a id.
291 */
292 startup_t checkStartup(WId w, KStartupInfoId &id);
293 /*!
294 * \brief Checks if the given window \a w matches any existing startup notification,
295 * if yes, returns the notification data in \a data.
296 */
297 startup_t checkStartup(WId w, KStartupInfoData &data);
298 /*!
299 * \brief Checks if the given window \a w matches any existing startup notification,
300 * if yes, returns the identification in \a id and notification data in \a data.
301 */
302 startup_t checkStartup(WId w, KStartupInfoId &id, KStartupInfoData &data);
303 /*!
304 * \brief Sets the timeout for notifications in \a secs,
305 * after this timeout a notification is removed.
306 */
307 void setTimeout(unsigned int secs);
308 /*!
309 * \brief Returns startup notification identification of the given window \a w.
310 *
311 * Returns the startup notification id. Can be null if not found.
312 */
313 static QByteArray windowStartupId(WId w);
314 /*!
315 * \internal
316 */
317 class Data;
318
319 /*!
320 * \internal
321 */
322 class Private;
323Q_SIGNALS:
324 /*!
325 * \brief Emitted when a new startup notification is created
326 * (i.e. a new application is being started).
327 *
328 * \a id The notification identification.
329 *
330 * \a data The notification data.
331 */
332 void gotNewStartup(const KStartupInfoId &id, const KStartupInfoData &data);
333 /*!
334 * \brief Emitted when a startup notification changes.
335 *
336 * \a id The notification identification.
337 *
338 * \a data The notification data.
339 */
340 void gotStartupChange(const KStartupInfoId &id, const KStartupInfoData &data);
341 /*!
342 * \brief Emitted when a startup notification is removed
343 * (either because it was detected
344 * that the application is ready or because of a timeout).
345 *
346 * \a id The notification identification.
347 *
348 * \a data The notification data.
349 */
350 void gotRemoveStartup(const KStartupInfoId &id, const KStartupInfoData &data);
351
352protected:
353 void customEvent(QEvent *e_P) override;
354
355private:
356 Q_PRIVATE_SLOT(d, void startups_cleanup())
357 Q_PRIVATE_SLOT(d, void startups_cleanup_no_age())
358 Q_PRIVATE_SLOT(d, void got_message(const QString &msg))
359 Q_PRIVATE_SLOT(d, void window_added(WId w))
360 Q_PRIVATE_SLOT(d, void slot_window_added(WId w))
361
362 Private *const d;
363
364 Q_DISABLE_COPY(KStartupInfo)
365};
366
367/*!
368 * \class KStartupInfoId
369 * \inheaderfile KStartupInfo
370 * \inmodule KWindowSystem
371 * \brief Class representing an identification of application startup notification.
372 *
373 * Every existing notification about a starting application has its own unique
374 * identification, that's used to identify and manipulate the notification.
375 *
376 * \sa KStartupInfo
377 * \sa KStartupInfoData
378 */
379class KWINDOWSYSTEM_EXPORT KStartupInfoId
380{
381public:
382 /*!
383 * \brief Overloaded operator.
384 *
385 * Returns \c true if the given notification \a id is the same.
386 */
387 bool operator==(const KStartupInfoId &id) const;
388 /*!
389 * \brief Overloaded operator.
390 *
391 * Returns \c true if the given notification \a id is different.
392 */
393 bool operator!=(const KStartupInfoId &id) const;
394 /*!
395 * \brief Checks whether the identifier is valid.
396 *
397 * Returns true if this object doesn't represent a valid notification identification.
398 */
399 bool isNull() const;
400
401 /*!
402 * Initializes this object with the given identification (which may be also "0"
403 * for no notification), or if "" is given, tries to read it from the startup
404 * notification environment variable, and if it's not set, creates a new one.
405 *
406 * \a id The new identification, "0" for no notification or "" to read
407 * the environment variable.
408 */
409 void initId(const QByteArray &id = "");
410 /*!
411 * Returns the notification identifier as string.
412 */
413 const QByteArray &id() const;
414 /*!
415 * Returns the user timestamp for the startup notification, or 0 if no timestamp
416 * is set.
417 */
418 unsigned long timestamp() const;
419 /*!
420 * Sets the startup notification environment variable to this identification.
421 *
422 * Returns \c true if successful, \c false otherwise.
423 */
424 bool setupStartupEnv() const;
425 /*!
426 * Creates an empty identification
427 */
428 KStartupInfoId();
429 /*!
430 * Copy constructor.
431 */
432 KStartupInfoId(const KStartupInfoId &data);
433 ~KStartupInfoId();
434 KStartupInfoId &operator=(const KStartupInfoId &data);
435 bool operator<(const KStartupInfoId &id) const;
436
437private:
438 explicit KStartupInfoId(const QString &txt);
439 friend class KStartupInfo;
440 friend class KStartupInfo::Private;
441 struct Private;
442 Private *const d;
443};
444
445/*!
446 * \class KStartupInfoData
447 * \inheaderfile KStartupInfo
448 * \inmodule KWindowSystem
449 * \brief Class representing data about an application startup notification.
450 *
451 * Such data include the icon of the starting application, the desktop on which
452 * the application should start, the binary name of the application, etc.
453 *
454 * \sa KStartupInfo
455 * \sa KStartupInfoId
456 */
457class KWINDOWSYSTEM_EXPORT KStartupInfoData
458{
459public:
460 /*!
461 * Sets the binary name \a bin of the application (e.g. 'kcontrol').
462 */
463 void setBin(const QString &bin);
464 /*!
465 * \brief Returns the binary name of the starting application.
466 */
467 const QString &bin() const;
468 /*!
469 * Sets the \a name for the notification (e.g. 'Control Center').
470 */
471 void setName(const QString &name);
472 /*!
473 * \brief Returns the name of the startup notification.
474 *
475 * If it's not available, it tries to use other information (binary name).
476 */
477 const QString &findName() const;
478 /*!
479 * Returns the name of the startup notification,
480 * or an empty string if not set.
481 */
482 const QString &name() const;
483 /*!
484 * Sets the description \a descr for the notification (e.g. 'Launching Control Center').
485 *
486 * That is, name() describes what is being started, while description() is
487 * the actual action performed by the starting.
488 */
489 void setDescription(const QString &descr);
490 /*!
491 * Returns the description of the startup notification.
492 *
493 * If it's not available, it returns name().
494 */
495 const QString &findDescription() const;
496 /*!
497 * Returns the name of the startup notification,
498 * or an empty string if not set.
499 */
500 const QString &description() const;
501 /*!
502 * Sets the \a icon for the startup notification (e.g.\ 'kcontrol').
503 */
504 void setIcon(const QString &icon);
505 /*!
506 * Returns the icon of the startup notification, and if it's not available,
507 * tries to get it from the binary name.
508 */
509 const QString &findIcon() const;
510 /*!
511 * Returns the name of the startup notification icon,
512 * or an empty string if not set.
513 */
514 const QString &icon() const;
515 /*!
516 * Sets the \a desktop for the startup notification (i.e. the desktop on which
517 * the starting application should appear).
518 */
519 void setDesktop(int desktop);
520 /*!
521 * Returns the desktop for the startup notification.
522 */
523 int desktop() const;
524 /*!
525 * \brief Sets a WM_CLASS value \a wmclass for the startup notification.
526 *
527 * It may be used for increasing the chance that the windows created
528 * by the starting application will be detected correctly.
529 */
530 void setWMClass(const QByteArray &wmclass);
531 /*!
532 * Returns the WM_CLASS value for the startup notification, or binary name if not
533 * available.
534 */
535 const QByteArray findWMClass() const;
536 /*!
537 * Returns the WM_CLASS value for the startup notification,
538 * or empty if not available.
539 */
540 QByteArray WMClass() const;
541 /*!
542 * Adds a PID \a pid to the list of processes that belong to the startup notification.
543 *
544 * It may be used to increase the chance that the windows created by the starting
545 * application will be detected correctly, and also for detecting if the application
546 * has quit without creating any window.
547 */
548 void addPid(pid_t pid);
549 /*!
550 * Returns all PIDs for the startup notification.
551 */
552 QList<pid_t> pids() const;
553 /*!
554 * Returns \c true if the given \a pid is in the list of PIDs for the startup notification
555 */
556 bool is_pid(pid_t pid) const;
557 /*!
558 * \brief Sets the \a hostname on which the application is starting.
559 *
560 * It's necessary to set it if PIDs are set.
561 * If it's a null string, the current hostname is used.
562 */
563 void setHostname(const QByteArray &hostname = QByteArray());
564 /*!
565 * Returns the hostname for the startup notification.
566 */
567 QByteArray hostname() const;
568
569 /*!
570 * \enum KStartupInfoData::TriState
571 * \value Yes
572 * \value No
573 * \value Unknown
574 */
575 enum TriState { Yes, No, Unknown };
576
577 /*!
578 * Sets whether the visual feedback for this startup notification
579 * with the given \a state should be silenced (temporarily suspended).
580 */
581 void setSilent(TriState state);
582
583 /*!
584 * Returns KStartupInfoData::Yes if visual feedback
585 * for the startup notification is silenced.
586 */
587 TriState silent() const;
588
589 /*!
590 * The X11 screen on which the startup notification is happening, -1 if unknown.
591 */
592 int screen() const;
593
594 /*!
595 * Sets the X11 \a screen on which the startup notification should happen.
596 *
597 * This is usually not necessary to set, as it's set by default to QX11Info::screen().
598 */
599 void setScreen(int screen);
600
601 /*!
602 * The Xinerama screen for the startup notification, -1 if unknown.
603 */
604 int xinerama() const;
605
606 /*!
607 * Sets the \a xinerama screen for the startup notification (i.e. the screeen on which
608 * the starting application should appear).
609 */
610 void setXinerama(int xinerama);
611
612 /*!
613 * The .desktop file used to initiate this startup notification, or empty.
614 *
615 * This information should be used only to identify the application,
616 * not to read any additional information.
617 * \since 4.5
618 **/
619 QString applicationId() const;
620
621 /*!
622 * Sets the \a desktop file that was used to initiate the startup notification.
623 * \since 4.5
624 */
625 void setApplicationId(const QString &desktop);
626
627 /*!
628 * Updates the notification data from the given \a data.
629 *
630 * Some data, such as the desktop or the name,
631 * won't be rewritten if already set.
632 */
633 void update(const KStartupInfoData &data);
634
635 /*!
636 * Constructor. Initializes all the data to their default empty values.
637 */
638 KStartupInfoData();
639
640 /*!
641 * Copy constructor.
642 */
643 KStartupInfoData(const KStartupInfoData &data);
644 ~KStartupInfoData();
645 KStartupInfoData &operator=(const KStartupInfoData &data);
646
647private:
648 explicit KStartupInfoData(const QString &txt);
649 friend class KStartupInfo;
650 friend class KStartupInfo::Data;
651 friend class KStartupInfo::Private;
652 struct Private;
653 Private *const d;
654};
655
656#endif
657

source code of kwindowsystem/src/kstartupinfo.h