File indexing completed on 2024-05-05 05:38:21

0001 /*
0002     SPDX-FileCopyrightText: 2023 David Edmundson <davidedmundson@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "x11windowscreenrelativepositioner.h"
0008 
0009 #include <QScreen>
0010 
0011 #include <KWindowSystem>
0012 
0013 X11WindowScreenRelativePositioner::X11WindowScreenRelativePositioner(QWindow *window)
0014     : QObject(window)
0015     , m_window(window)
0016 {
0017     if (!KWindowSystem::isPlatformX11()) {
0018         qCritical("X11WindowScreenRelativePositioner should only be used on X11 windows");
0019     }
0020 
0021     m_window->installEventFilter(this);
0022     connect(m_window, &QWindow::screenChanged, this, &X11WindowScreenRelativePositioner::handleScreenChanged);
0023 
0024     handleScreenChanged();
0025 }
0026 
0027 void X11WindowScreenRelativePositioner::setAnchors(Qt::Edges anchors)
0028 {
0029     if (m_anchors == anchors) {
0030         return;
0031     }
0032 
0033     m_anchors = anchors;
0034     Q_EMIT anchorsChanged();
0035     polish();
0036 }
0037 
0038 void X11WindowScreenRelativePositioner::setMargins(const QMargins &margins)
0039 {
0040     if (m_margins == margins) {
0041         return;
0042     }
0043     m_margins = margins;
0044     Q_EMIT marginsChanged();
0045     polish();
0046 }
0047 
0048 bool X11WindowScreenRelativePositioner::eventFilter(QObject *watched, QEvent *event)
0049 {
0050     if (watched != m_window) {
0051         return false;
0052     }
0053     switch (event->type()) {
0054     case QEvent::UpdateRequest:
0055         updatePolish();
0056         break;
0057     case QEvent::Resize:
0058     case QEvent::Expose:
0059         polish();
0060         break;
0061     default:
0062         break;
0063     }
0064     return false;
0065 }
0066 
0067 void X11WindowScreenRelativePositioner::polish()
0068 {
0069     m_needsRepositioning = true;
0070     m_window->requestUpdate();
0071 }
0072 
0073 void X11WindowScreenRelativePositioner::updatePolish()
0074 {
0075     if (m_needsRepositioning) {
0076         reposition();
0077         m_needsRepositioning = false;
0078     }
0079 }
0080 
0081 void X11WindowScreenRelativePositioner::reposition()
0082 {
0083     QScreen *screen = m_window->screen();
0084 
0085     QRect screenRect = screen->availableGeometry();
0086     screenRect = screenRect.marginsRemoved(m_margins);
0087 
0088     QRect targetRect;
0089     // Y
0090     if (m_anchors.testFlags({Qt::TopEdge, Qt::BottomEdge})) {
0091         targetRect.setTop(screenRect.top());
0092         targetRect.setBottom(screenRect.bottom());
0093     } else {
0094         targetRect.setHeight(m_window->height());
0095         if (m_anchors.testFlag(Qt::TopEdge)) {
0096             targetRect.moveTop(screenRect.top());
0097         } else if (m_anchors.testFlag(Qt::BottomEdge)) {
0098             targetRect.moveBottom(screenRect.bottom());
0099         } else {
0100             targetRect.moveCenter(QPoint(0, screenRect.center().y()));
0101         }
0102     }
0103 
0104     // X
0105     if (m_anchors.testFlags({Qt::LeftEdge, Qt::RightEdge})) {
0106         targetRect.setLeft(screenRect.left());
0107         targetRect.setRight(screenRect.right());
0108     } else {
0109         targetRect.setWidth(m_window->width());
0110         if (m_anchors.testFlag(Qt::LeftEdge)) {
0111             targetRect.moveLeft(screenRect.left());
0112         } else if (m_anchors.testFlag(Qt::RightEdge)) {
0113             targetRect.moveRight(screenRect.right());
0114         } else {
0115             targetRect.moveCenter(QPoint(screenRect.center().x(), targetRect.center().y()));
0116         }
0117     }
0118 
0119     m_window->setGeometry(targetRect);
0120 }
0121 
0122 void X11WindowScreenRelativePositioner::handleScreenChanged()
0123 {
0124     QScreen *newScreen = m_window->screen();
0125     if (newScreen == m_screen) {
0126         return;
0127     }
0128     if (m_screen) {
0129         disconnect(m_screen, nullptr, this, nullptr);
0130     }
0131     m_screen = newScreen;
0132     connect(newScreen, &QScreen::availableGeometryChanged, this, &X11WindowScreenRelativePositioner::polish);
0133     polish();
0134 }