1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6     SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
7 
8     SPDX-License-Identifier: GPL-2.0-or-later
9 */
10 
11 #pragma once
12 
13 // kwin
14 #include "decorationitem.h"
15 #include "abstract_client.h"
16 #include "xcbutils.h"
17 // Qt
18 #include <QElapsedTimer>
19 #include <QFlags>
20 #include <QPointer>
21 #include <QPixmap>
22 #include <QWindow>
23 // X
24 #include <xcb/sync.h>
25 
26 // TODO: Cleanup the order of things in this .h file
27 
28 class QTimer;
29 class KStartupInfoData;
30 class KStartupInfoId;
31 
32 namespace KWin
33 {
34 
35 
36 /**
37  * @brief Defines Predicates on how to search for a Client.
38  *
39  * Used by Workspace::findClient.
40  */
41 enum class Predicate {
42     WindowMatch,
43     WrapperIdMatch,
44     FrameIdMatch,
45     InputIdMatch,
46 };
47 
48 /**
49  * @todo Remove when the X11 platform support is dropped. This decoration renderer
50  * will be used if compositing is off.
51  */
52 class X11DecorationRenderer : public DecorationRenderer
53 {
54     Q_OBJECT
55 
56 public:
57     explicit X11DecorationRenderer(Decoration::DecoratedClientImpl *client);
58     ~X11DecorationRenderer() override;
59 
60 protected:
61     void render(const QRegion &region) override;
62 
63 private:
64     void update();
65 
66     QTimer *m_scheduleTimer;
67     xcb_gcontext_t m_gc;
68 };
69 
70 class KWIN_EXPORT X11Client : public AbstractClient
71 {
72     Q_OBJECT
73     /**
74      * By how much the window wishes to grow/shrink at least. Usually QSize(1,1).
75      * MAY BE DISOBEYED BY THE WM! It's only for information, do NOT rely on it at all.
76      * The value is evaluated each time the getter is called.
77      * Because of that no changed signal is provided.
78      */
79     Q_PROPERTY(QSize basicUnit READ basicUnit)
80     /**
81      * A client can block compositing. That is while the Client is alive and the state is set,
82      * Compositing is suspended and is resumed when there are no Clients blocking compositing any
83      * more.
84      *
85      * This is actually set by a window property, unfortunately not used by the target application
86      * group. For convenience it's exported as a property to the scripts.
87      *
88      * Use with care!
89      */
90     Q_PROPERTY(bool blocksCompositing READ isBlockingCompositing WRITE setBlockingCompositing NOTIFY blockingCompositingChanged)
91     /**
92      * Whether the Client uses client side window decorations.
93      * Only GTK+ are detected.
94      */
95     Q_PROPERTY(bool clientSideDecorated READ isClientSideDecorated NOTIFY clientSideDecoratedChanged)
96 public:
97     explicit X11Client();
98     ~X11Client() override; ///< Use destroyClient() or releaseWindow()
99 
100     xcb_window_t wrapperId() const;
inputId()101     xcb_window_t inputId() const { return m_decoInputExtent; }
102     xcb_window_t frameId() const override;
103 
104     QRect inputGeometry() const override;
105 
106     QPoint framePosToClientPos(const QPoint &point) const override;
107     QPoint clientPosToFramePos(const QPoint &point) const override;
108     QSize frameSizeToClientSize(const QSize &size) const override;
109     QSize clientSizeToFrameSize(const QSize &size) const override;
110     QRect frameRectToBufferRect(const QRect &rect) const;
111 
112     QMatrix4x4 inputTransformation() const override;
113 
114     bool isTransient() const override;
115     bool groupTransient() const override;
116     bool wasOriginallyGroupTransient() const;
117     QList<AbstractClient*> mainClients() const override; // Call once before loop , is not indirect
118     bool hasTransient(const AbstractClient* c, bool indirect) const override;
119     void checkTransient(xcb_window_t w);
120     AbstractClient* findModal(bool allow_itself = false) override;
121     const Group* group() const override;
122     Group* group() override;
123     void checkGroup(Group* gr = nullptr, bool force = false);
124     void changeClientLeaderGroup(Group* gr);
125     bool supportsWindowRules() const override;
126     void updateWindowRules(Rules::Types selection) override;
127     void applyWindowRules() override;
128     void updateFullscreenMonitors(NETFullscreenMonitors topology);
129 
130     bool hasNETSupport() const;
131 
132     QSize minSize() const override;
133     QSize maxSize() const override;
134     QSize basicUnit() const;
inputPos()135     QPoint inputPos() const { return input_offset; } // Inside of geometry()
136 
137     bool windowEvent(xcb_generic_event_t *e);
138     NET::WindowType windowType(bool direct = false, int supported_types = 0) const override;
139 
140     bool manage(xcb_window_t w, bool isMapped);
141     void releaseWindow(bool on_shutdown = false);
142     void destroyClient() override;
143 
144     QStringList activities() const override;
145     void doSetOnActivities(const QStringList &newActivitiesList) override;
146     void updateActivities(bool includeTransients) override;
147 
148     /// Is not minimized and not hidden. I.e. normally visible on some virtual desktop.
149     bool isShown(bool shaded_is_shown) const override;
150     bool isHiddenInternal() const override; // For compositing
151 
152     bool isShadeable() const override;
153     bool isMaximizable() const override;
154     MaximizeMode maximizeMode() const override;
155 
156     bool isMinimizable() const override;
157     QRect iconGeometry() const override;
158 
159     bool isFullScreenable() const override;
160     void setFullScreen(bool set, bool user = true) override;
161     bool isFullScreen() const override;
162     bool userCanSetFullScreen() const override;
fullScreenMode()163     int fullScreenMode() const {
164         return m_fullscreenMode;    // only for session saving
165     }
166 
167     bool userNoBorder() const;
168     bool noBorder() const override;
169     void setNoBorder(bool set) override;
170     bool userCanSetNoBorder() const override;
171     void checkNoBorder() override;
172 
173     int sessionStackingOrder() const;
174 
175     // Auxiliary functions, depend on the windowType
176     bool wantsInput() const override;
177 
178     bool isResizable() const override;
179     bool isMovable() const override;
180     bool isMovableAcrossScreens() const override;
181     bool isCloseable() const override; ///< May be closed by the user (May have a close button)
182 
183     bool takeFocus() override;
184 
185     void updateDecoration(bool check_workspace_pos, bool force = false) override;
186 
187     void updateShape();
188 
189     /// resizeWithChecks() resizes according to gravity, and checks workarea position
190     void resizeWithChecks(const QSize &size) override;
191     void resizeWithChecks(int w, int h, xcb_gravity_t gravity);
192     void resizeWithChecks(const QSize& s, xcb_gravity_t gravity);
193     QSize constrainClientSize(const QSize &size, SizeMode mode = SizeModeAny) const override;
194 
195     bool providesContextHelp() const override;
196 
197     xcb_colormap_t colormap() const;
198 
199     /// Updates visibility depending on being shaded, virtual desktop, etc.
200     void updateVisibility();
201     /// Hides a client - Basically like minimize, but without effects, it's simply hidden
202     void hideClient(bool hide) override;
203     bool hiddenPreview() const; ///< Window is mapped in order to get a window pixmap
204 
205     bool setupCompositing() override;
206     void finishCompositing(ReleaseReason releaseReason = ReleaseReason::Release) override;
207     void setBlockingCompositing(bool block);
isBlockingCompositing()208     inline bool isBlockingCompositing() { return blocks_compositing; }
209 
captionNormal()210     QString captionNormal() const override {
211         return cap_normal;
212     }
captionSuffix()213     QString captionSuffix() const override {
214         return cap_suffix;
215     }
216 
217     using AbstractClient::keyPressEvent;
218     void keyPressEvent(uint key_code, xcb_timestamp_t time);   // FRAME ??
219     void updateMouseGrab() override;
220     xcb_window_t moveResizeGrabWindow() const;
221 
222     QPoint gravityAdjustment(xcb_gravity_t gravity) const;
223     const QPoint calculateGravitation(bool invert) const;
224 
225     void NETMoveResize(int x_root, int y_root, NET::Direction direction);
226     void NETMoveResizeWindow(int flags, int x, int y, int width, int height);
227     void restackWindow(xcb_window_t above, int detail, NET::RequestSource source, xcb_timestamp_t timestamp,
228                        bool send_event = false);
229 
230     void gotPing(xcb_timestamp_t timestamp);
231 
232     void updateUserTime(xcb_timestamp_t time = XCB_TIME_CURRENT_TIME);
233     xcb_timestamp_t userTime() const override;
234     bool hasUserTimeSupport() const;
235 
236     /// Does 'delete c;'
237     static void deleteClient(X11Client *c);
238 
239     static bool belongToSameApplication(const X11Client *c1, const X11Client *c2, SameApplicationChecks checks = SameApplicationChecks());
240     static bool sameAppWindowRoleMatch(const X11Client *c1, const X11Client *c2, bool active_hack);
241 
242     void killWindow() override;
243     void showContextHelp() override;
244     void checkActiveModal();
245 
246     StrutRect strutRect(StrutArea area) const override;
247     bool hasStrut() const override;
248 
249     /**
250      * If shown is true the client is mapped and raised, if false
251      * the client is unmapped and hidden, this function is called
252      * when the tabbing group of the client switches its visible
253      * client.
254      */
255     void setClientShown(bool shown) override;
256 
257     bool isClientSideDecorated() const;
258 
259     Xcb::Property fetchFirstInTabBox() const;
260     void readFirstInTabBox(Xcb::Property &property);
261     void updateFirstInTabBox();
262     Xcb::StringProperty fetchPreferredColorScheme() const;
263     QString readPreferredColorScheme(Xcb::StringProperty &property) const;
264     QString preferredColorScheme() const override;
265 
266     //sets whether the client should be faked as being on all activities (and be shown during session save)
267     void setSessionActivityOverride(bool needed);
268     bool isClient() const override;
269 
270     void cancelFocusOutTimer();
271 
272     /**
273      * Restores the Client after it had been hidden due to show on screen edge functionality.
274      * In addition the property gets deleted so that the Client knows that it is visible again.
275      */
276     void showOnScreenEdge() override;
277 
278     Xcb::StringProperty fetchApplicationMenuServiceName() const;
279     void readApplicationMenuServiceName(Xcb::StringProperty &property);
280     void checkApplicationMenuServiceName();
281 
282     Xcb::StringProperty fetchApplicationMenuObjectPath() const;
283     void readApplicationMenuObjectPath(Xcb::StringProperty &property);
284     void checkApplicationMenuObjectPath();
285 
286     struct SyncRequest {
287         xcb_sync_counter_t counter;
288         xcb_sync_int64_t value;
289         xcb_sync_alarm_t alarm;
290         xcb_timestamp_t lastTimestamp;
291         QTimer *timeout, *failsafeTimeout;
292         bool isPending;
293     };
syncRequest()294     const SyncRequest &syncRequest() const {
295         return m_syncRequest;
296     }
297     virtual bool wantsSyncCounter() const;
298     void handleSync();
299     void handleSyncTimeout();
300 
301     static void cleanupX11();
302 
303 public Q_SLOTS:
304     void closeWindow() override;
305     void updateCaption() override;
306 
307 private:
308     // Handlers for X11 events
309     bool mapRequestEvent(xcb_map_request_event_t *e);
310     void unmapNotifyEvent(xcb_unmap_notify_event_t *e);
311     void destroyNotifyEvent(xcb_destroy_notify_event_t *e);
312     void configureRequestEvent(xcb_configure_request_event_t *e);
313     void propertyNotifyEvent(xcb_property_notify_event_t *e) override;
314     void clientMessageEvent(xcb_client_message_event_t *e) override;
315     void enterNotifyEvent(xcb_enter_notify_event_t *e);
316     void leaveNotifyEvent(xcb_leave_notify_event_t *e);
317     void focusInEvent(xcb_focus_in_event_t *e);
318     void focusOutEvent(xcb_focus_out_event_t *e);
319     void damageNotifyEvent();
320 
321     bool buttonPressEvent(xcb_window_t w, int button, int state, int x, int y, int x_root, int y_root, xcb_timestamp_t time = XCB_CURRENT_TIME);
322     bool buttonReleaseEvent(xcb_window_t w, int button, int state, int x, int y, int x_root, int y_root);
323     bool motionNotifyEvent(xcb_window_t w, int state, int x, int y, int x_root, int y_root);
324 
325 protected:
326     bool belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const override;
327     void doSetActive() override;
328     void doSetKeepAbove() override;
329     void doSetKeepBelow() override;
330     void doSetShade(ShadeMode previousShadeMode) override;
331     void doSetDesktop() override;
332     void doMinimize() override;
333     void doSetSkipPager() override;
334     void doSetSkipTaskbar() override;
335     void doSetSkipSwitcher() override;
336     void doSetDemandsAttention() override;
337     bool belongsToDesktop() const override;
338     bool doStartInteractiveMoveResize() override;
339     bool isWaitingForInteractiveMoveResizeSync() const override;
340     void doInteractiveResizeSync() override;
341     QSize resizeIncrements() const override;
342     bool acceptsFocus() const override;
343     void moveResizeInternal(const QRect &rect, MoveResizeMode mode) override;
344 
345     //Signals for the scripting interface
346     //Signals make an excellent way for communication
347     //in between objects as compared to simple function
348     //calls
349 Q_SIGNALS:
350     void clientManaging(KWin::X11Client *);
351     void clientFullScreenSet(KWin::X11Client *, bool, bool);
352 
353     /**
354      * Emitted whenever the Client want to show it menu
355      */
356     void showRequest();
357     /**
358      * Emitted whenever the Client's menu is closed
359      */
360     void menuHidden();
361     /**
362      * Emitted whenever the Client's menu is available
363      */
364     void appMenuAvailable();
365     /**
366      * Emitted whenever the Client's menu is unavailable
367      */
368     void appMenuUnavailable();
369 
370     /**
371      * Emitted whenever the Client's block compositing state changes.
372      */
373     void blockingCompositingChanged(KWin::X11Client *client);
374     void clientSideDecoratedChanged();
375 
376 private:
377     void exportMappingState(int s);   // ICCCM 4.1.3.1, 4.1.4, NETWM 2.5.1
378     bool isManaged() const; ///< Returns false if this client is not yet managed
379     void updateAllowedActions(bool force = false);
380     QRect fullscreenMonitorsArea(NETFullscreenMonitors topology) const;
381     void changeMaximize(bool horizontal, bool vertical, bool adjust) override;
382     void getWmNormalHints();
383     void getMotifHints();
384     void getIcons();
385     void fetchName();
386     void fetchIconicName();
387     QString readName() const;
388     void setCaption(const QString& s, bool force = false);
389     bool hasTransientInternal(const X11Client *c, bool indirect, QList<const X11Client *> &set) const;
390     void setShortcutInternal() override;
391 
392     void configureRequest(int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool);
393     NETExtendedStrut strut() const;
394     int checkShadeGeometry(int w, int h);
395     void getSyncCounter();
396     void sendSyncRequest();
397     void leaveInteractiveMoveResize() override;
398     void positionGeometryTip() override;
399     void establishCommandWindowGrab(uint8_t button);
400     void establishCommandAllGrab(uint8_t button);
401     void resizeDecoration();
402     void createDecoration(const QRect &oldgeom) override;
403 
404     void pingWindow();
405     void killProcess(bool ask, xcb_timestamp_t timestamp = XCB_TIME_CURRENT_TIME);
406     void updateUrgency();
407     static void sendClientMessage(xcb_window_t w, xcb_atom_t a, xcb_atom_t protocol,
408                                   uint32_t data1 = 0, uint32_t data2 = 0, uint32_t data3 = 0);
409 
410     void embedClient(xcb_window_t w, xcb_visualid_t visualid, xcb_colormap_t colormap, uint8_t depth);
411     void detectNoBorder();
412     void destroyDecoration() override;
413     void updateFrameExtents();
414     void setClientFrameExtents(const NETStrut &strut);
415 
416     void internalShow();
417     void internalHide();
418     void internalKeep();
419     void map();
420     void unmap();
421     void updateHiddenPreview();
422 
423     void updateInputShape();
424     void updateServerGeometry();
425     void discardWindowPixmap();
426     void updateWindowPixmap();
427 
428     xcb_timestamp_t readUserTimeMapTimestamp(const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
429                                   bool session) const;
430     xcb_timestamp_t readUserCreationTime() const;
431     void startupIdChanged();
432 
433     void updateInputWindow();
434 
435     Xcb::Property fetchShowOnScreenEdge() const;
436     void readShowOnScreenEdge(Xcb::Property &property);
437     /**
438      * Reads the property and creates/destroys the screen edge if required
439      * and shows/hides the client.
440      */
441     void updateShowOnScreenEdge();
442 
443     void maybeCreateX11DecorationRenderer();
444     void maybeDestroyX11DecorationRenderer();
445 
446     Xcb::Window m_client;
447     Xcb::Window m_wrapper;
448     Xcb::Window m_frame;
449     QStringList activityList;
450     int m_activityUpdatesBlocked;
451     bool m_blockedActivityUpdatesRequireTransients;
452     Xcb::Window m_moveResizeGrabWindow;
453     bool move_resize_has_keyboard_grab;
454     bool m_managed;
455 
456     Xcb::GeometryHints m_geometryHints;
457     void sendSyntheticConfigureNotify();
458     enum MappingState {
459         Withdrawn, ///< Not handled, as per ICCCM WithdrawnState
460         Mapped, ///< The frame is mapped
461         Unmapped, ///< The frame is not mapped
462         Kept ///< The frame should be unmapped, but is kept (For compositing)
463     };
464     MappingState mapping_state;
465 
466     Xcb::TransientFor fetchTransient() const;
467     void readTransientProperty(Xcb::TransientFor &transientFor);
468     void readTransient();
469     xcb_window_t verifyTransientFor(xcb_window_t transient_for, bool set);
470     void addTransient(AbstractClient* cl) override;
471     void removeTransient(AbstractClient* cl) override;
472     void removeFromMainClients();
473     void cleanGrouping();
474     void checkGroupTransients();
475     void setTransient(xcb_window_t new_transient_for_id);
476     xcb_window_t m_transientForId;
477     xcb_window_t m_originalTransientForId;
478     X11Client *shade_below;
479     Xcb::MotifHints m_motif;
480     uint hidden : 1; ///< Forcibly hidden by calling hide()
481     uint noborder : 1;
482     uint app_noborder : 1; ///< App requested no border via window type, shape extension, etc.
483     uint ignore_focus_stealing : 1; ///< Don't apply focus stealing prevention to this client
484     bool blocks_compositing;
485 
486     enum FullScreenMode {
487         FullScreenNone,
488         FullScreenNormal
489     } m_fullscreenMode;
490 
491     MaximizeMode max_mode;
492     xcb_colormap_t m_colormap;
493     QString cap_normal, cap_iconic, cap_suffix;
494     Group* in_group;
495     QTimer* ping_timer;
496     qint64 m_killHelperPID;
497     xcb_timestamp_t m_pingTimestamp;
498     xcb_timestamp_t m_userTime;
499     NET::Actions allowed_actions;
500     bool shade_geometry_change;
501     SyncRequest m_syncRequest;
502     static bool check_active_modal; ///< \see X11Client::checkActiveModal()
503     int sm_stacking_order;
504     friend struct ResetupRulesProcedure;
505 
506     friend bool performTransiencyCheck();
507 
508     Xcb::StringProperty fetchActivities() const;
509     void readActivities(Xcb::StringProperty &property);
510     void checkActivities();
511     bool activitiesDefined; //whether the x property was actually set
512 
513     bool sessionActivityOverride;
514     bool needsXWindowMove;
515 
516     Xcb::Window m_decoInputExtent;
517     QPoint input_offset;
518 
519     QTimer *m_focusOutTimer;
520 
521     QMetaObject::Connection m_edgeRemoveConnection;
522     QMetaObject::Connection m_edgeGeometryTrackingConnection;
523 
524     QMargins m_clientFrameExtents;
525     QRect m_lastBufferGeometry;
526     QRect m_lastFrameGeometry;
527     QRect m_lastClientGeometry;
528     QScopedPointer<X11DecorationRenderer> m_decorationRenderer;
529 };
530 
wrapperId()531 inline xcb_window_t X11Client::wrapperId() const
532 {
533     return m_wrapper;
534 }
535 
isClientSideDecorated()536 inline bool X11Client::isClientSideDecorated() const
537 {
538     return !m_clientFrameExtents.isNull();
539 }
540 
groupTransient()541 inline bool X11Client::groupTransient() const
542 {
543     return m_transientForId == rootWindow();
544 }
545 
546 // Needed because verifyTransientFor() may set transient_for_id to root window,
547 // if the original value has a problem (window doesn't exist, etc.)
wasOriginallyGroupTransient()548 inline bool X11Client::wasOriginallyGroupTransient() const
549 {
550     return m_originalTransientForId == rootWindow();
551 }
552 
isTransient()553 inline bool X11Client::isTransient() const
554 {
555     return m_transientForId != XCB_WINDOW_NONE;
556 }
557 
group()558 inline const Group* X11Client::group() const
559 {
560     return in_group;
561 }
562 
group()563 inline Group* X11Client::group()
564 {
565     return in_group;
566 }
567 
isShown(bool shaded_is_shown)568 inline bool X11Client::isShown(bool shaded_is_shown) const
569 {
570     return !isMinimized() && (!isShade() || shaded_is_shown) && !hidden;
571 }
572 
isHiddenInternal()573 inline bool X11Client::isHiddenInternal() const
574 {
575     return hidden;
576 }
577 
maximizeMode()578 inline MaximizeMode X11Client::maximizeMode() const
579 {
580     return max_mode;
581 }
582 
isFullScreen()583 inline bool X11Client::isFullScreen() const
584 {
585     return m_fullscreenMode != FullScreenNone;
586 }
587 
hasNETSupport()588 inline bool X11Client::hasNETSupport() const
589 {
590     return info->hasNETSupport();
591 }
592 
colormap()593 inline xcb_colormap_t X11Client::colormap() const
594 {
595     return m_colormap;
596 }
597 
sessionStackingOrder()598 inline int X11Client::sessionStackingOrder() const
599 {
600     return sm_stacking_order;
601 }
602 
isManaged()603 inline bool X11Client::isManaged() const
604 {
605     return m_managed;
606 }
607 
resizeWithChecks(const QSize & s)608 inline void X11Client::resizeWithChecks(const QSize &s)
609 {
610     resizeWithChecks(s.width(), s.height(), XCB_GRAVITY_BIT_FORGET);
611 }
612 
resizeWithChecks(const QSize & s,xcb_gravity_t gravity)613 inline void X11Client::resizeWithChecks(const QSize& s, xcb_gravity_t gravity)
614 {
615     resizeWithChecks(s.width(), s.height(), gravity);
616 }
617 
hasUserTimeSupport()618 inline bool X11Client::hasUserTimeSupport() const
619 {
620     return info->userTime() != -1U;
621 }
622 
moveResizeGrabWindow()623 inline xcb_window_t X11Client::moveResizeGrabWindow() const
624 {
625     return m_moveResizeGrabWindow;
626 }
627 
hiddenPreview()628 inline bool X11Client::hiddenPreview() const
629 {
630     return mapping_state == Kept;
631 }
632 
633 } // namespace
634 Q_DECLARE_METATYPE(KWin::X11Client *)
635 Q_DECLARE_METATYPE(QList<KWin::X11Client *>)
636