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 }