Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make event loop implementation swappable. #1183

Merged
merged 1 commit into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 51 additions & 18 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ option(ENABLE_DBUS "Enable DBus" On)
option(ENABLE_DOC "Build doxygen" Off)
option(ENABLE_SERVER "Build a fcitx as server, disable this option if you want to use fcitx as an embedded library." On)
option(ENABLE_KEYBOARD "Enable key event translation with XKB and build keyboard engine" On)
option(USE_SYSTEMD "Use systemd for event loop and dbus, will fallback to libuv/libdbus if not found." On)
option(USE_SYSTEMD "Use systemd for event loop and dbus, will fallback to libuv/libdbus if not found. Only used when EVENT_LOOP_BACKEND is auto." On)
option(ENABLE_XDGAUTOSTART "Enable xdg autostart desktop file installation" On)
option(USE_FLATPAK_ICON "Use flatpak icon name for desktop files" Off)
option(ENABLE_EMOJI "Enable emoji module" On)
option(ENABLE_LIBUUID "Use libuuid for uuid generation" On)
option(BUILD_SPELL_DICT "Build en_dict.fscd for English spell check" On)
set(NO_PREEDIT_APPS "gvim.*,wps.*,wpp.*,et.*" CACHE STRING "Disable preedit for follwing app by default.")
set(EVENT_LOOP_BACKEND "auto" CACHE STRING "Set the underlying event loop implementation, valid values are auto,systemd,libuv,none")

if (ENABLE_EMOJI)
find_package(ZLIB REQUIRED)
Expand All @@ -47,35 +48,67 @@ if ((ENABLE_WAYLAND OR ENABLE_X11) AND NOT ENABLE_KEYBOARD)
message(FATAL_ERROR "X11 and Wayland require ENABLE_KEYBOARD to be set to ON.")
endif ()


#######################################################################
# Find packages
#######################################################################

find_package(PkgConfig REQUIRED)

if (USE_SYSTEMD)
find_package(Systemd)
endif ()
set(CANDIDATE_EVENT_LOOP_BACKENDS)

if (USE_FLATPAK_ICON)
set(FCITX_ICON_NAME "org.fcitx.Fcitx5")
else()
set(FCITX_ICON_NAME "fcitx")
if (EVENT_LOOP_BACKEND STREQUAL "auto")
if (USE_SYSTEMD)
list(APPEND CANDIDATE_EVENT_LOOP_BACKENDS systemd)
endif()

list(APPEND CANDIDATE_EVENT_LOOP_BACKENDS libuv)
elseif (EVENT_LOOP_BACKEND STREQUAL "systemd")
list(APPEND CANDIDATE_EVENT_LOOP_BACKENDS systemd)
elseif (EVENT_LOOP_BACKEND STREQUAL "libuv")
list(APPEND CANDIDATE_EVENT_LOOP_BACKENDS libuv)
elseif (EVENT_LOOP_BACKEND STREQUAL "none")
list(APPEND CANDIDATE_EVENT_LOOP_BACKENDS none)
endif()

if (NOT TARGET Systemd::Systemd)
if (ENABLE_DBUS)
pkg_check_modules(DBus REQUIRED IMPORTED_TARGET "dbus-1")
pkg_get_variable(DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "dbus-1" "system_bus_default_address")
endif()
set(FCITX_EVENT_LOOP_BACKEND "")
foreach(CANDIDATE_EVENT_LOOP_BACKEND IN LISTS CANDIDATE_EVENT_LOOP_BACKENDS)
if (CANDIDATE_EVENT_LOOP_BACKEND STREQUAL systemd)
find_package(Systemd)
if (TARGET Systemd::Systemd)
set(FCITX_EVENT_LOOP_BACKEND "systemd")
break()
endif()
elseif (CANDIDATE_EVENT_LOOP_BACKEND STREQUAL libuv)
if (NOT LIBUV_TARGET)
if (NOT (TARGET PkgConfig::LibUV))
pkg_check_modules(LibUV IMPORTED_TARGET "libuv")
set(LIBUV_TARGET PkgConfig::LibUV)
endif()
endif()

if (NOT LIBUV_TARGET)
if (NOT (TARGET PkgConfig::LibUV))
pkg_check_modules(LibUV REQUIRED IMPORTED_TARGET "libuv")
if (TARGET LIBUV_TARGET)
set(FCITX_EVENT_LOOP_BACKEND "libuv")
break()
endif()
set(LIBUV_TARGET PkgConfig::LibUV)
elseif (CANDIDATE_EVENT_LOOP_BACKEND STREQUAL none)
set(FCITX_EVENT_LOOP_BACKEND "none")
break()
endif()
endforeach()

if (ENABLE_DBUS AND NOT (FCITX_EVENT_LOOP_BACKEND STREQUAL systemd))
pkg_check_modules(DBus REQUIRED IMPORTED_TARGET "dbus-1")
pkg_get_variable(DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "dbus-1" "system_bus_default_address")
endif()

