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 ®ion) 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