/* * Copyright (C) 2020 ~ 2021 CyberOS Team. * * Author: rekols * * 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 . */ #include "xwindowinterface.h" #include "utils.h" #include #include #include #include #include #include #include #include // X11 #include 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 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 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 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 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, bool isMax) { 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 + (isMax ? 0 : DockSettings::self()->edgeMargins()); strut.bottom_start = rect.x(); strut.bottom_end = rect.x() + rect.width(); 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(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); } }