227 lines
7.3 KiB
C++
227 lines
7.3 KiB
C++
/*
|
|
* Copyright (C) 2021 CutefishOS Team.
|
|
*
|
|
* Author: rekols <revenmartin@gmail.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "xwindowinterface.h"
|
|
#include "utils.h"
|
|
|
|
#include <QTimer>
|
|
#include <QDebug>
|
|
#include <QX11Info>
|
|
#include <QWindow>
|
|
#include <QScreen>
|
|
|
|
#include <KWindowEffects>
|
|
#include <KWindowSystem>
|
|
#include <KWindowInfo>
|
|
|
|
// X11
|
|
#include <NETWM>
|
|
|
|
static XWindowInterface *INSTANCE = nullptr;
|
|
|
|
XWindowInterface *XWindowInterface::instance()
|
|
{
|
|
if (!INSTANCE)
|
|
INSTANCE = new XWindowInterface;
|
|
|
|
return INSTANCE;
|
|
}
|
|
|
|
XWindowInterface::XWindowInterface(QObject *parent)
|
|
: QObject(parent)
|
|
{
|
|
connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, &XWindowInterface::onWindowadded);
|
|
connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, this, &XWindowInterface::windowRemoved);
|
|
connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &XWindowInterface::activeChanged);
|
|
}
|
|
|
|
void XWindowInterface::enableBlurBehind(QWindow *view, bool enable, const QRegion ®ion)
|
|
{
|
|
KWindowEffects::enableBlurBehind(view->winId(), enable, region);
|
|
}
|
|
|
|
WId XWindowInterface::activeWindow()
|
|
{
|
|
return KWindowSystem::activeWindow();
|
|
}
|
|
|
|
void XWindowInterface::minimizeWindow(WId win)
|
|
{
|
|
KWindowSystem::minimizeWindow(win);
|
|
}
|
|
|
|
void XWindowInterface::closeWindow(WId id)
|
|
{
|
|
// FIXME: Why there is no such thing in KWindowSystem??
|
|
NETRootInfo(QX11Info::connection(), NET::CloseWindow).closeWindowRequest(id);
|
|
}
|
|
|
|
void XWindowInterface::forceActiveWindow(WId win)
|
|
{
|
|
KWindowSystem::forceActiveWindow(win);
|
|
}
|
|
|
|
QMap<QString, QVariant> XWindowInterface::requestInfo(quint64 wid)
|
|
{
|
|
const KWindowInfo winfo { wid, NET::WMFrameExtents
|
|
| NET::WMWindowType
|
|
| NET::WMGeometry
|
|
| NET::WMDesktop
|
|
| NET::WMState
|
|
| NET::WMName
|
|
| NET::WMVisibleName,
|
|
NET::WM2WindowClass
|
|
| NET::WM2Activities
|
|
| NET::WM2AllowedActions
|
|
| NET::WM2TransientFor };
|
|
QMap<QString, QVariant> result;
|
|
const QString winClass = QString(winfo.windowClassClass());
|
|
|
|
result.insert("iconName", winClass.toLower());
|
|
result.insert("active", wid == KWindowSystem::activeWindow());
|
|
result.insert("visibleName", winfo.visibleName());
|
|
result.insert("id", winClass);
|
|
|
|
return result;
|
|
}
|
|
|
|
QString XWindowInterface::requestWindowClass(quint64 wid)
|
|
{
|
|
return KWindowInfo(wid, NET::Supported, NET::WM2WindowClass).windowClassClass();
|
|
}
|
|
|
|
bool XWindowInterface::isAcceptableWindow(quint64 wid)
|
|
{
|
|
QFlags<NET::WindowTypeMask> ignoreList;
|
|
ignoreList |= NET::DesktopMask;
|
|
ignoreList |= NET::DockMask;
|
|
ignoreList |= NET::SplashMask;
|
|
ignoreList |= NET::ToolbarMask;
|
|
ignoreList |= NET::MenuMask;
|
|
ignoreList |= NET::PopupMenuMask;
|
|
ignoreList |= NET::NotificationMask;
|
|
|
|
KWindowInfo info(wid, NET::WMWindowType | NET::WMState, NET::WM2TransientFor | NET::WM2WindowClass);
|
|
|
|
if (!info.valid())
|
|
return false;
|
|
|
|
if (NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList))
|
|
return false;
|
|
|
|
if (info.hasState(NET::SkipTaskbar) || info.hasState(NET::SkipPager))
|
|
return false;
|
|
|
|
// WM_TRANSIENT_FOR hint not set - normal window
|
|
WId transFor = info.transientFor();
|
|
if (transFor == 0 || transFor == wid || transFor == (WId) QX11Info::appRootWindow())
|
|
return true;
|
|
|
|
info = KWindowInfo(transFor, NET::WMWindowType);
|
|
|
|
QFlags<NET::WindowTypeMask> normalFlag;
|
|
normalFlag |= NET::NormalMask;
|
|
normalFlag |= NET::DialogMask;
|
|
normalFlag |= NET::UtilityMask;
|
|
|
|
return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag);
|
|
}
|
|
|
|
void XWindowInterface::setViewStruts(QWindow *view, DockSettings::Direction direction, const QRect &rect)
|
|
{
|
|
NETExtendedStrut strut;
|
|
|
|
const auto screen = view->screen();
|
|
|
|
const QRect currentScreen {screen->geometry()};
|
|
const QRect wholeScreen { {0, 0}, screen->virtualSize() };
|
|
|
|
switch (direction) {
|
|
case DockSettings::Left: {
|
|
const int leftOffset = { screen->geometry().left() };
|
|
strut.left_width = rect.width() + leftOffset + DockSettings::self()->edgeMargins();
|
|
strut.left_start = rect.y();
|
|
strut.left_end = rect.y() + rect.height() - 1;
|
|
break;
|
|
}
|
|
case DockSettings::Bottom: {
|
|
const int bottomOffset { wholeScreen.bottom() - currentScreen.bottom() };
|
|
strut.bottom_width = rect.height() + bottomOffset + DockSettings::self()->edgeMargins();
|
|
strut.bottom_start = rect.x();
|
|
strut.bottom_end = rect.x() + rect.width();
|
|
break;
|
|
}
|
|
case DockSettings::Right: {
|
|
const int rightOffset = {wholeScreen.right() - currentScreen.right()};
|
|
strut.right_width = rect.width() + rightOffset + DockSettings::self()->edgeMargins();
|
|
strut.right_start = rect.y();
|
|
strut.right_end = rect.y() + rect.height() - 1;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
KWindowSystem::setExtendedStrut(view->winId(),
|
|
strut.left_width, strut.left_start, strut.left_end,
|
|
strut.right_width, strut.right_start, strut.right_end,
|
|
strut.top_width, strut.top_start, strut.top_end,
|
|
strut.bottom_width, strut.bottom_start, strut.bottom_end
|
|
);
|
|
}
|
|
|
|
void XWindowInterface::startInitWindows()
|
|
{
|
|
for (auto wid : KWindowSystem::self()->windows()) {
|
|
onWindowadded(wid);
|
|
}
|
|
}
|
|
|
|
QString XWindowInterface::desktopFilePath(quint64 wid)
|
|
{
|
|
const KWindowInfo info(wid, NET::Properties(), NET::WM2WindowClass | NET::WM2DesktopFileName);
|
|
return Utils::instance()->desktopPathFromMetadata(info.windowClassClass(),
|
|
NETWinInfo(QX11Info::connection(), wid,
|
|
QX11Info::appRootWindow(),
|
|
NET::WMPid,
|
|
NET::Properties2()).pid(),
|
|
info.windowClassName());
|
|
}
|
|
|
|
void XWindowInterface::setIconGeometry(quint64 wid, const QRect &rect)
|
|
{
|
|
NETWinInfo info(QX11Info::connection(),
|
|
wid,
|
|
(WId) QX11Info::appRootWindow(),
|
|
NET::WMIconGeometry,
|
|
QFlags<NET::Property2>(1));
|
|
NETRect nrect;
|
|
nrect.pos.x = rect.x();
|
|
nrect.pos.y = rect.y();
|
|
nrect.size.height = rect.height();
|
|
nrect.size.width = rect.width();
|
|
info.setIconGeometry(nrect);
|
|
}
|
|
|
|
void XWindowInterface::onWindowadded(quint64 wid)
|
|
{
|
|
if (isAcceptableWindow(wid)) {
|
|
emit windowAdded(wid);
|
|
}
|
|
}
|