File indexing completed on 2022-04-21 12:37:46
0001 /******************************************************************** 0002 KSld - the KDE Screenlocker Daemon 0003 This file is part of the KDE project. 0004 0005 Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org> 0006 0007 This program is free software; you can redistribute it and/or modify 0008 it under the terms of the GNU General Public License as published by 0009 the Free Software Foundation; either version 2 of the License, or 0010 (at your option) any later version. 0011 0012 This program is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 GNU General Public License for more details. 0016 0017 You should have received a copy of the GNU General Public License 0018 along with this program. If not, see <http://www.gnu.org/licenses/>. 0019 *********************************************************************/ 0020 #include "waylandserver.h" 0021 // Qt 0022 #include <QAbstractEventDispatcher> 0023 #include <QCoreApplication> 0024 // ksld 0025 #include "kscreenlocker_logging.h" 0026 #include <config-kscreenlocker.h> 0027 // Wayland 0028 #include <wayland-ksld-server-protocol.h> 0029 // system 0030 #include <fcntl.h> 0031 #include <sys/socket.h> 0032 #include <sys/types.h> 0033 #include <unistd.h> 0034 0035 namespace ScreenLocker 0036 { 0037 0038 WaylandServer::WaylandServer(QObject *parent) 0039 : QObject(parent) 0040 { 0041 m_listener.server = this; 0042 m_listener.listener.notify = [](wl_listener *listener, void *data) { 0043 Q_UNUSED(data) 0044 0045 WaylandServer *server = reinterpret_cast<Listener *>(listener)->server; 0046 server->m_greeter = nullptr; 0047 }; 0048 } 0049 0050 WaylandServer::~WaylandServer() 0051 { 0052 stop(); 0053 } 0054 0055 int WaylandServer::start() 0056 { 0057 stop(); 0058 0059 m_display = wl_display_create(); 0060 0061 wl_event_loop *eventLoop = wl_display_get_event_loop(m_display); 0062 const int fd = wl_event_loop_get_fd(eventLoop); 0063 if (fd == -1) { 0064 stop(); 0065 return -1; 0066 } 0067 0068 m_notifier = new QSocketNotifier(fd, QSocketNotifier::Read); 0069 connect(m_notifier, &QSocketNotifier::activated, this, &WaylandServer::dispatchEvents); 0070 0071 QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); 0072 connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock, this, &WaylandServer::flush); 0073 0074 int socketPair[2]; 0075 if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketPair) == -1) { 0076 // failed creating socket 0077 stop(); 0078 return -1; 0079 } 0080 fcntl(socketPair[0], F_SETFD, FD_CLOEXEC); 0081 0082 m_greeter = wl_client_create(m_display, socketPair[0]); 0083 if (!m_greeter) { 0084 // failed creating the Wayland client 0085 stop(); 0086 close(socketPair[0]); 0087 close(socketPair[1]); 0088 return -1; 0089 } 0090 wl_client_add_destroy_listener(m_greeter, &m_listener.listener); 0091 0092 m_interface = wl_global_create(m_display, &org_kde_ksld_interface, 3, this, bind); 0093 return socketPair[1]; 0094 } 0095 0096 void WaylandServer::stop() 0097 { 0098 QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); 0099 disconnect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock, this, &WaylandServer::flush); 0100 0101 delete m_notifier; 0102 m_notifier = nullptr; 0103 0104 if (m_interface) { 0105 wl_global_destroy(m_interface); 0106 m_interface = nullptr; 0107 } 0108 if (m_greeter) { 0109 wl_client_destroy(m_greeter); 0110 m_greeter = nullptr; 0111 } 0112 if (m_display) { 0113 wl_display_destroy(m_display); 0114 m_display = nullptr; 0115 } 0116 } 0117 0118 void WaylandServer::flush() 0119 { 0120 wl_display_flush_clients(m_display); 0121 } 0122 0123 void WaylandServer::dispatchEvents() 0124 { 0125 if (wl_event_loop_dispatch(wl_display_get_event_loop(m_display), 0) != 0) { 0126 qCWarning(KSCREENLOCKER) << "Error on dispatching WaylandServer event loop"; 0127 } 0128 } 0129 0130 void WaylandServer::bind(wl_client *client, void *data, uint32_t version, uint32_t id) 0131 { 0132 auto server = reinterpret_cast<WaylandServer *>(data); 0133 if (client != server->m_greeter) { 0134 // a proper error would be better 0135 wl_client_post_no_memory(client); 0136 return; 0137 } 0138 0139 wl_resource *resource = wl_resource_create(server->m_greeter, &org_kde_ksld_interface, qMin(version, 1u), id); 0140 if (!resource) { 0141 wl_client_post_no_memory(client); 0142 return; 0143 } 0144 0145 static const struct org_kde_ksld_interface s_interface = { 0146 .x11window = 0147 [](wl_client *client, wl_resource *resource, uint32_t id) { 0148 auto s = reinterpret_cast<WaylandServer *>(wl_resource_get_user_data(resource)); 0149 if (s->m_greeter == client) { 0150 Q_EMIT s->x11WindowAdded(id); 0151 } 0152 }, 0153 }; 0154 0155 wl_resource_set_implementation(resource, &s_interface, server, nullptr); 0156 } 0157 0158 }