Revision control
Copy as Markdown
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qx11capturablewindows_p.h"
#include <QtCore/qdebug.h>
#include <QtGui/qwindow.h>
#include <QtMultimedia/private/qcapturablewindow_p.h>
#include <X11/Xlib.h>
#include <optional>
QT_BEGIN_NAMESPACE
namespace { // Anonymous namespace start
[[nodiscard]] bool qIsX11WindowValid(Display *display, Window window)
{
XWindowAttributes windowAttributes = {};
return display
&& XGetWindowAttributes(display, window, &windowAttributes) != 0
&& windowAttributes.depth > 0;
}
[[nodiscard]] std::optional<QString> qGetX11WindowTitle(Display *display, Window window)
{
if (!display)
return std::nullopt;
char *windowTitle = nullptr;
if (XFetchName(display, window, &windowTitle) && windowTitle) {
QString out = QString::fromUtf8(windowTitle);
XFree(windowTitle);
return out;
}
return std::nullopt;
}
} // Anonymous namespace end
QX11CapturableWindows::~QX11CapturableWindows()
{
if (m_display)
XCloseDisplay(m_display);
}
QList<QCapturableWindow> QX11CapturableWindows::windows() const
{
auto display = this->display();
if (!display)
return {};
Atom atom = XInternAtom(display, "_NET_CLIENT_LIST", true);
Atom actualType = 0;
int format = 0;
unsigned long windowsCount = 0;
unsigned long bytesAfter = 0;
unsigned char *data = nullptr;
const int status = XGetWindowProperty(display, XDefaultRootWindow(display), atom, 0L, (~0L),
false, AnyPropertyType, &actualType, &format,
&windowsCount, &bytesAfter, &data);
if (status < Success || !data)
return {};
QList<QCapturableWindow> result;
auto freeDataGuard = qScopeGuard([data]() { XFree(data); });
auto windows = reinterpret_cast<XID *>(data);
for (unsigned long i = 0; i < windowsCount; i++) {
XID windowId = windows[i];
if (!qIsX11WindowValid(display, windowId))
continue;
result.push_back(QCapturableWindowPrivate::create(
static_cast<QCapturableWindowPrivate::Id>(windowId),
qGetX11WindowTitle(display, windowId).value_or(QString())));
}
return result;
}
bool QX11CapturableWindows::isWindowValid(const QCapturableWindowPrivate &window) const
{
return qIsX11WindowValid(this->display(), static_cast<Window>(window.id));
}
Display *QX11CapturableWindows::display() const
{
std::call_once(m_displayOnceFlag, [this]() { m_display = XOpenDisplay(nullptr); });
return m_display;
}
q23::expected<QCapturableWindow, QString> QX11CapturableWindows::fromQWindow(QWindow *window) const
{
const auto xId = static_cast<XID>(window->winId());
return QCapturableWindowPrivate::create(
static_cast<QCapturableWindowPrivate::Id>(xId),
window->title());
}
QT_END_NAMESPACE