kwin/waylandclient.cpp
Vlad Zahorodnii 1fb9f6f13a Switch to SPDX license markers
The main advantage of SPDX license identifiers over the traditional
license headers is that it's more difficult to overlook inappropriate
licenses for kwin, for example GPL 3. We also don't have to copy a
lot of boilerplate text.

In order to create this change, I ran licensedigger -r -c from the
toplevel source directory.
2020-08-07 19:57:56 +00:00

276 lines
6.7 KiB
C++

/*
* SPDX-FileCopyrightText: 2015 Martin Flöser <mgraesslin@kde.org>
* SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org>
* SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "waylandclient.h"
#include "screens.h"
#include "wayland_server.h"
#include "workspace.h"
#include <KWaylandServer/display.h>
#include <KWaylandServer/clientconnection.h>
#include <KWaylandServer/surface_interface.h>
#include <QFileInfo>
#include <csignal>
#include <sys/types.h>
#include <unistd.h>
using namespace KWaylandServer;
namespace KWin
{
WaylandClient::WaylandClient(SurfaceInterface *surface)
{
// Note that we cannot setup compositing here because we may need to call visibleRect(),
// which in its turn will call bufferGeometry(), which is a pure virtual method.
setSurface(surface);
m_windowId = waylandServer()->createWindowId(surface);
connect(this, &WaylandClient::frameGeometryChanged,
this, &WaylandClient::updateClientOutputs);
connect(this, &WaylandClient::frameGeometryChanged,
this, &WaylandClient::updateClientArea);
connect(this, &WaylandClient::desktopFileNameChanged,
this, &WaylandClient::updateIcon);
connect(screens(), &Screens::changed, this,
&WaylandClient::updateClientOutputs);
updateResourceName();
updateIcon();
}
QString WaylandClient::captionNormal() const
{
return m_captionNormal;
}
QString WaylandClient::captionSuffix() const
{
return m_captionSuffix;
}
QStringList WaylandClient::activities() const
{
return QStringList();
}
void WaylandClient::setOnAllActivities(bool set)
{
Q_UNUSED(set)
}
void WaylandClient::blockActivityUpdates(bool b)
{
Q_UNUSED(b)
}
QPoint WaylandClient::clientContentPos() const
{
return -clientPos();
}
QRect WaylandClient::transparentRect() const
{
return QRect();
}
quint32 WaylandClient::windowId() const
{
return m_windowId;
}
pid_t WaylandClient::pid() const
{
return surface()->client()->processId();
}
bool WaylandClient::isLockScreen() const
{
return surface()->client() == waylandServer()->screenLockerClientConnection();
}
bool WaylandClient::isInputMethod() const
{
return surface()->client() == waylandServer()->inputMethodConnection();
}
bool WaylandClient::isLocalhost() const
{
return true;
}
double WaylandClient::opacity() const
{
return m_opacity;
}
void WaylandClient::setOpacity(double opacity)
{
const qreal newOpacity = qBound(0.0, opacity, 1.0);
if (newOpacity == m_opacity) {
return;
}
const qreal oldOpacity = m_opacity;
m_opacity = newOpacity;
addRepaintFull();
emit opacityChanged(this, oldOpacity);
}
AbstractClient *WaylandClient::findModal(bool allow_itself)
{
Q_UNUSED(allow_itself)
return nullptr;
}
void WaylandClient::resizeWithChecks(const QSize &size, ForceGeometry_t force)
{
const QRect area = workspace()->clientArea(WorkArea, this);
int width = size.width();
int height = size.height();
// don't allow growing larger than workarea
if (width > area.width()) {
width = area.width();
}
if (height > area.height()) {
height = area.height();
}
setFrameGeometry(QRect(x(), y(), width, height), force);
}
void WaylandClient::killWindow()
{
if (!surface()) {
return;
}
auto c = surface()->client();
if (c->processId() == getpid() || c->processId() == 0) {
c->destroy();
return;
}
::kill(c->processId(), SIGTERM);
// give it time to terminate and only if terminate fails, try destroy Wayland connection
QTimer::singleShot(5000, c, &ClientConnection::destroy);
}
QByteArray WaylandClient::windowRole() const
{
return QByteArray();
}
bool WaylandClient::belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const
{
if (checks.testFlag(SameApplicationCheck::AllowCrossProcesses)) {
if (other->desktopFileName() == desktopFileName()) {
return true;
}
}
if (auto s = other->surface()) {
return s->client() == surface()->client();
}
return false;
}
bool WaylandClient::belongsToDesktop() const
{
const auto clients = waylandServer()->clients();
return std::any_of(clients.constBegin(), clients.constEnd(),
[this](const AbstractClient *client) {
if (belongsToSameApplication(client, SameApplicationChecks())) {
return client->isDesktop();
}
return false;
}
);
}
void WaylandClient::updateClientArea()
{
if (hasStrut()) {
workspace()->updateClientArea();
}
}
void WaylandClient::updateClientOutputs()
{
QVector<OutputInterface *> clientOutputs;
const auto outputs = waylandServer()->display()->outputs();
for (const auto output : outputs) {
if (output->isEnabled()) {
const QRect outputGeometry(output->globalPosition(), output->pixelSize() / output->scale());
if (frameGeometry().intersects(outputGeometry)) {
clientOutputs << output;
}
}
}
surface()->setOutputs(clientOutputs);
}
void WaylandClient::updateIcon()
{
const QString waylandIconName = QStringLiteral("wayland");
const QString dfIconName = iconFromDesktopFile();
const QString iconName = dfIconName.isEmpty() ? waylandIconName : dfIconName;
if (iconName == icon().name()) {
return;
}
setIcon(QIcon::fromTheme(iconName));
}
void WaylandClient::updateResourceName()
{
const QFileInfo fileInfo(surface()->client()->executablePath());
if (fileInfo.exists()) {
setResourceClass(fileInfo.fileName().toUtf8());
}
}
void WaylandClient::updateCaption()
{
const QString oldSuffix = m_captionSuffix;
const auto shortcut = shortcutCaptionSuffix();
m_captionSuffix = shortcut;
if ((!isSpecialWindow() || isToolbar()) && findClientWithSameCaption()) {
int i = 2;
do {
m_captionSuffix = shortcut + QLatin1String(" <") + QString::number(i) + QLatin1Char('>');
i++;
} while (findClientWithSameCaption());
}
if (m_captionSuffix != oldSuffix) {
emit captionChanged();
}
}
void WaylandClient::setCaption(const QString &caption)
{
const QString oldSuffix = m_captionSuffix;
m_captionNormal = caption.simplified();
updateCaption();
if (m_captionSuffix == oldSuffix) {
// Don't emit caption change twice it already got emitted by the changing suffix.
emit captionChanged();
}
}
void WaylandClient::doSetActive()
{
if (isActive()) { // TODO: Xwayland clients must be unfocused somewhere else.
StackingUpdatesBlocker blocker(workspace());
workspace()->focusToNull();
}
}
} // namespace KWin