KWindowSystem

platforms/xcb/kwindowinfo.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 1999 Matthias Ettrich <[email protected]>
4  SPDX-FileCopyrightText: 2007 Lubos Lunak <[email protected]>
5  SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9 
10 #include "kwindowinfo_p_x11.h"
11 #include "kwindowsystem.h"
12 
13 #include <QDebug>
14 #include <QX11Info>
15 #include <X11/Xatom.h>
16 #include <kxerrorhandler_p.h>
17 #include <netwm.h>
18 
19 #include <xcb/res.h>
20 
21 static bool haveXRes()
22 {
23  static bool s_checked = false;
24  static bool s_haveXRes = false;
25  if (!s_checked) {
26  auto cookie = xcb_res_query_version(QX11Info::connection(), XCB_RES_MAJOR_VERSION, XCB_RES_MINOR_VERSION);
27  QScopedPointer<xcb_res_query_version_reply_t, QScopedPointerPodDeleter> reply(xcb_res_query_version_reply(QX11Info::connection(), cookie, nullptr));
28  s_haveXRes = !reply.isNull();
29  s_checked = true;
30  }
31  return s_haveXRes;
32 }
33 
34 // KWindowSystem::info() should be updated too if something has to be changed here
35 KWindowInfoPrivateX11::KWindowInfoPrivateX11(WId _win, NET::Properties properties, NET::Properties2 properties2)
36  : KWindowInfoPrivate(_win, properties, properties2)
37  , KWindowInfoPrivateDesktopFileNameExtension()
38  , KWindowInfoPrivatePidExtension()
39  , KWindowInfoPrivateAppMenuExtension()
40 {
41  installDesktopFileNameExtension(this);
42  installPidExtension(this);
43  installAppMenuExtension(this);
44 
45  KXErrorHandler handler;
46  if (properties & NET::WMVisibleIconName) {
47  properties |= NET::WMIconName | NET::WMVisibleName; // force, in case it will be used as a fallback
48  }
49  if (properties & NET::WMVisibleName) {
50  properties |= NET::WMName; // force, in case it will be used as a fallback
51  }
52  if (properties2 & NET::WM2ExtendedStrut) {
53  properties |= NET::WMStrut; // will be used as fallback
54  }
55  if (properties & NET::WMWindowType) {
56  properties2 |= NET::WM2TransientFor; // will be used when type is not set
57  }
58  if ((properties & NET::WMDesktop) && KWindowSystem::mapViewport()) {
59  properties |= NET::WMGeometry; // for viewports, the desktop (workspace) is determined from the geometry
60  }
61  properties |= NET::XAWMState; // force to get error detection for valid()
62  m_info.reset(new NETWinInfo(QX11Info::connection(), _win, QX11Info::appRootWindow(), properties, properties2));
63  if (properties & NET::WMName) {
64  if (m_info->name() && m_info->name()[0] != '\0') {
65  m_name = QString::fromUtf8(m_info->name());
66  } else {
67  m_name = KWindowSystem::readNameProperty(_win, XA_WM_NAME);
68  }
69  }
70  if (properties & NET::WMIconName) {
71  if (m_info->iconName() && m_info->iconName()[0] != '\0') {
72  m_iconic_name = QString::fromUtf8(m_info->iconName());
73  } else {
74  m_iconic_name = KWindowSystem::readNameProperty(_win, XA_WM_ICON_NAME);
75  }
76  }
77  if (properties & (NET::WMGeometry | NET::WMFrameExtents)) {
78  NETRect frame;
79  NETRect geom;
80  m_info->kdeGeometry(frame, geom);
81  m_geometry.setRect(geom.pos.x, geom.pos.y, geom.size.width, geom.size.height);
82  m_frame_geometry.setRect(frame.pos.x, frame.pos.y, frame.size.width, frame.size.height);
83  }
84  m_valid = !handler.error(false); // no sync - NETWinInfo did roundtrips
85 
86  if (haveXRes()) {
87  xcb_res_client_id_spec_t specs;
88  specs.client = win();
89  specs.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
90  auto cookie = xcb_res_query_client_ids(QX11Info::connection(), 1, &specs);
91 
93  xcb_res_query_client_ids_reply(QX11Info::connection(), cookie, nullptr));
94  if (reply && xcb_res_query_client_ids_ids_length(reply.data()) > 0) {
95  uint32_t pid = *xcb_res_client_id_value_value((xcb_res_query_client_ids_ids_iterator(reply.data()).data));
96  m_pid = pid;
97  }
98  }
99 }
100 
101 KWindowInfoPrivateX11::~KWindowInfoPrivateX11()
102 {
103 }
104 
105 bool KWindowInfoPrivateX11::valid(bool withdrawn_is_valid) const
106 {
107  if (!m_valid) {
108  return false;
109  }
110  if (!withdrawn_is_valid && mappingState() == NET::Withdrawn) {
111  return false;
112  }
113  return true;
114 }
115 
116 NET::States KWindowInfoPrivateX11::state() const
117 {
118 #if !defined(KDE_NO_WARNING_OUTPUT)
119  if (!(m_info->passedProperties() & NET::WMState)) {
120  qWarning() << "Pass NET::WMState to KWindowInfo";
121  }
122 #endif
123  return m_info->state();
124 }
125 
126 NET::MappingState KWindowInfoPrivateX11::mappingState() const
127 {
128 #if !defined(KDE_NO_WARNING_OUTPUT)
129  if (!(m_info->passedProperties() & NET::XAWMState)) {
130  qWarning() << "Pass NET::XAWMState to KWindowInfo";
131  }
132 #endif
133  return m_info->mappingState();
134 }
135 
136 NETExtendedStrut KWindowInfoPrivateX11::extendedStrut() const
137 {
138 #if !defined(KDE_NO_WARNING_OUTPUT)
139  if (!(m_info->passedProperties2() & NET::WM2ExtendedStrut)) {
140  qWarning() << "Pass NET::WM2ExtendedStrut to KWindowInfo";
141  }
142 #endif
143  NETExtendedStrut ext = m_info->extendedStrut();
144  NETStrut str = m_info->strut();
145  if (ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0
146  && (str.left != 0 || str.right != 0 || str.top != 0 || str.bottom != 0)) {
147  // build extended from simple
148  if (str.left != 0) {
149  ext.left_width = str.left;
150  ext.left_start = 0;
151  ext.left_end = XDisplayHeight(QX11Info::display(), DefaultScreen(QX11Info::display()));
152  }
153  if (str.right != 0) {
154  ext.right_width = str.right;
155  ext.right_start = 0;
156  ext.right_end = XDisplayHeight(QX11Info::display(), DefaultScreen(QX11Info::display()));
157  }
158  if (str.top != 0) {
159  ext.top_width = str.top;
160  ext.top_start = 0;
161  ext.top_end = XDisplayWidth(QX11Info::display(), DefaultScreen(QX11Info::display()));
162  }
163  if (str.bottom != 0) {
164  ext.bottom_width = str.bottom;
165  ext.bottom_start = 0;
166  ext.bottom_end = XDisplayWidth(QX11Info::display(), DefaultScreen(QX11Info::display()));
167  }
168  }
169  return ext;
170 }
171 
172 NET::WindowType KWindowInfoPrivateX11::windowType(NET::WindowTypes supported_types) const
173 {
174 #if !defined(KDE_NO_WARNING_OUTPUT)
175  if (!(m_info->passedProperties() & NET::WMWindowType)) {
176  qWarning() << "Pass NET::WMWindowType to KWindowInfo";
177  }
178 #endif
179  if (!m_info->hasWindowType()) { // fallback, per spec recommendation
180  if (transientFor() != XCB_WINDOW_NONE) { // dialog
181  if (supported_types & NET::DialogMask) {
182  return NET::Dialog;
183  }
184  } else {
185  if (supported_types & NET::NormalMask) {
186  return NET::Normal;
187  }
188  }
189  }
190  return m_info->windowType(supported_types);
191 }
192 
193 QString KWindowInfoPrivateX11::visibleNameWithState() const
194 {
195  QString s = visibleName();
196  if (isMinimized()) {
197  s.prepend(QLatin1Char('('));
198  s.append(QLatin1Char(')'));
199  }
200  return s;
201 }
202 
203 QString KWindowInfoPrivateX11::visibleName() const
204 {
205 #if !defined(KDE_NO_WARNING_OUTPUT)
206  if (!(m_info->passedProperties() & NET::WMVisibleName)) {
207  qWarning() << "Pass NET::WMVisibleName to KWindowInfo";
208  }
209 #endif
210  return m_info->visibleName() && m_info->visibleName()[0] != '\0' ? QString::fromUtf8(m_info->visibleName()) : name();
211 }
212 
213 QString KWindowInfoPrivateX11::name() const
214 {
215 #if !defined(KDE_NO_WARNING_OUTPUT)
216  if (!(m_info->passedProperties() & NET::WMName)) {
217  qWarning() << "Pass NET::WMName to KWindowInfo";
218  }
219 #endif
220  return m_name;
221 }
222 
223 QString KWindowInfoPrivateX11::visibleIconNameWithState() const
224 {
225  QString s = visibleIconName();
226  if (isMinimized()) {
227  s.prepend(QLatin1Char('('));
228  s.append(QLatin1Char(')'));
229  }
230  return s;
231 }
232 
233 QString KWindowInfoPrivateX11::visibleIconName() const
234 {
235 #if !defined(KDE_NO_WARNING_OUTPUT)
236  if (!(m_info->passedProperties() & NET::WMVisibleIconName)) {
237  qWarning() << "Pass NET::WMVisibleIconName to KWindowInfo";
238  }
239 #endif
240  if (m_info->visibleIconName() && m_info->visibleIconName()[0] != '\0') {
241  return QString::fromUtf8(m_info->visibleIconName());
242  }
243  if (m_info->iconName() && m_info->iconName()[0] != '\0') {
244  return QString::fromUtf8(m_info->iconName());
245  }
246  if (!m_iconic_name.isEmpty()) {
247  return m_iconic_name;
248  }
249  return visibleName();
250 }
251 
252 QString KWindowInfoPrivateX11::iconName() const
253 {
254 #if !defined(KDE_NO_WARNING_OUTPUT)
255  if (!(m_info->passedProperties() & NET::WMIconName)) {
256  qWarning() << "Pass NET::WMIconName to KWindowInfo";
257  }
258 #endif
259  if (m_info->iconName() && m_info->iconName()[0] != '\0') {
260  return QString::fromUtf8(m_info->iconName());
261  }
262  if (!m_iconic_name.isEmpty()) {
263  return m_iconic_name;
264  }
265  return name();
266 }
267 
268 bool KWindowInfoPrivateX11::isOnDesktop(int _desktop) const
269 {
270 #if !defined(KDE_NO_WARNING_OUTPUT)
271  if (!(m_info->passedProperties() & NET::WMDesktop)) {
272  qWarning() << "Pass NET::WMDesktop to KWindowInfo";
273  }
274 #endif
276  if (onAllDesktops()) {
277  return true;
278  }
279  return KWindowSystem::viewportWindowToDesktop(m_geometry) == _desktop;
280  }
281  return m_info->desktop() == _desktop || m_info->desktop() == NET::OnAllDesktops;
282 }
283 
284 bool KWindowInfoPrivateX11::onAllDesktops() const
285 {
286 #if !defined(KDE_NO_WARNING_OUTPUT)
287  if (!(m_info->passedProperties() & NET::WMDesktop)) {
288  qWarning() << "Pass NET::WMDesktop to KWindowInfo";
289  }
290 #endif
292  if (m_info->passedProperties() & NET::WMState) {
293  return m_info->state() & NET::Sticky;
294  }
295  NETWinInfo info(QX11Info::connection(), win(), QX11Info::appRootWindow(), NET::WMState, NET::Properties2());
296  return info.state() & NET::Sticky;
297  }
298  return m_info->desktop() == NET::OnAllDesktops;
299 }
300 
301 int KWindowInfoPrivateX11::desktop() const
302 {
303 #if !defined(KDE_NO_WARNING_OUTPUT)
304  if (!(m_info->passedProperties() & NET::WMDesktop)) {
305  qWarning() << "Pass NET::WMDesktop to KWindowInfo";
306  }
307 #endif
309  if (onAllDesktops()) {
310  return NET::OnAllDesktops;
311  }
312  return KWindowSystem::viewportWindowToDesktop(m_geometry);
313  }
314  return m_info->desktop();
315 }
316 
317 QStringList KWindowInfoPrivateX11::activities() const
318 {
319 #if !defined(KDE_NO_WARNING_OUTPUT)
320  if (!(m_info->passedProperties2() & NET::WM2Activities)) {
321  qWarning() << "Pass NET::WM2Activities to KWindowInfo";
322  }
323 #endif
324 
325  const QStringList result = QString::fromLatin1(m_info->activities()).split(QLatin1Char(','), Qt::SkipEmptyParts);
326 
327  return result.contains(QStringLiteral(KDE_ALL_ACTIVITIES_UUID)) ? QStringList() : result;
328 }
329 
330 QRect KWindowInfoPrivateX11::geometry() const
331 {
332 #if !defined(KDE_NO_WARNING_OUTPUT)
333  if (!(m_info->passedProperties() & NET::WMGeometry)) {
334  qWarning() << "Pass NET::WMGeometry to KWindowInfo";
335  }
336 #endif
337  return m_geometry;
338 }
339 
340 QRect KWindowInfoPrivateX11::frameGeometry() const
341 {
342 #if !defined(KDE_NO_WARNING_OUTPUT)
343  if (!(m_info->passedProperties() & NET::WMFrameExtents)) {
344  qWarning() << "Pass NET::WMFrameExtents to KWindowInfo";
345  }
346 #endif
347  return m_frame_geometry;
348 }
349 
350 WId KWindowInfoPrivateX11::transientFor() const
351 {
352 #if !defined(KDE_NO_WARNING_OUTPUT)
353  if (!(m_info->passedProperties2() & NET::WM2TransientFor)) {
354  qWarning() << "Pass NET::WM2TransientFor to KWindowInfo";
355  }
356 #endif
357  return m_info->transientFor();
358 }
359 
360 WId KWindowInfoPrivateX11::groupLeader() const
361 {
362 #if !defined(KDE_NO_WARNING_OUTPUT)
363  if (!(m_info->passedProperties2() & NET::WM2GroupLeader)) {
364  qWarning() << "Pass NET::WM2GroupLeader to KWindowInfo";
365  }
366 #endif
367  return m_info->groupLeader();
368 }
369 
370 QByteArray KWindowInfoPrivateX11::windowClassClass() const
371 {
372 #if !defined(KDE_NO_WARNING_OUTPUT)
373  if (!(m_info->passedProperties2() & NET::WM2WindowClass)) {
374  qWarning() << "Pass NET::WM2WindowClass to KWindowInfo";
375  }
376 #endif
377  return m_info->windowClassClass();
378 }
379 
380 QByteArray KWindowInfoPrivateX11::windowClassName() const
381 {
382 #if !defined(KDE_NO_WARNING_OUTPUT)
383  if (!(m_info->passedProperties2() & NET::WM2WindowClass)) {
384  qWarning() << "Pass NET::WM2WindowClass to KWindowInfo";
385  }
386 #endif
387  return m_info->windowClassName();
388 }
389 
390 QByteArray KWindowInfoPrivateX11::windowRole() const
391 {
392 #if !defined(KDE_NO_WARNING_OUTPUT)
393  if (!(m_info->passedProperties2() & NET::WM2WindowRole)) {
394  qWarning() << "Pass NET::WM2WindowRole to KWindowInfo";
395  }
396 #endif
397  return m_info->windowRole();
398 }
399 
400 QByteArray KWindowInfoPrivateX11::clientMachine() const
401 {
402 #if !defined(KDE_NO_WARNING_OUTPUT)
403  if (!(m_info->passedProperties2() & NET::WM2ClientMachine)) {
404  qWarning() << "Pass NET::WM2ClientMachine to KWindowInfo";
405  }
406 #endif
407  return m_info->clientMachine();
408 }
409 
410 bool KWindowInfoPrivateX11::actionSupported(NET::Action action) const
411 {
412 #if !defined(KDE_NO_WARNING_OUTPUT)
413  if (!(m_info->passedProperties2() & NET::WM2AllowedActions)) {
414  qWarning() << "Pass NET::WM2AllowedActions to KWindowInfo";
415  }
416 #endif
418  return m_info->allowedActions() & action;
419  } else {
420  return true; // no idea if it's supported or not -> pretend it is
421  }
422 }
423 
424 // see NETWM spec section 7.6
425 bool KWindowInfoPrivateX11::isMinimized() const
426 {
427  if (mappingState() != NET::Iconic) {
428  return false;
429  }
430  // NETWM 1.2 compliant WM - uses NET::Hidden for minimized windows
431  if ((state() & NET::Hidden) != 0 && (state() & NET::Shaded) == 0) { // shaded may have NET::Hidden too
432  return true;
433  }
434  // older WMs use WithdrawnState for other virtual desktops
435  // and IconicState only for minimized
436  return KWindowSystem::icccmCompliantMappingState() ? false : true;
437 }
438 
439 QByteArray KWindowInfoPrivateX11::desktopFileName() const
440 {
441 #if !defined(KDE_NO_WARNING_OUTPUT)
442  if (!(m_info->passedProperties2() & NET::WM2DesktopFileName)) {
443  qWarning() << "Pass NET::WM2DesktopFileName to KWindowInfo";
444  }
445 #endif
446  return QByteArray(m_info->desktopFileName());
447 }
448 
449 QByteArray KWindowInfoPrivateX11::applicationMenuObjectPath() const
450 {
451 #if !defined(KDE_NO_WARNING_OUTPUT)
452  if (!(m_info->passedProperties2() & NET::WM2AppMenuObjectPath)) {
453  qWarning() << "Pass NET::WM2AppMenuObjectPath to KWindowInfo";
454  }
455 #endif
456  return QByteArray(m_info->appMenuObjectPath());
457 }
458 
459 QByteArray KWindowInfoPrivateX11::applicationMenuServiceName() const
460 {
461 #if !defined(KDE_NO_WARNING_OUTPUT)
462  if (!(m_info->passedProperties2() & NET::WM2AppMenuServiceName)) {
463  qWarning() << "Pass NET::WM2AppMenuServiceName to KWindowInfo";
464  }
465 #endif
466  return QByteArray(m_info->appMenuServiceName());
467 }
468 
469 int KWindowInfoPrivateX11::pid() const
470 {
471  // If pid is found using the XRes extension use that instead.
472  // It is more reliable than the app reporting it's own PID as apps
473  // within an app namespace are unable to do so correctly
474  if (m_pid > 0) {
475  return m_pid;
476  }
477 
478 #if !defined(KDE_NO_WARNING_OUTPUT)
479  if (!(m_info->passedProperties() & NET::WMPid)) {
480  qWarning() << "Pass NET::WMPid to KWindowInfo";
481  }
482 #endif
483 
484  return m_info->pid();
485 }
static QString readNameProperty(WId window, unsigned long atom)
Function that reads and returns the contents of the given text property (WM_NAME, WM_ICON_NAME...
indicates that this is a normal, top-level window
Definition: netwm_def.h:365
bool error(bool sync) const
QString & append(QChar ch)
int bottom
Bottom border of the strut.
Definition: netwm_def.h:262
int bottom_width
Bottom border of the strut, width and range.
Definition: netwm_def.h:218
int pid() const
Returns the process ID of the window&#39;s application if present.
QString visibleName() const
Returns the visible name of the window.
QString visibleIconName() const
Returns the visible name of the window that should be shown in a taskbar.
int right
Right border of the strut.
Definition: netwm_def.h:252
QString & prepend(QChar ch)
int y
y coordinate
Definition: netwm_def.h:51
indicates that the client window is not visible, but its icon is.
Definition: netwm_def.h:638
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
static int viewportWindowToDesktop(const QRect &r)
Partial strut class for NET classes.
Definition: netwm_def.h:180
NET::States state() const
Returns the window&#39;s state flags.
int left
Left border of the strut.
Definition: netwm_def.h:247
bool isMinimized() const
Returns true if the window is minimized.
indicates that a window should not be visible on the screen (e.g.
Definition: netwm_def.h:550
bool onAllDesktops() const
Returns true if the window is on all desktops.
MappingState
Client window mapping state.
Definition: netwm_def.h:624
indicates that neither the client window nor its icon is visible.
Definition: netwm_def.h:632
NET::MappingState mappingState() const
Returns the mapping state of the window.
NETSize size
Size of the rectangle.
Definition: netwm_def.h:133
QString fromUtf8(const char *str, int size)
WindowType
Window type.
Definition: netwm_def.h:357
static bool icccmCompliantMappingState()
int x
x coordinate.
Definition: netwm_def.h:51
NETPoint pos
Position of the rectangle.
Definition: netwm_def.h:126
int top_width
Top border of the strut, width and range.
Definition: netwm_def.h:213
SkipEmptyParts
Simple rectangle class for NET classes.
Definition: netwm_def.h:105
WId win() const
Returns the window identifier.
static bool mapViewport()
int width
Width.
Definition: netwm_def.h:91
indicates that this is a dialog window
Definition: netwm_def.h:388
indicates that the window is shaded (rolled-up).
Definition: netwm_def.h:526
static bool allowedActionsSupported()
Returns true if the WM announces which actions it allows for windows.
WId transientFor() const
Returns the window identifier of the main window this window belongs to.
int right_width
Right border of the strut, width and range.
Definition: netwm_def.h:208
QString fromLatin1(const char *str, int size)
QString name() const
Returns the name of the window, as specified by the application.
Action
Actions that can be done with a window (_NET_WM_ALLOWED_ACTIONS).
Definition: netwm_def.h:645
Common API for application window properties/protocols.
Definition: netwm.h:944
int height
Height.
Definition: netwm_def.h:92
int left_width
Left border of the strut, width and range.
Definition: netwm_def.h:203
int top
Top border of the strut.
Definition: netwm_def.h:257
indicates that the Window Manager SHOULD keep the window&#39;s position fixed on the screen, even when the virtual desktop scrolls.
Definition: netwm_def.h:510
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Fri Oct 15 2021 22:41:50 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.