File indexing completed on 2024-04-28 16:54:46
0001 /* 0002 SPDX-FileCopyrightText: 2000 Matthias Ettrich <ettrich@kde.org> 0003 SPDX-FileCopyrightText: 2007 Urs Wolfer <uwolfer @ kde.org> 0004 0005 SPDX-License-Identifier: MIT 0006 */ 0007 0008 #include "shutdowndlg.h" 0009 0010 #include <QApplication> 0011 #include <QDBusConnection> 0012 #include <QDBusMessage> 0013 #include <QDBusPendingCall> 0014 #include <QDBusPendingCallWatcher> 0015 #include <QDBusPendingReply> 0016 #include <QDBusVariant> 0017 #include <QFile> 0018 #include <QPainter> 0019 #include <QQmlContext> 0020 #include <QQmlEngine> 0021 #include <QQmlPropertyMap> 0022 #include <QQuickItem> 0023 #include <QQuickView> 0024 #include <QStandardPaths> 0025 #include <QTimer> 0026 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0027 #include <private/qtx11extras_p.h> 0028 #else 0029 #include <QX11Info> 0030 #endif 0031 0032 #include <KAuthorized> 0033 #include <KConfigGroup> 0034 #include <KLocalizedString> 0035 #include <KSharedConfig> 0036 #include <KUser> 0037 #include <KWindowEffects> 0038 #include <KWindowSystem> 0039 #include <KX11Extras> 0040 #include <LayerShellQt/Window> 0041 0042 #include <netwm.h> 0043 #include <stdio.h> 0044 0045 #include <X11/Xatom.h> 0046 #include <X11/Xutil.h> 0047 #include <fixx11h.h> 0048 0049 #include <config-workspace.h> 0050 #include <debug.h> 0051 0052 static const QString s_login1Service = QStringLiteral("org.freedesktop.login1"); 0053 static const QString s_login1Path = QStringLiteral("/org/freedesktop/login1"); 0054 static const QString s_dbusPropertiesInterface = QStringLiteral("org.freedesktop.DBus.Properties"); 0055 static const QString s_login1ManagerInterface = QStringLiteral("org.freedesktop.login1.Manager"); 0056 static const QString s_login1RebootToFirmwareSetup = QStringLiteral("RebootToFirmwareSetup"); 0057 0058 KSMShutdownDlg::KSMShutdownDlg(QWindow *parent, KWorkSpace::ShutdownType sdtype, QScreen *screen) 0059 : QuickViewSharedEngine(parent) 0060 , m_result(false) 0061 // this is a WType_Popup on purpose. Do not change that! Not 0062 // having a popup here has severe side effects. 0063 { 0064 // window stuff 0065 setColor(QColor(Qt::transparent)); 0066 setScreen(screen); 0067 0068 if (KWindowSystem::isPlatformWayland() && !m_windowed) { 0069 if (auto w = LayerShellQt::Window::get(this)) { 0070 w->setKeyboardInteractivity(LayerShellQt::Window::KeyboardInteractivityExclusive); 0071 w->setExclusiveZone(-1); 0072 w->setLayer(LayerShellQt::Window::LayerOverlay); 0073 w->setDesiredOutput(screen); 0074 } 0075 } 0076 0077 setResizeMode(KQuickAddons::QuickViewSharedEngine::SizeRootObjectToView); 0078 0079 // Qt doesn't set this on unmanaged windows 0080 // FIXME: or does it? 0081 if (KWindowSystem::isPlatformX11()) { 0082 XChangeProperty(QX11Info::display(), 0083 winId(), 0084 XInternAtom(QX11Info::display(), "WM_WINDOW_ROLE", False), 0085 XA_STRING, 0086 8, 0087 PropModeReplace, 0088 (unsigned char *)"logoutdialog", 0089 strlen("logoutdialog")); 0090 0091 XClassHint classHint; 0092 classHint.res_name = const_cast<char *>("ksmserver-logout-greeter"); 0093 classHint.res_class = const_cast<char *>("ksmserver-logout-greeter"); 0094 XSetClassHint(QX11Info::display(), winId(), &classHint); 0095 } 0096 0097 // QQuickView *windowContainer = QQuickView::createWindowContainer(m_view, this); 0098 // windowContainer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 0099 QQmlContext *context = rootContext(); 0100 context->setContextProperty(QStringLiteral("maysd"), m_session.canShutdown()); 0101 context->setContextProperty(QStringLiteral("sdtype"), sdtype); 0102 0103 QQmlPropertyMap *mapShutdownType = new QQmlPropertyMap(this); 0104 mapShutdownType->insert(QStringLiteral("ShutdownTypeDefault"), QVariant::fromValue<int>(KWorkSpace::ShutdownTypeDefault)); 0105 mapShutdownType->insert(QStringLiteral("ShutdownTypeNone"), QVariant::fromValue<int>(KWorkSpace::ShutdownTypeNone)); 0106 mapShutdownType->insert(QStringLiteral("ShutdownTypeReboot"), QVariant::fromValue<int>(KWorkSpace::ShutdownTypeReboot)); 0107 mapShutdownType->insert(QStringLiteral("ShutdownTypeHalt"), QVariant::fromValue<int>(KWorkSpace::ShutdownTypeHalt)); 0108 mapShutdownType->insert(QStringLiteral("ShutdownTypeLogout"), QVariant::fromValue<int>(KWorkSpace::ShutdownTypeLogout)); 0109 context->setContextProperty(QStringLiteral("ShutdownType"), mapShutdownType); 0110 0111 QQmlPropertyMap *mapSpdMethods = new QQmlPropertyMap(this); 0112 mapSpdMethods->insert(QStringLiteral("StandbyState"), m_session.canSuspend()); 0113 mapSpdMethods->insert(QStringLiteral("SuspendState"), m_session.canSuspend()); 0114 mapSpdMethods->insert(QStringLiteral("HibernateState"), m_session.canHibernate()); 0115 context->setContextProperty(QStringLiteral("spdMethods"), mapSpdMethods); 0116 context->setContextProperty(QStringLiteral("canLogout"), m_session.canLogout()); 0117 0118 // Trying to access a non-existent context property throws an error, always create the property and then update it later 0119 context->setContextProperty("rebootToFirmwareSetup", false); 0120 0121 QDBusMessage message = QDBusMessage::createMethodCall(s_login1Service, s_login1Path, s_dbusPropertiesInterface, QStringLiteral("Get")); 0122 message.setArguments({s_login1ManagerInterface, s_login1RebootToFirmwareSetup}); 0123 QDBusPendingReply<QVariant> call = QDBusConnection::systemBus().asyncCall(message); 0124 QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(call, this); 0125 connect(callWatcher, &QDBusPendingCallWatcher::finished, context, [context](QDBusPendingCallWatcher *watcher) { 0126 QDBusPendingReply<QVariant> reply = *watcher; 0127 watcher->deleteLater(); 0128 0129 if (reply.value().toBool()) { 0130 context->setContextProperty("rebootToFirmwareSetup", true); 0131 } 0132 }); 0133 0134 // TODO KF6 remove, used to read "BootManager" from kdmrc 0135 context->setContextProperty(QStringLiteral("bootManager"), QStringLiteral("None")); 0136 0137 // TODO KF6 remove. Unused 0138 context->setContextProperty(QStringLiteral("choose"), false); 0139 0140 // TODO KF6 remove, used to call KDisplayManager::bootOptions 0141 QStringList rebootOptions; 0142 int def = 0; 0143 QQmlPropertyMap *rebootOptionsMap = new QQmlPropertyMap(this); 0144 rebootOptionsMap->insert(QStringLiteral("options"), QVariant::fromValue(rebootOptions)); 0145 rebootOptionsMap->insert(QStringLiteral("default"), QVariant::fromValue(def)); 0146 context->setContextProperty(QStringLiteral("rebootOptions"), rebootOptionsMap); 0147 0148 // engine stuff 0149 engine()->rootContext()->setContextObject(new KLocalizedContext(engine())); 0150 } 0151 0152 void KSMShutdownDlg::init(const KPackage::Package &package) 0153 { 0154 rootContext()->setContextProperty(QStringLiteral("screenGeometry"), screen()->geometry()); 0155 0156 const QString fileName = package.filePath("logoutmainscript"); 0157 0158 if (QFile::exists(fileName)) { 0159 setSource(package.fileUrl("logoutmainscript")); 0160 } else { 0161 qCWarning(LOGOUT_GREETER) << "Couldn't find a theme for the Shutdown dialog" << fileName; 0162 return; 0163 } 0164 0165 if (!errors().isEmpty()) { 0166 qCWarning(LOGOUT_GREETER) << errors(); 0167 } 0168 0169 connect(rootObject(), SIGNAL(logoutRequested()), SLOT(slotLogout())); 0170 connect(rootObject(), SIGNAL(haltRequested()), SLOT(slotHalt())); 0171 connect(rootObject(), SIGNAL(suspendRequested(int)), SLOT(slotSuspend(int))); 0172 connect(rootObject(), SIGNAL(rebootRequested()), SLOT(slotReboot())); 0173 connect(rootObject(), SIGNAL(rebootRequested2(int)), SLOT(slotReboot(int))); 0174 connect(rootObject(), SIGNAL(cancelRequested()), SLOT(reject())); 0175 connect(rootObject(), SIGNAL(lockScreenRequested()), SLOT(slotLockScreen())); 0176 0177 connect(screen(), &QScreen::geometryChanged, this, [this] { 0178 setGeometry(screen()->geometry()); 0179 }); 0180 0181 // decide in backgroundcontrast whether doing things darker or lighter 0182 // set backgroundcontrast here, because in QEvent::PlatformSurface 0183 // is too early and we don't have the root object yet 0184 const QColor backgroundColor = rootObject() ? rootObject()->property("backgroundColor").value<QColor>() : QColor(); 0185 KWindowEffects::enableBackgroundContrast(this, true, 0.4, (backgroundColor.value() > 128 ? 1.6 : 0.3), 1.7); 0186 if (m_windowed) { 0187 show(); 0188 } else { 0189 showFullScreen(); 0190 setFlag(Qt::FramelessWindowHint); 0191 } 0192 requestActivate(); 0193 0194 KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager); 0195 0196 setKeyboardGrabEnabled(true); 0197 KWindowEffects::enableBlurBehind(this, true); 0198 } 0199 0200 void KSMShutdownDlg::resizeEvent(QResizeEvent *e) 0201 { 0202 KQuickAddons::QuickViewSharedEngine::resizeEvent(e); 0203 0204 if (KX11Extras::compositingActive()) { 0205 // TODO: reenable window mask when we are without composite? 0206 // clearMask(); 0207 } else { 0208 // setMask(m_view->mask()); 0209 } 0210 } 0211 0212 void KSMShutdownDlg::slotLogout() 0213 { 0214 m_session.requestLogout(SessionManagement::ConfirmationMode::Skip); 0215 accept(); 0216 } 0217 0218 void KSMShutdownDlg::slotReboot() 0219 { 0220 // no boot option selected -> current 0221 m_bootOption.clear(); 0222 m_session.requestReboot(SessionManagement::ConfirmationMode::Skip); 0223 accept(); 0224 } 0225 0226 void KSMShutdownDlg::slotReboot(int opt) 0227 { 0228 if (int(rebootOptions.size()) > opt) 0229 m_bootOption = rebootOptions[opt]; 0230 m_session.requestReboot(SessionManagement::ConfirmationMode::Skip); 0231 accept(); 0232 } 0233 0234 void KSMShutdownDlg::slotLockScreen() 0235 { 0236 m_bootOption.clear(); 0237 m_session.lock(); 0238 reject(); 0239 } 0240 0241 void KSMShutdownDlg::slotHalt() 0242 { 0243 m_bootOption.clear(); 0244 m_session.requestShutdown(SessionManagement::ConfirmationMode::Skip); 0245 accept(); 0246 } 0247 0248 void KSMShutdownDlg::slotSuspend(int spdMethod) 0249 { 0250 m_bootOption.clear(); 0251 switch (spdMethod) { 0252 case 1: // Solid::PowerManagement::StandbyState: 0253 case 2: // Solid::PowerManagement::SuspendState: 0254 m_session.suspend(); 0255 break; 0256 case 4: // Solid::PowerManagement::HibernateState: 0257 m_session.hibernate(); 0258 break; 0259 } 0260 reject(); 0261 } 0262 0263 void KSMShutdownDlg::accept() 0264 { 0265 Q_EMIT accepted(); 0266 } 0267 0268 void KSMShutdownDlg::reject() 0269 { 0270 Q_EMIT rejected(); 0271 }