File indexing completed on 2024-04-28 16:54:58
0001 /* 0002 SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "panelconfigview.h" 0008 #include "panelshadows_p.h" 0009 #include "shellcorona.h" 0010 0011 #include <QAction> 0012 #include <QDebug> 0013 #include <QDir> 0014 #include <QQmlComponent> 0015 #include <QQmlContext> 0016 #include <QQmlEngine> 0017 #include <QScreen> 0018 0019 #include <KActionCollection> 0020 #include <KWindowSystem> 0021 #include <KX11Extras> 0022 #include <klocalizedstring.h> 0023 #include <kwindoweffects.h> 0024 0025 #include <Plasma/Containment> 0026 #include <Plasma/PluginLoader> 0027 0028 #include <KWayland/Client/plasmashell.h> 0029 #include <KWayland/Client/surface.h> 0030 0031 #include <chrono> 0032 0033 using namespace std::chrono_literals; 0034 0035 //////////////////////////////PanelConfigView 0036 PanelConfigView::PanelConfigView(Plasma::Containment *containment, PanelView *panelView, QWindow *parent) 0037 : ConfigView(containment, parent) 0038 , m_containment(containment) 0039 , m_panelView(panelView) 0040 { 0041 connect(panelView, &QObject::destroyed, this, &QObject::deleteLater); 0042 0043 setScreen(panelView->screen()); 0044 0045 connect(panelView, &QWindow::screenChanged, &m_screenSyncTimer, QOverload<>::of(&QTimer::start)); 0046 m_screenSyncTimer.setSingleShot(true); 0047 m_screenSyncTimer.setInterval(150ms); 0048 connect(&m_screenSyncTimer, &QTimer::timeout, [=]() { 0049 setScreen(panelView->screen()); 0050 KWindowSystem::setType(winId(), NET::Dock); 0051 KWindowSystem::setState(winId(), NET::KeepAbove); 0052 syncGeometry(); 0053 syncLocation(); 0054 }); 0055 0056 KWindowSystem::setType(winId(), NET::Dock); 0057 KWindowSystem::setState(winId(), NET::KeepAbove); 0058 KX11Extras::forceActiveWindow(winId()); 0059 0060 updateBlurBehindAndContrast(); 0061 connect(&m_theme, &Plasma::Theme::themeChanged, this, &PanelConfigView::updateBlurBehindAndContrast); 0062 0063 rootContext()->setContextProperty(QStringLiteral("panel"), panelView); 0064 rootContext()->setContextProperty(QStringLiteral("configDialog"), this); 0065 connect(containment, &Plasma::Containment::formFactorChanged, this, &PanelConfigView::syncGeometry); 0066 connect(containment, &Plasma::Containment::locationChanged, this, &PanelConfigView::syncLocation); 0067 } 0068 0069 PanelConfigView::~PanelConfigView() 0070 { 0071 } 0072 0073 void PanelConfigView::init() 0074 { 0075 setSource(m_containment->corona()->kPackage().fileUrl("panelconfigurationui")); 0076 syncGeometry(); 0077 syncLocation(); 0078 } 0079 0080 void PanelConfigView::updateBlurBehindAndContrast() 0081 { 0082 KWindowEffects::enableBlurBehind(this, m_theme.blurBehindEnabled()); 0083 KWindowEffects::enableBackgroundContrast(this, 0084 m_theme.backgroundContrastEnabled(), 0085 m_theme.backgroundContrast(), 0086 m_theme.backgroundIntensity(), 0087 m_theme.backgroundSaturation()); 0088 } 0089 0090 void PanelConfigView::showAddWidgetDialog() 0091 { 0092 QAction *addWidgetAction = m_containment->actions()->action(QStringLiteral("add widgets")); 0093 if (addWidgetAction) { 0094 addWidgetAction->trigger(); 0095 } 0096 } 0097 0098 void PanelConfigView::addPanelSpacer() 0099 { 0100 ShellCorona *c = qobject_cast<ShellCorona *>(m_containment->corona()); 0101 if (!c) { 0102 return; 0103 } 0104 // Add a spacer at the end *except* if there is exactly one spacer already 0105 // this to trigger the panel centering mode of the spacer in a slightly more discoverable way 0106 c->evaluateScript(QStringLiteral("panel = panelById(") + QString::number(m_containment->id()) 0107 + QStringLiteral(");" 0108 "var spacers = panel.widgets(\"org.kde.plasma.panelspacer\");" 0109 "if (spacers.length === 1) {" 0110 " panel.addWidget(\"org.kde.plasma.panelspacer\", 0,0,1,1);" 0111 "} else {" 0112 " panel.addWidget(\"org.kde.plasma.panelspacer\");" 0113 "}")); 0114 } 0115 0116 void PanelConfigView::syncGeometry() 0117 { 0118 if (!m_containment || !rootObject()) { 0119 return; 0120 } 0121 0122 if (m_containment->formFactor() == Plasma::Types::Vertical) { 0123 QSize s(rootObject()->implicitWidth(), screen()->size().height()); 0124 resize(s); 0125 setMinimumSize(s); 0126 setMaximumSize(s); 0127 0128 if (m_containment->location() == Plasma::Types::LeftEdge) { 0129 setPosition(m_panelView->geometry().right(), screen()->geometry().top()); 0130 } else if (m_containment->location() == Plasma::Types::RightEdge) { 0131 setPosition(m_panelView->geometry().left() - width(), screen()->geometry().top()); 0132 } 0133 0134 } else { 0135 QSize s(screen()->size().width(), rootObject()->implicitHeight()); 0136 resize(s); 0137 setMinimumSize(s); 0138 setMaximumSize(s); 0139 0140 if (m_containment->location() == Plasma::Types::TopEdge) { 0141 setPosition(screen()->geometry().left(), m_panelView->geometry().bottom()); 0142 } else if (m_containment->location() == Plasma::Types::BottomEdge) { 0143 setPosition(screen()->geometry().left(), m_panelView->geometry().top() - height()); 0144 } 0145 } 0146 } 0147 0148 void PanelConfigView::syncLocation() 0149 { 0150 if (!m_containment) { 0151 return; 0152 } 0153 0154 KWindowEffects::SlideFromLocation slideLocation = KWindowEffects::NoEdge; 0155 Plasma::FrameSvg::EnabledBorders enabledBorders = Plasma::FrameSvg::AllBorders; 0156 0157 switch (m_containment->location()) { 0158 case Plasma::Types::TopEdge: 0159 slideLocation = KWindowEffects::TopEdge; 0160 enabledBorders = Plasma::FrameSvg::BottomBorder; 0161 break; 0162 case Plasma::Types::RightEdge: 0163 slideLocation = KWindowEffects::RightEdge; 0164 enabledBorders = Plasma::FrameSvg::LeftBorder; 0165 break; 0166 case Plasma::Types::BottomEdge: 0167 slideLocation = KWindowEffects::BottomEdge; 0168 enabledBorders = Plasma::FrameSvg::TopBorder; 0169 break; 0170 case Plasma::Types::LeftEdge: 0171 slideLocation = KWindowEffects::LeftEdge; 0172 enabledBorders = Plasma::FrameSvg::RightBorder; 0173 break; 0174 default: 0175 break; 0176 } 0177 0178 KWindowEffects::slideWindow(this, slideLocation, -1); 0179 0180 if (m_enabledBorders != enabledBorders) { 0181 m_enabledBorders = enabledBorders; 0182 0183 PanelShadows::self()->setEnabledBorders(this, enabledBorders); 0184 0185 Q_EMIT enabledBordersChanged(); 0186 } 0187 } 0188 0189 void PanelConfigView::showEvent(QShowEvent *ev) 0190 { 0191 QQuickWindow::showEvent(ev); 0192 0193 KWindowSystem::setType(winId(), NET::Dock); 0194 setFlags(Qt::WindowFlags((flags() | Qt::FramelessWindowHint) & (~Qt::WindowDoesNotAcceptFocus)) | Qt::X11BypassWindowManagerHint 0195 | Qt::WindowStaysOnTopHint); 0196 KWindowSystem::setState(winId(), NET::KeepAbove); 0197 KX11Extras::forceActiveWindow(winId()); 0198 updateBlurBehindAndContrast(); 0199 syncGeometry(); 0200 syncLocation(); 0201 0202 // this because due to Qt xcb implementation the actual flags gets set only after a while after the window is actually visible 0203 m_screenSyncTimer.start(); 0204 0205 if (m_containment) { 0206 m_containment->setUserConfiguring(true); 0207 } 0208 0209 PanelShadows::self()->addWindow(this, m_enabledBorders); 0210 } 0211 0212 void PanelConfigView::hideEvent(QHideEvent *ev) 0213 { 0214 QQuickWindow::hideEvent(ev); 0215 0216 if (m_containment) { 0217 m_containment->setUserConfiguring(false); 0218 } 0219 deleteLater(); 0220 } 0221 0222 void PanelConfigView::focusOutEvent(QFocusEvent *ev) 0223 { 0224 const QWindow *focusWindow = QGuiApplication::focusWindow(); 0225 0226 if (focusWindow && ((focusWindow->flags().testFlag(Qt::Popup)) || focusWindow->objectName() == QLatin1String("QMenuClassWindow"))) { 0227 return; 0228 } 0229 Q_UNUSED(ev) 0230 close(); 0231 } 0232 0233 void PanelConfigView::moveEvent(QMoveEvent *ev) 0234 { 0235 if (m_shellSurface) { 0236 m_shellSurface->setPosition(ev->pos()); 0237 } 0238 } 0239 0240 bool PanelConfigView::event(QEvent *e) 0241 { 0242 if (e->type() == QEvent::PlatformSurface) { 0243 switch (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType()) { 0244 case QPlatformSurfaceEvent::SurfaceCreated: 0245 KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager); 0246 0247 if (m_shellSurface) { 0248 break; 0249 } 0250 if (ShellCorona *c = qobject_cast<ShellCorona *>(m_containment->corona())) { 0251 using namespace KWayland::Client; 0252 PlasmaShell *interface = c->waylandPlasmaShellInterface(); 0253 if (!interface) { 0254 break; 0255 } 0256 Surface *s = Surface::fromWindow(this); 0257 if (!s) { 0258 break; 0259 } 0260 m_shellSurface = interface->createSurface(s, this); 0261 m_shellSurface->setPanelTakesFocus(true); 0262 } 0263 break; 0264 case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: 0265 delete m_shellSurface; 0266 m_shellSurface = nullptr; 0267 PanelShadows::self()->removeWindow(this); 0268 break; 0269 } 0270 } 0271 0272 return PlasmaQuick::ConfigView::event(e); 0273 } 0274 0275 void PanelConfigView::setVisibilityMode(PanelView::VisibilityMode mode) 0276 { 0277 m_panelView->setVisibilityMode(mode); 0278 Q_EMIT visibilityModeChanged(); 0279 } 0280 0281 PanelView::VisibilityMode PanelConfigView::visibilityMode() const 0282 { 0283 return m_panelView->visibilityMode(); 0284 } 0285 0286 void PanelConfigView::setOpacityMode(PanelView::OpacityMode mode) 0287 { 0288 m_panelView->setOpacityMode(mode); 0289 Q_EMIT opacityModeChanged(); 0290 } 0291 0292 PanelView::OpacityMode PanelConfigView::opacityMode() const 0293 { 0294 return m_panelView->opacityMode(); 0295 } 0296 0297 Plasma::FrameSvg::EnabledBorders PanelConfigView::enabledBorders() const 0298 { 0299 return m_enabledBorders; 0300 } 0301 0302 #include "moc_panelconfigview.cpp"