if (FCITX_EVENT_LOOP_BACKEND STREQUAL "")
message(FATAL_ERROR "Failed to find a valid event loop backend.")
endif()

if (USE_FLATPAK_ICON)
set(FCITX_ICON_NAME "org.fcitx.Fcitx5")
else()
set(FCITX_ICON_NAME "fcitx")
endif()

if(${CMAKE_SYSTEM_NAME} MATCHES "BSD|DragonFly")
Expand Down
52 changes: 21 additions & 31 deletions src/lib/fcitx-utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,44 +1,42 @@
set(FCITX_UTILS_SOURCES)
set(FCITX_UTILS_DEPS)

if (ENABLE_DBUS)

set(FCITX_UTILS_SOURCES
${FCITX_UTILS_SOURCES}
list(APPEND FCITX_UTILS_SOURCES
dbus/servicewatcher.cpp
dbus/matchrule.cpp
dbus/variant.cpp
dbus/objectvtable.cpp
)

if (NOT TARGET Systemd::Systemd)
set(FCITX_UTILS_SOURCES
${FCITX_UTILS_SOURCES}
dbus/libdbus/bus.cpp
dbus/libdbus/message.cpp
dbus/libdbus/objectvtable_libdbus.cpp
dbus/libdbus/servicenamecache.cpp)
else()
set(FCITX_UTILS_SOURCES
${FCITX_UTILS_SOURCES}
if (FCITX_EVENT_LOOP_BACKEND STREQUAL "systemd")
list(APPEND FCITX_UTILS_SOURCES
dbus/sdbus/bus.cpp
dbus/sdbus/message.cpp
dbus/sdbus/objectvtablewrapper.c
dbus/sdbus/objectvtable_sdbus.cpp)
else()
list(APPEND FCITX_UTILS_SOURCES
dbus/libdbus/bus.cpp
dbus/libdbus/message.cpp
dbus/libdbus/objectvtable_libdbus.cpp
dbus/libdbus/servicenamecache.cpp)
list(APPEND FCITX_UTILS_DEPS PkgConfig::DBus)
endif()
endif()

if (NOT TARGET Systemd::Systemd)
set(FCITX_UTILS_SOURCES
${FCITX_UTILS_SOURCES}
event_libuv.cpp)
else()
set(FCITX_UTILS_SOURCES
${FCITX_UTILS_SOURCES}
event_sdevent.cpp)
if (FCITX_EVENT_LOOP_BACKEND STREQUAL "libuv")
list(APPEND FCITX_UTILS_SOURCES event_libuv.cpp)
list(APPEND FCITX_UTILS_DEPS "${LIBUV_TARGET}")
elseif (FCITX_EVENT_LOOP_BACKEND STREQUAL "systemd")
list(APPEND FCITX_UTILS_SOURCES event_sdevent.cpp)
list(APPEND FCITX_UTILS_DEPS Systemd::Systemd)
elseif (FCITX_EVENT_LOOP_BACKEND STREQUAL "none")
list(APPEND FCITX_UTILS_SOURCES event_none.cpp)
endif()

set(FCITX_UTILS_SOURCES
${FCITX_UTILS_SOURCES}
list(APPEND FCITX_UTILS_SOURCES
stringutils.cpp
testing.cpp
key.cpp
Expand Down Expand Up @@ -135,15 +133,7 @@ target_link_libraries(Fcitx5Utils PRIVATE DL::DL LibIntl::LibIntl Pthread::Pthre
if(LIBKVM_FOUND)
target_link_libraries(Fcitx5Utils PRIVATE LibKVM::LibKVM)
endif()

if (NOT TARGET Systemd::Systemd)
target_link_libraries(Fcitx5Utils PRIVATE ${LIBUV_TARGET})
if (ENABLE_DBUS)
target_link_libraries(Fcitx5Utils PRIVATE PkgConfig::DBus)
endif()
else()
target_link_libraries(Fcitx5Utils PRIVATE Systemd::Systemd)
endif()
target_link_libraries(Fcitx5Utils PRIVATE ${FCITX_UTILS_DEPS})

configure_file(Fcitx5Utils.pc.in ${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Utils.pc @ONLY)

Expand Down
13 changes: 10 additions & 3 deletions src/lib/fcitx-utils/dbus/sdbus/bus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#include <stdexcept>
#include <string_view>
#include "../../log.h"
#include "bus_p.h"
#include "message_p.h"
Expand Down Expand Up @@ -117,9 +118,15 @@ void Bus::attachEventLoop(EventLoop *loop) {
if (d->eventLoop_) {
return;
}
sd_event *event = static_cast<sd_event *>(loop->nativeHandle());
if (sd_bus_attach_event(d->bus_, event, 0) >= 0) {
d->eventLoop_ = loop;
if (loop->implementation() == std::string_view("sd-event")) {
sd_event *event = static_cast<sd_event *>(loop->nativeHandle());
if (sd_bus_attach_event(d->bus_, event, 0) >= 0) {
d->eventLoop_ = loop;
}
} else {
// TODO: support sd-bus + generic event loop implementation.
throw std::invalid_argument(
"not support sd-bus with non-sdevent implementation.");
}
}

Expand Down
21 changes: 19 additions & 2 deletions src/lib/fcitx-utils/event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <cstring>
#include <ctime>
#include <memory>
#include <stdexcept>
#include <utility>
#include "event_p.h"
#include "eventloopinterface.h"
Expand All @@ -21,12 +22,28 @@ namespace fcitx {
class EventLoopPrivate {
public:
EventLoopPrivate(std::unique_ptr<EventLoopInterface> impl)
: impl_(std::move(impl)) {}
: impl_(std::move(impl)) {
if (!impl_) {
throw std::runtime_error("No available event loop implementation.");
}
}

std::unique_ptr<EventLoopInterface> impl_;

static EventLoopFactory factory_;
};

EventLoop::EventLoop() : EventLoop(createDefaultEventLoop()) {}
EventLoopFactory EventLoopPrivate::factory_ = createDefaultEventLoop;

void EventLoop::setEventLoopFactory(EventLoopFactory factory) {
if (factory) {
EventLoopPrivate::factory_ = std::move(factory);
} else {
EventLoopPrivate::factory_ = createDefaultEventLoop;
}
}

EventLoop::EventLoop() : EventLoop(EventLoopPrivate::factory_()) {}

EventLoop::EventLoop(std::unique_ptr<EventLoopInterface> impl)
: d_ptr(std::make_unique<EventLoopPrivate>(std::move(impl))) {}
Expand Down
20 changes: 20 additions & 0 deletions src/lib/fcitx-utils/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

namespace fcitx {

using EventLoopFactory = std::function<std::unique_ptr<EventLoopInterface>()>;

class EventLoopPrivate;
class FCITXUTILS_EXPORT EventLoop {
public:
Expand All @@ -27,9 +29,18 @@ class FCITXUTILS_EXPORT EventLoop {

/**
* Return the default implementation name.
*
* This will only return the default implementation name.
* Do not rely on this value.
*
* @see EventLoop::implementation
*/
FCITXUTILS_DEPRECATED static const char *impl();

/**
* Return the name of implementation of event loop.
* @since 5.1.12
*/
const char *implementation() const;
void *nativeHandle();

Expand All @@ -45,6 +56,15 @@ class FCITXUTILS_EXPORT EventLoop {
FCITX_NODISCARD std::unique_ptr<EventSource>
addPostEvent(EventCallback callback);

/**
* Set an external event loop implementation.
*
* This is useful if you need to integrate fcitx with another event loop.
*
* @since 5.1.12
*/
static void setEventLoopFactory(EventLoopFactory factory);

private:
const std::unique_ptr<EventLoopPrivate> d_ptr;
FCITX_DECLARE_PRIVATE(EventLoop);
Expand Down
7 changes: 6 additions & 1 deletion src/lib/fcitx-utils/event_libuv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,12 @@ void PostEventCallback(uv_prepare_t *handle) {
source->setEnabled(false);
}
auto callback = source->callback_;
(*callback)(source);
auto ret = (*callback)(source);
if (sourceRef.isValid()) {
if (!ret) {
source->setEnabled(false);
}
}
} catch (const std::exception &e) {
// some abnormal things threw{
FCITX_FATAL() << e.what();
Expand Down
16 changes: 16 additions & 0 deletions src/lib/fcitx-utils/event_none.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

/*
* SPDX-FileCopyrightText: 2015-2015 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#include "event_p.h"

namespace fcitx {

std::unique_ptr<EventLoopInterface> createDefaultEventLoop() { return nullptr; }

const char *defaultEventLoopImplementation() { return "none"; }

} // namespace fcitx
7 changes: 6 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})

add_subdirectory(addon)

add_library(eventlooptests STATIC eventlooptests.cpp)
target_link_libraries(eventlooptests Fcitx5::Utils)

set(FCITX_UTILS_TEST
testflags
teststringutils
Expand All @@ -11,6 +14,7 @@ set(FCITX_UTILS_TEST
testcolor
testi18nstring
testevent
testcustomeventloop
testlist
testfs
testlibrary
Expand All @@ -33,7 +37,8 @@ set(FCITX_UTILS_DBUS_TEST

set(testdbus_LIBS Pthread::Pthread)
set(testeventdispatcher_LIBS Pthread::Pthread)
set(testevent_LIBS Pthread::Pthread)
set(testevent_LIBS Pthread::Pthread eventlooptests)
set(testcustomeventloop_LIBS Pthread::Pthread eventlooptests)

find_program(XVFB_BIN Xvfb)

Expand Down
Loading
Loading