Commit ade861d6 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

Refactor session code

At the moment, the session code is far from being extensible. If we
decide to add support for libseatd, it will be a challenging task with
the current design of session management code. The goal of this
refactoring is to fix that.

Another motivation behind this change is to prepare session related code
for upstreaming to kwayland-server where it belongs.
parent aad767f9
......@@ -317,14 +317,6 @@ set_package_properties(QAccessibilityClient PROPERTIES
)
set(HAVE_ACCESSIBILITY ${QAccessibilityClient_FOUND})
if(CMAKE_SYSTEM MATCHES "FreeBSD")
find_package(epoll)
set_package_properties(epoll PROPERTIES DESCRIPTION "I/O event notification facility"
TYPE REQUIRED
PURPOSE "Needed for running kwin_wayland"
)
endif()
include(ECMQMLModules)
ecm_find_qmlmodule(QtQuick 2.3)
ecm_find_qmlmodule(QtQuick.Controls 1.2)
......
......@@ -128,27 +128,21 @@ void WaylandTestApplication::performStartup()
// first load options - done internally by a different thread
createOptions();
createSession();
if (!platform()->initialize()) {
std::exit(1);
}
createColorManager();
waylandServer()->createInternalConnection();
// try creating the Wayland Backend
createInput();
createBackend();
createPlugins();
}
void WaylandTestApplication::createBackend()
{
Platform *platform = kwinApp()->platform();
connect(platform, &Platform::screensQueried, this, &WaylandTestApplication::continueStartupWithScreens);
connect(platform, &Platform::initFailed, this,
[] () {
std::cerr << "FATAL ERROR: backend failed to initialize, exiting now" << std::endl;
::exit(1);
}
);
platform->init();
if (!platform()->enabledOutputs().isEmpty()) {
continueStartupWithScreens();
} else {
connect(platform(), &Platform::screensQueried, this, &WaylandTestApplication::continueStartupWithScreens);
}
}
void WaylandTestApplication::continueStartupWithScreens()
......
......@@ -76,7 +76,6 @@ protected:
void performStartup() override;
private:
void createBackend();
void continueStartupWithScreens();
void continueStartupWithScene();
void finalizeStartup();
......
#.rest:
# FindEpoll
# --------------
#
# Try to find epoll or epoll-shim on this system. This finds:
# - some shim on Unix like systems (FreeBSD), or
# - the kernel's epoll on Linux systems.
#
# This will define the following variables:
#
# ``epoll_FOUND``
# True if epoll is available
# ``epoll_LIBRARIES``
# This has to be passed to target_link_libraries()
# ``epoll_INCLUDE_DIRS``
# This has to be passed to target_include_directories()
#
# On Linux, the libraries and include directories are empty,
# even though epoll_FOUND may be set to TRUE. This is because
# no special includes or libraries are needed. On other systems
# these may be needed to use epoll.
#=============================================================================
# SPDX-FileCopyrightText: 2019 Tobias C. Berner <tcberner@FreeBSD.org>
#
# SPDX-License-Identifier: BSD-2-Clause
#=============================================================================
find_path(epoll_INCLUDE_DIRS sys/epoll.h PATH_SUFFIXES libepoll-shim)
if(epoll_INCLUDE_DIRS)
# On Linux there is no library to link against, on the BSDs there is.
# On the BSD's, epoll is implemented through a library, libepoll-shim.
if( CMAKE_SYSTEM_NAME MATCHES "Linux")
set(epoll_FOUND TRUE)
set(epoll_LIBRARIES "")
set(epoll_INCLUDE_DIRS "")
else()
find_library(epoll_LIBRARIES NAMES epoll-shim)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(epoll
FOUND_VAR
epoll_FOUND
REQUIRED_VARS
epoll_LIBRARIES
epoll_INCLUDE_DIRS
)
mark_as_advanced(epoll_LIBRARIES epoll_INCLUDE_DIRS)
include(FeatureSummary)
set_package_properties(epoll PROPERTIES
URL "https://github.com/FreeBSDDesktop/epoll-shim"
DESCRIPTION "small epoll implementation using kqueue"
)
endif()
else()
set(epoll_FOUND FALSE)
endif()
mark_as_advanced(epoll_LIBRARIES epoll_INCLUDE_DIRS)
......@@ -73,7 +73,6 @@ set(kwin_SRCS
libinput/events.cpp
libinput/libinput_logging.cpp
linux_dmabuf.cpp
logind.cpp
main.cpp
modifier_only_shortcuts.cpp
moving_client_x11_filter.cpp
......@@ -106,6 +105,11 @@ set(kwin_SRCS
scripting/scripting_model.cpp
scripting/scriptingutils.cpp
scripting/workspace_wrapper.cpp
session.cpp
session_consolekit.cpp
session_direct.h
session_logind.cpp
session_noop.cpp
shadow.cpp
sm.cpp
subsurfacemonitor.cpp
......@@ -141,24 +145,6 @@ set(kwin_SRCS
qt5_add_dbus_adaptor(kwin_SRCS scripting/org.kde.kwin.Script.xml scripting/scripting.h KWin::AbstractScript)
if (HAVE_LINUX_VT_H)
set(kwin_SRCS ${kwin_SRCS}
virtual_terminal.cpp
)
set(KWIN_TTY_PREFIX "/dev/tty")
endif()
if(CMAKE_SYSTEM MATCHES "FreeBSD")
# We know it has epoll, so supports VT as well
set(kwin_SRCS ${kwin_SRCS}
virtual_terminal.cpp
)
set(KWIN_TTY_PREFIX "/dev/ttyv")
endif()
if(KWIN_TTY_PREFIX)
set_source_files_properties(virtual_terminal.cpp PROPERTIES COMPILE_DEFINITIONS KWIN_TTY_PREFIX="${KWIN_TTY_PREFIX}")
endif()
kconfig_add_kcfg_files(kwin_SRCS settings.kcfgc)
kconfig_add_kcfg_files(kwin_SRCS rulesettings.kcfgc)
kconfig_add_kcfg_files(kwin_SRCS rulebooksettingsbase.kcfgc)
......@@ -238,6 +224,12 @@ target_link_libraries(kwin
Threads::Threads
)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_sources(kwin PRIVATE session_direct_linux.cpp)
elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
target_sources(kwin PRIVATE session_direct_freebsd.cpp)
endif()
if (KWIN_BUILD_CMS)
target_sources(kwin PRIVATE
colordevice.cpp
......@@ -270,12 +262,6 @@ qt5_generate_dbus_interface(virtualkeyboard_dbus.h org.kde.kwin.VirtualKeyboard.
generate_export_header(kwin EXPORT_FILE_NAME kwin_export.h)
if(CMAKE_SYSTEM MATCHES "FreeBSD")
# epoll is required, includes live under ${LOCALBASE}, separate library
target_include_directories(kwin PUBLIC ${epoll_INCLUDE_DIRS})
target_link_libraries(kwin ${epoll_LIBRARIES})
endif()
add_executable(kwin_x11 main_x11.cpp)
target_link_libraries(kwin_x11 kwin KF5::Crash Qt::X11Extras)
......
......@@ -7,9 +7,9 @@
#include "colormanager.h"
#include "abstract_output.h"
#include "colordevice.h"
#include "logind.h"
#include "main.h"
#include "platform.h"
#include "session.h"
#include "utils.h"
namespace KWin
......@@ -27,17 +27,17 @@ ColorManager::ColorManager(QObject *parent)
: QObject(parent)
, d(new ColorManagerPrivate)
{
const QVector<AbstractOutput *> outputs = kwinApp()->platform()->enabledOutputs();
Platform *platform = kwinApp()->platform();
Session *session = platform->session();
const QVector<AbstractOutput *> outputs = platform->enabledOutputs();
for (AbstractOutput *output : outputs) {
handleOutputEnabled(output);
}
connect(kwinApp()->platform(), &Platform::outputEnabled,
this, &ColorManager::handleOutputEnabled);
connect(kwinApp()->platform(), &Platform::outputDisabled,
this, &ColorManager::handleOutputDisabled);
connect(LogindIntegration::self(), &LogindIntegration::sessionActiveChanged,
this, &ColorManager::handleSessionActiveChanged);
connect(platform, &Platform::outputEnabled, this, &ColorManager::handleOutputEnabled);
connect(platform, &Platform::outputDisabled, this, &ColorManager::handleOutputDisabled);
connect(session, &Session::activeChanged, this, &ColorManager::handleSessionActiveChanged);
}
ColorManager::~ColorManager()
......
......@@ -15,9 +15,9 @@
#include "input_event.h"
#include "input_event_spy.h"
#include "keyboard_input.h"
#include "logind.h"
#include "main.h"
#include "pointer_input.h"
#include "session.h"
#include "tablet_input.h"
#include "touch_hide_cursor_spy.h"
#include "touch_input.h"
......@@ -252,7 +252,7 @@ public:
if (event->type() == QEvent::KeyPress && !event->isAutoRepeat()) {
const xkb_keysym_t keysym = event->nativeVirtualKey();
if (keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12) {
LogindIntegration::self()->switchVirtualTerminal(keysym - XKB_KEY_XF86Switch_VT_1 + 1);
kwinApp()->platform()->session()->switchTo(keysym - XKB_KEY_XF86Switch_VT_1 + 1);
return true;
}
}
......@@ -2012,23 +2012,7 @@ InputRedirection::InputRedirection(QObject *parent)
qRegisterMetaType<KWin::InputRedirection::PointerButtonState>();
qRegisterMetaType<KWin::InputRedirection::PointerAxis>();
if (Application::usesLibinput()) {
if (LogindIntegration::self()->hasSessionControl()) {
setupLibInput();
} else {
LibInput::Connection::createThread();
if (LogindIntegration::self()->isConnected()) {
LogindIntegration::self()->takeControl();
} else {
connect(LogindIntegration::self(), &LogindIntegration::connectedChanged, LogindIntegration::self(), &LogindIntegration::takeControl);
}
connect(LogindIntegration::self(), &LogindIntegration::hasSessionControlChanged, this,
[this] (bool sessionControl) {
if (sessionControl) {
setupLibInput();
}
}
);
}
setupLibInput();
}
connect(kwinApp(), &Application::workspaceCreated, this, &InputRedirection::setupWorkspace);
}
......@@ -2188,13 +2172,15 @@ void InputRedirection::setupWorkspace()
m_touch->init();
m_tablet->init();
}
setupTouchpadShortcuts();
setupInputFilters();
}
void InputRedirection::setupInputFilters()
{
const bool hasGlobalShortcutSupport = !waylandServer() || waylandServer()->hasGlobalShortcutSupport();
if (LogindIntegration::self()->hasSessionControl() && hasGlobalShortcutSupport) {
if ((kwinApp()->platform()->session()->capabilities() & Session::Capability::SwitchTerminal)
&& hasGlobalShortcutSupport) {
installInputEventFilter(new VirtualTerminalFilter);
}
if (waylandServer()) {
......@@ -2381,21 +2367,17 @@ void InputRedirection::setupLibInput()
}
);
}
connect(LogindIntegration::self(), &LogindIntegration::sessionActiveChanged, m_libInput,
[this] (bool active) {
if (!active) {
m_libInput->deactivate();
}
connect(kwinApp()->platform()->session(), &Session::activeChanged, m_libInput, [this](bool active) {
if (!active) {
m_libInput->deactivate();
}
);
});
m_inputConfigWatcher = KConfigWatcher::create(InputConfig::self()->inputConfig());
connect(m_inputConfigWatcher.data(), &KConfigWatcher::configChanged,
this, &InputRedirection::handleInputConfigChanged);
reconfigure();
}
setupTouchpadShortcuts();
}
void InputRedirection::setupTouchpadShortcuts()
......
......@@ -22,7 +22,7 @@
#endif
#include "input_event.h"
#include "logind.h"
#include "session.h"
#include "udev.h"
#include "libinput_logging.h"
......@@ -133,8 +133,9 @@ Connection *Connection::create(QObject *parent)
s_context = nullptr;
return nullptr;
}
if (!s_context->assignSeat(LogindIntegration::self()->seat().toUtf8().constData())) {
qCWarning(KWIN_LIBINPUT) << "Failed to assign seat" << LogindIntegration::self()->seat();
const QString seat = kwinApp()->platform()->session()->seat();
if (!s_context->assignSeat(seat.toUtf8().constData())) {
qCWarning(KWIN_LIBINPUT) << "Failed to assign seat" << seat;
delete s_context;
s_context = nullptr;
return nullptr;
......@@ -194,20 +195,17 @@ void Connection::doSetup()
m_notifier = new QSocketNotifier(m_input->fileDescriptor(), QSocketNotifier::Read, this);
connect(m_notifier, &QSocketNotifier::activated, this, &Connection::handleEvent);
LogindIntegration *logind = LogindIntegration::self();
connect(logind, &LogindIntegration::sessionActiveChanged, this,
[this](bool active) {
if (active) {
if (!m_input->isSuspended()) {
return;
}
m_input->resume();
wasSuspended = true;
} else {
deactivate();
connect(kwinApp()->platform()->session(), &Session::activeChanged, this, [this](bool active) {
if (active) {
if (!m_input->isSuspended()) {
return;
}
m_input->resume();
wasSuspended = true;
} else {
deactivate();
}
);
});
handleEvent();
}
......
......@@ -10,7 +10,9 @@
#include "events.h"
#include "libinput_logging.h"
#include "logind.h"
#include "main.h"
#include "platform.h"
#include "session.h"
#include "udev.h"
#include <fcntl.h>
......@@ -97,9 +99,7 @@ void Context::closeRestrictedCallBack(int fd, void *user_data)
int Context::openRestricted(const char *path, int flags)
{
LogindIntegration *logind = LogindIntegration::self();
Q_ASSERT(logind);
int fd = logind->takeDevice(path);
int fd = kwinApp()->platform()->session()->openRestricted(path);
if (fd < 0) {
// failed
return fd;
......@@ -143,9 +143,7 @@ int Context::openRestricted(const char *path, int flags)
void Context::closeRestricted(int fd)
{
LogindIntegration *logind = LogindIntegration::self();
Q_ASSERT(logind);
logind->releaseDevice(fd);
kwinApp()->platform()->session()->closeRestricted(fd);
}
Event *Context::event()
......
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "logind.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDBusConnectionInterface>
#include <QDBusPendingCallWatcher>
#include <QDBusServiceWatcher>
#include <QDBusUnixFileDescriptor>
#include <QDBusMetaType>
#include <sys/stat.h>
#include <config-kwin.h>
#if HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#ifndef major
#include <sys/types.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include "utils.h"
struct DBusLogindSeat {
QString name;
QDBusObjectPath path;
};
QDBusArgument &operator<<(QDBusArgument &argument, const DBusLogindSeat &seat)
{
argument.beginStructure();
argument << seat.name << seat.path ;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusLogindSeat &seat)
{
argument.beginStructure();
argument >> seat.name >> seat.path;
argument.endStructure();
return argument;
}
Q_DECLARE_METATYPE(DBusLogindSeat)
namespace KWin
{
const static QString s_login1Name = QStringLiteral("logind");
const static QString s_login1Service = QStringLiteral("org.freedesktop.login1");
const static QString s_login1Path = QStringLiteral("/org/freedesktop/login1");
const static QString s_login1ManagerInterface = QStringLiteral("org.freedesktop.login1.Manager");
const static QString s_login1SeatInterface = QStringLiteral("org.freedesktop.login1.Seat");
const static QString s_login1SessionInterface = QStringLiteral("org.freedesktop.login1.Session");
const static QString s_login1ActiveProperty = QStringLiteral("Active");
const static QString s_ck2Name = QStringLiteral("ConsoleKit");
const static QString s_ck2Service = QStringLiteral("org.freedesktop.ConsoleKit");
const static QString s_ck2Path = QStringLiteral("/org/freedesktop/ConsoleKit/Manager");
const static QString s_ck2ManagerInterface = QStringLiteral("org.freedesktop.ConsoleKit.Manager");
const static QString s_ck2SeatInterface = QStringLiteral("org.freedesktop.ConsoleKit.Seat");
const static QString s_ck2SessionInterface = QStringLiteral("org.freedesktop.ConsoleKit.Session");
const static QString s_ck2ActiveProperty = QStringLiteral("active");
const static QString s_dbusPropertiesInterface = QStringLiteral("org.freedesktop.DBus.Properties");
LogindIntegration *LogindIntegration::s_self = nullptr;
LogindIntegration *LogindIntegration::create(QObject *parent)
{
Q_ASSERT(!s_self);
s_self = new LogindIntegration(parent);
return s_self;
}
LogindIntegration::LogindIntegration(const QDBusConnection &connection, QObject *parent)
: QObject(parent)
, m_bus(connection)
, m_connected(false)
, m_sessionControl(false)
, m_sessionActive(false)
{
// check whether the logind service is registered
QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DBus"),
QStringLiteral("/"),
QStringLiteral("org.freedesktop.DBus"),
QStringLiteral("ListNames"));
QDBusPendingReply<QStringList> async = m_bus.asyncCall(message);
QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, this);
connect(callWatcher, &QDBusPendingCallWatcher::finished, this,
[this](QDBusPendingCallWatcher *self) {
QDBusPendingReply<QStringList> reply = *self;
self->deleteLater();
if (!reply.isValid()) {
return;
}
if (reply.value().contains(s_login1Service)) {
setupSessionController(SessionControllerLogind);
} else if (reply.value().contains(s_ck2Service)) {
setupSessionController(SessionControllerConsoleKit);
}
}
);
}
LogindIntegration::LogindIntegration(QObject *parent)
: LogindIntegration(QDBusConnection::systemBus(), parent)
{
}
LogindIntegration::~LogindIntegration()
{
s_self = nullptr;
}
void LogindIntegration::setupSessionController(SessionController controller)
{
if (controller == SessionControllerLogind) {
// We have the logind serivce, set it up and use it
m_sessionControllerName = s_login1Name;
m_sessionControllerService = s_login1Service;
m_sessionControllerPath = s_login1Path;
m_sessionControllerManagerInterface = s_login1ManagerInterface;
m_sessionControllerSeatInterface = s_login1SeatInterface;
m_sessionControllerSessionInterface = s_login1SessionInterface;
m_sessionControllerActiveProperty = s_login1ActiveProperty;
m_logindServiceWatcher = new QDBusServiceWatcher(m_sessionControllerService,
m_bus,
QDBusServiceWatcher::WatchForUnregistration | QDBusServiceWatcher::WatchForRegistration,
this);
connect(m_logindServiceWatcher, &QDBusServiceWatcher::serviceRegistered, this, &LogindIntegration::logindServiceRegistered);
connect(m_logindServiceWatcher, &QDBusServiceWatcher::serviceUnregistered, this,
[this]() {
m_connected = false;
emit connectedChanged();
}
);
logindServiceRegistered();
} else if (controller == SessionControllerConsoleKit) {
// We have the ConsoleKit serivce, set it up and use it
m_sessionControllerName = s_ck2Name;
m_sessionControllerService = s_ck2Service;
m_sessionControllerPath = s_ck2Path;
m_sessionControllerManagerInterface = s_ck2ManagerInterface;
m_sessionControllerSeatInterface = s_ck2SeatInterface;
m_sessionControllerSessionInterface = s_ck2SessionInterface;
m_sessionControllerActiveProperty = s_ck2ActiveProperty;
m_logindServiceWatcher = new QDBusServiceWatcher(m_sessionControllerService,
m_bus,
QDBusServiceWatcher::WatchForUnregistration | QDBusServiceWatcher::WatchForRegistration,
this);
connect(m_logindServiceWatcher, &QDBusServiceWatcher::serviceRegistered, this, &LogindIntegration::logindServiceRegistered);
connect(m_logindServiceWatcher, &QDBusServiceWatcher::serviceUnregistered, this,
[this]() {
m_connected = false;
emit connectedChanged();
}
);
logindServiceRegistered();
}
}
void LogindIntegration::logindServiceRegistered()
{
const QByteArray sessionId = qgetenv("XDG_SESSION_ID");
QString methodName;
QVariantList args;
if (sessionId.isEmpty()) {
methodName = QStringLiteral("GetSessionByPID");
args << (quint32) QCoreApplication::applicationPid();
} else {
methodName = QStringLiteral("GetSession");
args << QString::fromLocal8Bit(sessionId);
}
// get the current session
QDBusMessage message = QDBusMessage::createMethodCall(m_sessionControllerService,
m_sessionControllerPath,
m_sessionControllerManagerInterface,
methodName);
message.setArguments(args);
QDBusPendingReply<QDBusObjectPath> session = m_bus.asyncCall(message);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(session, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this,
[this](QDBusPendingCallWatcher *self) {
QDBusPendingReply<QDBusObjectPath> reply = *self;
self->deleteLater();
if (m_connected) {
return;
}
if (!reply.isValid()) {
qCDebug(KWIN_CORE) << "The session is not registered with " << m_sessionControllerName << " " << reply.error().message();
return;
}
m_sessionPath = reply.value().path();
qCDebug(KWIN_CORE) << "Session path:" << m_sessionPath;
m_connected = true;
connectSessionPropertiesChanged();
// activate the session, in case we are not on it
QDBusMessage message = QDBusMessage::createMethodCall(m_sessionControllerService,
m_sessionPath,
m_sessionControllerSessionInterface,
QStringLiteral("Activate"));
// blocking on purpose
m_bus.call(message);
getSeat();
getSessionActive();
getVirtualTerminal();
emit connectedChanged();
}
);
m_bus.connect(m_sessionControllerService,