VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/platform/nix/VBoxUtils-nix.cpp

Last change on this file was 103538, checked in by vboxsync, 3 months ago

FE/Qt: Moving out logging stuff from UIDefs.h to separate UILoggingDefs.h; This breaks dependency of UIDefs/UICommon headers from VBox/log.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.6 KB
Line 
1/* $Id: VBoxUtils-nix.cpp 103538 2024-02-22 17:06:26Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Declarations of utility classes and functions for handling X11 specific tasks.
4 */
5
6/*
7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#ifdef VBOX_WITH_SCREENSAVER_CONTROL
30# include <QtDBus/QDBusConnection>
31# include <QtDBus/QDBusConnectionInterface>
32# include <QtDBus/QDBusInterface>
33# include <QtDBus/QDBusReply>
34# include <QtXml/QDomDocument>
35# include <QtXml/QDomElement>
36#endif /* VBOX_WITH_SCREENSAVER_CONTROL */
37#include <QWidget>
38#include <QGuiApplication>
39
40/* GUI includes: */
41#include "UILoggingDefs.h"
42#include "VBoxUtils-nix.h"
43
44/* Other VBox includes: */
45#include <iprt/assert.h>
46#include <iprt/env.h>
47#include <iprt/process.h>
48#include <iprt/string.h>
49
50/* Other includes: */
51#undef BOOL /* Undefine the VBox/com/defs.h variant */
52#define BOOL X11BOOL /* Typedef'ed in Xmd.h via dpms.h, causing -Wpch-invalid to trigger. */
53#include <X11/Xatom.h>
54#include <X11/Xutil.h>
55#include <X11/extensions/dpms.h>
56#undef BOOL /* Restore the VBox/com/defs.h variant */
57#define BOOL PRBool
58#include <dlfcn.h>
59
60bool NativeWindowSubsystem::isCompositingManagerRunning(bool fIsXServerAvailable)
61{
62 if (fIsXServerAvailable)
63 return X11IsCompositingManagerRunning();
64 return WaylandIsCompositingManagerRunning();
65}
66bool NativeWindowSubsystem::X11IsCompositingManagerRunning()
67{
68 /* For each screen it manage, compositing manager MUST acquire ownership
69 * of a selection named _NET_WM_CM_Sn, where n is the screen number. */
70 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
71 Atom atom_property_name = XInternAtom(pDisplay, "_NET_WM_CM_S0", True);
72 return XGetSelectionOwner(pDisplay, atom_property_name);
73}
74
75bool NativeWindowSubsystem::WaylandIsCompositingManagerRunning()
76{
77 /// @todo implement
78 return true;
79}
80
81X11WMType NativeWindowSubsystem::windowManagerType(bool fIsXServerAvailable)
82{
83 if (fIsXServerAvailable)
84 return X11WindowManagerType();
85 return WaylandWindowManagerType();
86}
87
88X11WMType NativeWindowSubsystem::WaylandWindowManagerType()
89{
90 /// @wayland implement
91 return X11WMType_Unknown;
92}
93
94X11WMType NativeWindowSubsystem::X11WindowManagerType()
95{
96 /* Ask if root-window supports check for WM name: */
97 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
98 Atom atom_property_name;
99 Atom atom_returned_type;
100 int iReturnedFormat;
101 unsigned long ulReturnedItemCount;
102 unsigned long ulDummy;
103 unsigned char *pcData = 0;
104 X11WMType wmType = X11WMType_Unknown;
105 atom_property_name = XInternAtom(pDisplay, "_NET_SUPPORTING_WM_CHECK", True);
106 if (XGetWindowProperty(pDisplay, NativeWindowSubsystem::X11GetAppRootWindow(), atom_property_name,
107 0, 512, False, XA_WINDOW, &atom_returned_type,
108 &iReturnedFormat, &ulReturnedItemCount, &ulDummy, &pcData) == Success)
109 {
110 Window WMWindow = None;
111 if (atom_returned_type == XA_WINDOW && iReturnedFormat == 32)
112 WMWindow = *((Window*)pcData);
113 if (pcData)
114 XFree(pcData);
115 if (WMWindow != None)
116 {
117 /* Ask root-window for WM name: */
118 atom_property_name = XInternAtom(pDisplay, "_NET_WM_NAME", True);
119 Atom utf8Atom = XInternAtom(pDisplay, "UTF8_STRING", True);
120 if (XGetWindowProperty(pDisplay, WMWindow, atom_property_name,
121 0, 512, False, utf8Atom, &atom_returned_type,
122 &iReturnedFormat, &ulReturnedItemCount, &ulDummy, &pcData) == Success)
123 {
124 /** @todo r=bird: 6 QString conversions cannot be very efficient. */
125 if (QString((const char*)pcData).contains("Compiz", Qt::CaseInsensitive))
126 wmType = X11WMType_Compiz;
127 else
128 if (QString((const char*)pcData).contains("GNOME Shell", Qt::CaseInsensitive))
129 wmType = X11WMType_GNOMEShell;
130 else
131 if (QString((const char*)pcData).contains("KWin", Qt::CaseInsensitive))
132 wmType = X11WMType_KWin;
133 else
134 if (QString((const char*)pcData).contains("Metacity", Qt::CaseInsensitive))
135 wmType = X11WMType_Metacity;
136 else
137 if (QString((const char*)pcData).contains("Mutter", Qt::CaseInsensitive))
138 wmType = X11WMType_Mutter;
139 else
140 if (QString((const char*)pcData).contains("Xfwm4", Qt::CaseInsensitive))
141 wmType = X11WMType_Xfwm4;
142 if (pcData)
143 XFree(pcData);
144 }
145 }
146 }
147 return wmType;
148}
149
150bool NativeWindowSubsystem::checkExtension(bool fIsXServerAvailable, const char *pExtensionName)
151{
152 if (fIsXServerAvailable)
153 return X11CheckExtension(pExtensionName);
154 return WaylandCheckExtension(pExtensionName);
155}
156
157bool NativeWindowSubsystem::X11CheckExtension(const char *pExtensionName)
158{
159 /* Check extension: */
160 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
161 int major_opcode;
162 int first_event;
163 int first_error;
164 return XQueryExtension(pDisplay, pExtensionName, &major_opcode, &first_event, &first_error);
165}
166
167bool NativeWindowSubsystem::WaylandCheckExtension(const char *pExtensionName)
168{
169 Q_UNUSED(pExtensionName);
170 /// @todo implement
171 return false;
172}
173
174#ifdef VBOX_WITH_SCREENSAVER_CONTROL
175bool checkDBusConnection(const QDBusConnection &connection)
176{
177 if (!connection.isConnected())
178 {
179 const QDBusError lastError = connection.lastError();
180 if (lastError.isValid())
181 {
182 LogRel(("QDBus error. Could not connect to D-Bus server: %s: %s\n",
183 lastError.name().toUtf8().constData(),
184 lastError.message().toUtf8().constData()));
185 }
186 else
187 LogRel(("QDBus error. Could not connect to D-Bus server: Unable to load dbus libraries\n"));
188 return false;
189 }
190 return true;
191}
192
193QStringList findDBusScreenSaverServices(const QDBusConnection &connection)
194{
195 QStringList serviceNames;
196
197 QDBusReply<QStringList> replyr = connection.interface()->registeredServiceNames();
198 if (!replyr.isValid())
199 {
200 const QDBusError replyError = replyr.error();
201 LogRel(("QDBus error. Could not query registered service names %s %s",
202 replyError.name().toUtf8().constData(), replyError.message().toUtf8().constData()));
203 return serviceNames;
204 }
205
206 for (int i = 0; i < replyr.value().size(); ++i)
207 {
208 const QString strServiceName = replyr.value()[i];
209 if (strServiceName.contains("screensaver", Qt::CaseInsensitive))
210 serviceNames << strServiceName;
211 }
212 if (serviceNames.isEmpty())
213 LogRel(("QDBus error. No screen saver service found among registered DBus services."));
214
215 return serviceNames;
216}
217#endif /* VBOX_WITH_SCREENSAVER_CONTROL */
218
219bool NativeWindowSubsystem::checkDBusScreenSaverServices()
220{
221#ifdef VBOX_WITH_SCREENSAVER_CONTROL
222 QDBusConnection connection = QDBusConnection::sessionBus();
223 if (!checkDBusConnection(connection))
224 return false;
225
226 QDBusReply<QStringList> replyr = connection.interface()->registeredServiceNames();
227 if (!replyr.isValid())
228 {
229 const QDBusError replyError = replyr.error();
230 LogRel(("QDBus error. Could not query registered service names %s %s",
231 replyError.name().toUtf8().constData(), replyError.message().toUtf8().constData()));
232 return false;
233 }
234 for (int i = 0; i < replyr.value().size(); ++i)
235 {
236 const QString strServiceName = replyr.value()[i];
237 if (strServiceName.contains("screensaver", Qt::CaseInsensitive))
238 return true;
239 }
240 LogRel(("QDBus error. No screen saver service found among registered DBus services."));
241#else
242 printf("not defined\n");
243#endif /* VBOX_WITH_SCREENSAVER_CONTROL */
244 return false;
245}
246
247#ifdef VBOX_WITH_SCREENSAVER_CONTROL
248void introspectDBusInterfaceNode(const QDomElement &interface,
249 const QString &strServiceName,
250 QVector<DBusScreenSaverInhibitMethod*> &methods)
251{
252 QDomElement child = interface.firstChildElement();
253 while (!child.isNull())
254 {
255 if (child.tagName() == "method" && child.attribute("name") == "Inhibit")
256 {
257 DBusScreenSaverInhibitMethod *newMethod = new DBusScreenSaverInhibitMethod;
258 newMethod->m_iCookie = 0;
259 newMethod->m_strServiceName = strServiceName;
260 newMethod->m_strInterface = interface.attribute("name");
261 newMethod->m_strPath = "/";
262 newMethod->m_strPath.append(interface.attribute("name"));
263 newMethod->m_strPath.replace(".", "/");
264 methods.append(newMethod);
265 }
266 child = child.nextSiblingElement();
267 }
268}
269
270void introspectDBusServices(const QDBusConnection &connection,
271 const QString &strService,
272 const QString &strPath,
273 QVector<DBusScreenSaverInhibitMethod*> &methods)
274{
275 QDBusMessage call = QDBusMessage::createMethodCall(strService, strPath.isEmpty() ? QLatin1String("/") : strPath,
276 QLatin1String("org.freedesktop.DBus.Introspectable"),
277 QLatin1String("Introspect"));
278 QDBusReply<QString> xmlReply = connection.call(call);
279
280 if (!xmlReply.isValid())
281 return;
282
283 QDomDocument doc;
284 doc.setContent(xmlReply);
285 QDomElement node = doc.documentElement();
286 QDomElement child = node.firstChildElement();
287 while (!child.isNull())
288 {
289 if (child.tagName() == QLatin1String("node"))
290 {
291 QString subPath = strPath + QLatin1Char('/') + child.attribute(QLatin1String("name"));
292 introspectDBusServices(connection, strService, subPath, methods);
293 }
294 else if (child.tagName() == QLatin1String("interface"))
295 introspectDBusInterfaceNode(child, strService, methods);
296 child = child.nextSiblingElement();
297 }
298}
299#endif /* VBOX_WITH_SCREENSAVER_CONTROL */
300
301QVector<DBusScreenSaverInhibitMethod*> NativeWindowSubsystem::findDBusScrenSaverInhibitMethods()
302{
303 QVector<DBusScreenSaverInhibitMethod*> methods;
304#ifdef VBOX_WITH_SCREENSAVER_CONTROL
305 QDBusConnection connection = QDBusConnection::sessionBus();
306 if (!checkDBusConnection(connection))
307 return methods;
308
309 QStringList services = findDBusScreenSaverServices(connection);
310 foreach(const QString &strServiceName, services)
311 introspectDBusServices(connection, strServiceName, "", methods);
312#endif /* VBOX_WITH_SCREENSAVER_CONTROL */
313 return methods;
314}
315
316void NativeWindowSubsystem::toggleHostScrenSaver(bool fInhibit, QVector<DBusScreenSaverInhibitMethod*> &inOutInhibitMethods)
317{
318#ifdef VBOX_WITH_SCREENSAVER_CONTROL
319 QDBusConnection connection = QDBusConnection::sessionBus();
320 if (!checkDBusConnection(connection))
321 return;
322 for (int i = 0; i < inOutInhibitMethods.size(); ++i)
323 {
324 QDBusInterface screenSaverInterface(inOutInhibitMethods[i]->m_strServiceName, inOutInhibitMethods[i]->m_strPath,
325 inOutInhibitMethods[i]->m_strInterface, connection);
326 if (!screenSaverInterface.isValid())
327 {
328 QDBusError error = screenSaverInterface.lastError();
329 LogRel(("QDBus error for service %s: %s. %s\n",
330 inOutInhibitMethods[i]->m_strServiceName.toUtf8().constData(),
331 error.name().toUtf8().constData(),
332 error.message().toUtf8().constData()));
333 continue;
334 }
335 QDBusReply<uint> reply;
336 if (fInhibit)
337 {
338 reply = screenSaverInterface.call("Inhibit", "Oracle VirtualBox", "ScreenSaverInhibit");
339 if (reply.isValid())
340 inOutInhibitMethods[i]->m_iCookie = reply.value();
341 }
342 else
343 {
344 reply = screenSaverInterface.call("UnInhibit", inOutInhibitMethods[i]->m_iCookie);
345 }
346 if (!reply.isValid())
347 {
348 QDBusError error = reply.error();
349 LogRel(("QDBus inhibition call error for service %s: %s. %s\n",
350 inOutInhibitMethods[i]->m_strServiceName.toUtf8().constData(),
351 error.name().toUtf8().constData(),
352 error.message().toUtf8().constData()));
353 }
354 }
355#else
356 Q_UNUSED(fInhibit);
357 Q_UNUSED(inOutInhibitMethods);
358#endif /* VBOX_WITH_SCREENSAVER_CONTROL */
359}
360
361char *XXGetProperty(Display *pDpy, Window windowHandle, Atom propType, const char *pszPropName)
362{
363 Atom propNameAtom = XInternAtom(pDpy, pszPropName, True /* only_if_exists */);
364 if (propNameAtom == None)
365 return NULL;
366
367 Atom actTypeAtom = None;
368 int actFmt = 0;
369 unsigned long nItems = 0;
370 unsigned long nBytesAfter = 0;
371 unsigned char *propVal = NULL;
372 int rc = XGetWindowProperty(pDpy, windowHandle, propNameAtom,
373 0, LONG_MAX, False /* delete */,
374 propType, &actTypeAtom, &actFmt,
375 &nItems, &nBytesAfter, &propVal);
376 if (rc != Success)
377 return NULL;
378
379 return reinterpret_cast<char*>(propVal);
380}
381
382bool XXSendClientMessage(Display *pDpy, Window windowHandle, const char *pszMsg,
383 unsigned long aData0 = 0, unsigned long aData1 = 0,
384 unsigned long aData2 = 0, unsigned long aData3 = 0,
385 unsigned long aData4 = 0)
386{
387 Atom msgAtom = XInternAtom(pDpy, pszMsg, True /* only_if_exists */);
388 if (msgAtom == None)
389 return false;
390
391 XEvent ev;
392
393 ev.xclient.type = ClientMessage;
394 ev.xclient.serial = 0;
395 ev.xclient.send_event = True;
396 ev.xclient.display = pDpy;
397 ev.xclient.window = windowHandle;
398 ev.xclient.message_type = msgAtom;
399
400 /* Always send as 32 bit for now: */
401 ev.xclient.format = 32;
402 ev.xclient.data.l[0] = aData0;
403 ev.xclient.data.l[1] = aData1;
404 ev.xclient.data.l[2] = aData2;
405 ev.xclient.data.l[3] = aData3;
406 ev.xclient.data.l[4] = aData4;
407
408 return XSendEvent(pDpy, DefaultRootWindow(pDpy), False,
409 SubstructureRedirectMask, &ev) != 0;
410}
411
412bool NativeWindowSubsystem::activateWindow(bool fIsXServerAvailable, WId wId, bool fSwitchDesktop)
413{
414 if (fIsXServerAvailable)
415 return X11ActivateWindow(wId, fSwitchDesktop);
416 return WaylandActivateWindow(wId, fSwitchDesktop);
417}
418
419bool NativeWindowSubsystem::X11ActivateWindow(WId wId, bool fSwitchDesktop)
420{
421 bool fResult = true;
422 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
423
424 if (fSwitchDesktop)
425 {
426 /* Try to find the desktop ID using the NetWM property: */
427 CARD32 *pDesktop = (CARD32*)XXGetProperty(pDisplay, wId, XA_CARDINAL, "_NET_WM_DESKTOP");
428 if (pDesktop == NULL)
429 // WORKAROUND:
430 // if the NetWM properly is not supported try to find
431 // the desktop ID using the GNOME WM property.
432 pDesktop = (CARD32*)XXGetProperty(pDisplay, wId, XA_CARDINAL, "_WIN_WORKSPACE");
433
434 if (pDesktop != NULL)
435 {
436 bool ok = XXSendClientMessage(pDisplay, DefaultRootWindow(pDisplay), "_NET_CURRENT_DESKTOP", *pDesktop);
437 if (!ok)
438 {
439 Log1WarningFunc(("Couldn't switch to pDesktop=%08X\n", pDesktop));
440 fResult = false;
441 }
442 XFree(pDesktop);
443 }
444 else
445 {
446 Log1WarningFunc(("Couldn't find a pDesktop ID for wId=%08X\n", wId));
447 fResult = false;
448 }
449 }
450
451 bool ok = XXSendClientMessage(pDisplay, wId, "_NET_ACTIVE_WINDOW");
452 fResult &= !!ok;
453
454 XRaiseWindow(pDisplay, wId);
455 return fResult;
456}
457
458bool NativeWindowSubsystem::WaylandActivateWindow(WId wId, bool fSwitchDesktop)
459{
460 /// @todo implement
461 Q_UNUSED(wId);
462 Q_UNUSED(fSwitchDesktop);
463 return false;
464}
465
466bool NativeWindowSubsystem::X11SupportsFullScreenMonitorsProtocol()
467{
468 /* This method tests whether the current X11 window manager supports full-screen mode as we need it.
469 * Unfortunately the EWMH specification was not fully clear about whether we can expect to find
470 * all of these atoms on the _NET_SUPPORTED root window property, so we have to test with all
471 * interesting window managers. If this fails for a user when you think it should succeed
472 * they should try executing:
473 * xprop -root | egrep -w '_NET_WM_FULLSCREEN_MONITORS|_NET_WM_STATE|_NET_WM_STATE_FULLSCREEN'
474 * in an X11 terminal window.
475 * All three strings should be found under a property called "_NET_SUPPORTED(ATOM)". */
476
477 /* Using a global to get at the display does not feel right, but that is how it is done elsewhere in the code. */
478 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
479 Atom atomSupported = XInternAtom(pDisplay, "_NET_SUPPORTED",
480 True /* only_if_exists */);
481 Atom atomWMFullScreenMonitors = XInternAtom(pDisplay,
482 "_NET_WM_FULLSCREEN_MONITORS",
483 True /* only_if_exists */);
484 Atom atomWMState = XInternAtom(pDisplay,
485 "_NET_WM_STATE",
486 True /* only_if_exists */);
487 Atom atomWMStateFullScreen = XInternAtom(pDisplay,
488 "_NET_WM_STATE_FULLSCREEN",
489 True /* only_if_exists */);
490 bool fFoundFullScreenMonitors = false;
491 bool fFoundState = false;
492 bool fFoundStateFullScreen = false;
493 Atom atomType;
494 int cFormat;
495 unsigned long cItems;
496 unsigned long cbLeft;
497 Atom *pAtomHints;
498 int rc;
499 unsigned i;
500
501 if ( atomSupported == None || atomWMFullScreenMonitors == None
502 || atomWMState == None || atomWMStateFullScreen == None)
503 return false;
504 /* Get atom value: */
505 rc = XGetWindowProperty(pDisplay, DefaultRootWindow(pDisplay),
506 atomSupported, 0, 0x7fffffff /*LONG_MAX*/,
507 False /* delete */, XA_ATOM, &atomType,
508 &cFormat, &cItems, &cbLeft,
509 (unsigned char **)&pAtomHints);
510 if (rc != Success)
511 return false;
512 if (pAtomHints == NULL)
513 return false;
514 if (atomType == XA_ATOM && cFormat == 32 && cbLeft == 0)
515 for (i = 0; i < cItems; ++i)
516 {
517 if (pAtomHints[i] == atomWMFullScreenMonitors)
518 fFoundFullScreenMonitors = true;
519 if (pAtomHints[i] == atomWMState)
520 fFoundState = true;
521 if (pAtomHints[i] == atomWMStateFullScreen)
522 fFoundStateFullScreen = true;
523 }
524 XFree(pAtomHints);
525 return fFoundFullScreenMonitors && fFoundState && fFoundStateFullScreen;
526}
527
528bool NativeWindowSubsystem::X11SetFullScreenMonitor(QWidget *pWidget, ulong uScreenId)
529{
530 return XXSendClientMessage(NativeWindowSubsystem::X11GetDisplay(),
531 pWidget->window()->winId(),
532 "_NET_WM_FULLSCREEN_MONITORS",
533 uScreenId, uScreenId, uScreenId, uScreenId,
534 1 /* Source indication (1 = normal application) */);
535}
536
537QVector<Atom> flagsNetWmState(QWidget *pWidget)
538{
539 /* Get display: */
540 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
541
542 /* Prepare atoms: */
543 QVector<Atom> resultNetWmState;
544 Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
545
546 /* Get the size of the property data: */
547 Atom actual_type;
548 int iActualFormat;
549 ulong uPropertyLength;
550 ulong uBytesLeft;
551 uchar *pPropertyData = 0;
552 if (XGetWindowProperty(pDisplay, pWidget->window()->winId(),
553 net_wm_state, 0, 0, False, XA_ATOM, &actual_type, &iActualFormat,
554 &uPropertyLength, &uBytesLeft, &pPropertyData) == Success &&
555 actual_type == XA_ATOM && iActualFormat == 32)
556 {
557 resultNetWmState.resize(uBytesLeft / 4);
558 XFree((char*)pPropertyData);
559 pPropertyData = 0;
560
561 /* Fetch all data: */
562 if (XGetWindowProperty(pDisplay, pWidget->window()->winId(),
563 net_wm_state, 0, resultNetWmState.size(), False, XA_ATOM, &actual_type, &iActualFormat,
564 &uPropertyLength, &uBytesLeft, &pPropertyData) != Success)
565 resultNetWmState.clear();
566 else if (uPropertyLength != (ulong)resultNetWmState.size())
567 resultNetWmState.resize(uPropertyLength);
568
569 /* Put it into resultNetWmState: */
570 if (!resultNetWmState.isEmpty())
571 memcpy(resultNetWmState.data(), pPropertyData, resultNetWmState.size() * sizeof(Atom));
572 if (pPropertyData)
573 XFree((char*)pPropertyData);
574 }
575
576 /* Return result: */
577 return resultNetWmState;
578}
579
580#if 0 // unused for now?
581bool NativeWindowSubsystem::isFullScreenFlagSet(QWidget *pWidget)
582{
583 /* Get display: */
584 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
585
586 /* Prepare atoms: */
587 Atom net_wm_state_fullscreen = XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", True /* only if exists */);
588
589 /* Check if flagsNetWmState(pWidget) contains full-screen flag: */
590 return flagsNetWmState(pWidget).contains(net_wm_state_fullscreen);
591}
592
593void NativeWindowSubsystem::setFullScreenFlag(QWidget *pWidget)
594{
595 /* Get display: */
596 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
597
598 /* Prepare atoms: */
599 QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
600 Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
601 Atom net_wm_state_fullscreen = XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", True /* only if exists */);
602
603 /* Append resultNetWmState with fullscreen flag if necessary: */
604 if (!resultNetWmState.contains(net_wm_state_fullscreen))
605 {
606 resultNetWmState.append(net_wm_state_fullscreen);
607 /* Apply property to widget again: */
608 XChangeProperty(pDisplay, pWidget->window()->winId(),
609 net_wm_state, XA_ATOM, 32, PropModeReplace,
610 (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
611 }
612}
613#endif // unused for now?
614
615void NativeWindowSubsystem::X11SetSkipTaskBarFlag(QWidget *pWidget)
616{
617 /* Get display: */
618 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
619
620 /* Prepare atoms: */
621 QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
622 Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
623 Atom net_wm_state_skip_taskbar = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", True /* only if exists */);
624
625 /* Append resultNetWmState with skip-taskbar flag if necessary: */
626 if (!resultNetWmState.contains(net_wm_state_skip_taskbar))
627 {
628 resultNetWmState.append(net_wm_state_skip_taskbar);
629 /* Apply property to widget again: */
630 XChangeProperty(pDisplay, pWidget->window()->winId(),
631 net_wm_state, XA_ATOM, 32, PropModeReplace,
632 (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
633 }
634}
635
636void NativeWindowSubsystem::X11SetSkipPagerFlag(QWidget *pWidget)
637{
638 /* Get display: */
639 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
640
641 /* Prepare atoms: */
642 QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
643 Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
644 Atom net_wm_state_skip_pager = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_PAGER", True /* only if exists */);
645
646 /* Append resultNetWmState with skip-pager flag if necessary: */
647 if (!resultNetWmState.contains(net_wm_state_skip_pager))
648 {
649 resultNetWmState.append(net_wm_state_skip_pager);
650 /* Apply property to widget again: */
651 XChangeProperty(pDisplay, pWidget->window()->winId(),
652 net_wm_state, XA_ATOM, 32, PropModeReplace,
653 (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
654 }
655}
656
657void NativeWindowSubsystem::setWMClass(bool fIsXServerAvailable, QWidget *pWidget, const QString &strNameString, const QString &strClassString)
658{
659 if (fIsXServerAvailable)
660 X11SetWMClass(pWidget, strNameString, strClassString);
661 else
662 WaylandSetWMClass(pWidget, strNameString, strClassString);
663}
664
665void NativeWindowSubsystem::X11SetWMClass(QWidget *pWidget, const QString &strNameString, const QString &strClassString)
666{
667 /* Make sure all arguments set: */
668 AssertReturnVoid(pWidget && !strNameString.isNull() && !strClassString.isNull());
669
670 /* Define QByteArray objects to make sure data is alive within the scope: */
671 QByteArray nameByteArray;
672 /* Check the existence of RESOURCE_NAME env. variable and override name string if necessary: */
673 const char resourceName[] = "RESOURCE_NAME";
674 if (qEnvironmentVariableIsSet(resourceName))
675 nameByteArray = qgetenv(resourceName);
676 else
677 nameByteArray = strNameString.toLatin1();
678 QByteArray classByteArray = strClassString.toLatin1();
679
680 AssertReturnVoid(nameByteArray.data() && classByteArray.data());
681
682 XClassHint windowClass;
683 windowClass.res_name = nameByteArray.data();
684 windowClass.res_class = classByteArray.data();
685 /* Set WM_CLASS of the window to passed name and class strings: */
686 XSetClassHint(NativeWindowSubsystem::X11GetDisplay(), pWidget->window()->winId(), &windowClass);
687}
688
689void NativeWindowSubsystem::WaylandSetWMClass(QWidget *pWidget, const QString &strNameString, const QString &strClassString)
690{
691 Q_UNUSED(pWidget);
692 Q_UNUSED(strNameString);
693 Q_UNUSED(strClassString);
694 /// @todo implement
695}
696
697void NativeWindowSubsystem::setXwaylandMayGrabKeyboardFlag(bool fIsXServerAvailable, QWidget *pWidget)
698{
699 if (fIsXServerAvailable)
700 XXSendClientMessage(NativeWindowSubsystem::X11GetDisplay(), pWidget->window()->winId(),
701 "_XWAYLAND_MAY_GRAB_KEYBOARD", 1);
702}
703
704Display *NativeWindowSubsystem::X11GetDisplay()
705{
706 Display *pDisplay = 0;
707 if (qApp)
708 {
709 QNativeInterface::QX11Application *pX11App = qApp->nativeInterface<QNativeInterface::QX11Application>();
710 if (pX11App)
711 pDisplay = pX11App->display();
712 }
713 Assert(pDisplay);
714 return pDisplay;
715}
716
717xcb_connection_t *NativeWindowSubsystem::X11GetConnection()
718{
719 xcb_connection_t *pConnection = 0;
720 if (qApp)
721 {
722 QNativeInterface::QX11Application *pX11App = qApp->nativeInterface<QNativeInterface::QX11Application>();
723 if (pX11App)
724 pConnection = pX11App->connection();
725 }
726 Assert(pConnection);
727 return pConnection;
728}
729
730uint32_t NativeWindowSubsystem::X11GetAppRootWindow()
731{
732 Window idWindow = 0;
733 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
734 if (pDisplay)
735 idWindow = DefaultRootWindow(pDisplay);
736 return idWindow;
737}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use