Skip to content

Commit

Permalink
Make event loop implementation swappable.
Browse files Browse the repository at this point in the history
  • Loading branch information
wengxt committed Nov 17, 2024
1 parent 58131c4 commit d33ca55
Show file tree
Hide file tree
Showing 12 changed files with 735 additions and 234 deletions.
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

0 comments on commit d33ca55

Please sign in to comment.