File indexing completed on 2024-11-10 04:56:31

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "context.h"
0010 #include "events.h"
0011 #include "libinput_logging.h"
0012 
0013 #include "core/session.h"
0014 #include "utils/udev.h"
0015 
0016 #include <fcntl.h>
0017 #include <unistd.h>
0018 
0019 #include <cerrno>
0020 
0021 namespace KWin
0022 {
0023 namespace LibInput
0024 {
0025 
0026 static void libinputLogHandler(libinput *libinput, libinput_log_priority priority, const char *format, va_list args)
0027 {
0028     char buf[1024];
0029     if (std::vsnprintf(buf, 1023, format, args) <= 0) {
0030         return;
0031     }
0032     switch (priority) {
0033     case LIBINPUT_LOG_PRIORITY_DEBUG:
0034         qCDebug(KWIN_LIBINPUT) << "Libinput:" << buf;
0035         break;
0036     case LIBINPUT_LOG_PRIORITY_INFO:
0037         qCInfo(KWIN_LIBINPUT) << "Libinput:" << buf;
0038         break;
0039     case LIBINPUT_LOG_PRIORITY_ERROR:
0040     default:
0041         qCCritical(KWIN_LIBINPUT) << "Libinput:" << buf;
0042         break;
0043     }
0044 }
0045 
0046 Context::Context(Session *session, std::unique_ptr<Udev> &&udev)
0047     : m_session(session)
0048     , m_libinput(libinput_udev_create_context(&Context::s_interface, this, *udev.get()))
0049     , m_suspended(false)
0050     , m_udev(std::move(udev))
0051 {
0052     libinput_log_set_priority(m_libinput, LIBINPUT_LOG_PRIORITY_DEBUG);
0053     libinput_log_set_handler(m_libinput, &libinputLogHandler);
0054 }
0055 
0056 Context::~Context()
0057 {
0058     if (m_libinput) {
0059         libinput_unref(m_libinput);
0060     }
0061 }
0062 
0063 bool Context::initialize()
0064 {
0065     if (!isValid()) {
0066         return false;
0067     }
0068     return libinput_udev_assign_seat(m_libinput, m_session->seat().toUtf8().constData()) == 0;
0069 }
0070 
0071 Session *Context::session() const
0072 {
0073     return m_session;
0074 }
0075 
0076 int Context::fileDescriptor()
0077 {
0078     if (!isValid()) {
0079         return -1;
0080     }
0081     return libinput_get_fd(m_libinput);
0082 }
0083 
0084 void Context::dispatch()
0085 {
0086     libinput_dispatch(m_libinput);
0087 }
0088 
0089 const struct libinput_interface Context::s_interface = {
0090     Context::openRestrictedCallback,
0091     Context::closeRestrictedCallBack,
0092 };
0093 
0094 int Context::openRestrictedCallback(const char *path, int flags, void *user_data)
0095 {
0096     return ((Context *)user_data)->openRestricted(path, flags);
0097 }
0098 
0099 void Context::closeRestrictedCallBack(int fd, void *user_data)
0100 {
0101     ((Context *)user_data)->closeRestricted(fd);
0102 }
0103 
0104 int Context::openRestricted(const char *path, int flags)
0105 {
0106     int fd = m_session->openRestricted(path);
0107     if (fd < 0) {
0108         // failed
0109         return fd;
0110     }
0111     // adjust flags - based on Weston (logind-util.c)
0112     int fl = fcntl(fd, F_GETFL);
0113     auto errorHandling = [fd, this]() {
0114         close(fd);
0115         closeRestricted(fd);
0116     };
0117     if (fl < 0) {
0118         errorHandling();
0119         return -1;
0120     }
0121 
0122     if (flags & O_NONBLOCK) {
0123         fl |= O_NONBLOCK;
0124     }
0125 
0126     if (fcntl(fd, F_SETFL, fl) < 0) {
0127         errorHandling();
0128         return -1;
0129     }
0130 
0131     fl = fcntl(fd, F_GETFD);
0132     if (fl < 0) {
0133         errorHandling();
0134         return -1;
0135     }
0136 
0137     if (!(flags & O_CLOEXEC)) {
0138         fl &= ~FD_CLOEXEC;
0139     }
0140 
0141     if (fcntl(fd, F_SETFD, fl) < 0) {
0142         errorHandling();
0143         return -1;
0144     }
0145     return fd;
0146 }
0147 
0148 void Context::closeRestricted(int fd)
0149 {
0150     m_session->closeRestricted(fd);
0151 }
0152 
0153 std::unique_ptr<Event> Context::event()
0154 {
0155     return Event::create(libinput_get_event(m_libinput));
0156 }
0157 
0158 void Context::suspend()
0159 {
0160     if (m_suspended) {
0161         return;
0162     }
0163     libinput_suspend(m_libinput);
0164     m_suspended = true;
0165 }
0166 
0167 void Context::resume()
0168 {
0169     if (!m_suspended) {
0170         return;
0171     }
0172     libinput_resume(m_libinput);
0173     m_suspended = false;
0174 }
0175 
0176 }
0177 }