File indexing completed on 2024-03-24 17:02:36
0001 /* 0002 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #include "waylandserver.h" 0007 // Qt 0008 #include <QAbstractEventDispatcher> 0009 #include <QCoreApplication> 0010 // ksld 0011 #include "kscreenlocker_logging.h" 0012 #include <config-kscreenlocker.h> 0013 // Wayland 0014 #include <wayland-ksld-server-protocol.h> 0015 // system 0016 #include <fcntl.h> 0017 #include <sys/socket.h> 0018 #include <sys/types.h> 0019 #include <unistd.h> 0020 0021 namespace ScreenLocker 0022 { 0023 0024 WaylandServer::WaylandServer(QObject *parent) 0025 : QObject(parent) 0026 { 0027 m_listener.server = this; 0028 m_listener.listener.notify = [](wl_listener *listener, void *data) { 0029 Q_UNUSED(data) 0030 0031 WaylandServer *server = reinterpret_cast<Listener *>(listener)->server; 0032 server->m_greeter = nullptr; 0033 }; 0034 } 0035 0036 WaylandServer::~WaylandServer() 0037 { 0038 stop(); 0039 } 0040 0041 int WaylandServer::start() 0042 { 0043 stop(); 0044 0045 m_display = wl_display_create(); 0046 0047 wl_event_loop *eventLoop = wl_display_get_event_loop(m_display); 0048 const int fd = wl_event_loop_get_fd(eventLoop); 0049 if (fd == -1) { 0050 stop(); 0051 return -1; 0052 } 0053 0054 m_notifier = new QSocketNotifier(fd, QSocketNotifier::Read); 0055 connect(m_notifier, &QSocketNotifier::activated, this, &WaylandServer::dispatchEvents); 0056 0057 QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); 0058 connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock, this, &WaylandServer::flush); 0059 0060 int socketPair[2]; 0061 if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketPair) == -1) { 0062 // failed creating socket 0063 stop(); 0064 return -1; 0065 } 0066 fcntl(socketPair[0], F_SETFD, FD_CLOEXEC); 0067 0068 m_greeter = wl_client_create(m_display, socketPair[0]); 0069 if (!m_greeter) { 0070 // failed creating the Wayland client 0071 stop(); 0072 close(socketPair[0]); 0073 close(socketPair[1]); 0074 return -1; 0075 } 0076 wl_client_add_destroy_listener(m_greeter, &m_listener.listener); 0077 0078 m_interface = wl_global_create(m_display, &org_kde_ksld_interface, 3, this, bind); 0079 return socketPair[1]; 0080 } 0081 0082 void WaylandServer::stop() 0083 { 0084 QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); 0085 disconnect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock, this, &WaylandServer::flush); 0086 0087 delete m_notifier; 0088 m_notifier = nullptr; 0089 0090 if (m_interface) { 0091 wl_global_destroy(m_interface); 0092 m_interface = nullptr; 0093 } 0094 if (m_greeter) { 0095 wl_client_destroy(m_greeter); 0096 m_greeter = nullptr; 0097 } 0098 if (m_display) { 0099 wl_display_destroy(m_display); 0100 m_display = nullptr; 0101 } 0102 } 0103 0104 void WaylandServer::flush() 0105 { 0106 wl_display_flush_clients(m_display); 0107 } 0108 0109 void WaylandServer::dispatchEvents() 0110 { 0111 if (wl_event_loop_dispatch(wl_display_get_event_loop(m_display), 0) != 0) { 0112 qCWarning(KSCREENLOCKER) << "Error on dispatching WaylandServer event loop"; 0113 } 0114 } 0115 0116 void WaylandServer::bind(wl_client *client, void *data, uint32_t version, uint32_t id) 0117 { 0118 auto server = reinterpret_cast<WaylandServer *>(data); 0119 if (client != server->m_greeter) { 0120 // a proper error would be better 0121 wl_client_post_no_memory(client); 0122 return; 0123 } 0124 0125 wl_resource *resource = wl_resource_create(server->m_greeter, &org_kde_ksld_interface, qMin(version, 1u), id); 0126 if (!resource) { 0127 wl_client_post_no_memory(client); 0128 return; 0129 } 0130 0131 static const struct org_kde_ksld_interface s_interface = { 0132 .x11window = 0133 [](wl_client *client, wl_resource *resource, uint32_t id) { 0134 auto s = reinterpret_cast<WaylandServer *>(wl_resource_get_user_data(resource)); 0135 if (s->m_greeter == client) { 0136 Q_EMIT s->x11WindowAdded(id); 0137 } 0138 }, 0139 }; 0140 0141 wl_resource_set_implementation(resource, &s_interface, server, nullptr); 0142 } 0143 0144 }