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 | |
20 | typedef struct _XDisplay Display; |
21 | |
22 | struct xcb_connection_t; |
23 | |
24 | class KStartupInfoId; |
25 | class 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 | */ |
47 | class KWINDOWSYSTEM_EXPORT KStartupInfo : public QObject |
48 | { |
49 | Q_OBJECT |
50 | public: |
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; |
323 | Q_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 | |
352 | protected: |
353 | void customEvent(QEvent *e_P) override; |
354 | |
355 | private: |
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 | */ |
379 | class KWINDOWSYSTEM_EXPORT KStartupInfoId |
380 | { |
381 | public: |
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 | |
437 | private: |
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 | */ |
457 | class KWINDOWSYSTEM_EXPORT KStartupInfoData |
458 | { |
459 | public: |
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 | |
647 | private: |
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 | |