├── CMakeLists.txt ├── LICENSES └── LGPL-2.1-or-later.txt ├── README.md ├── cmake └── FindWaylandProtocols.cmake ├── config.h.in └── src ├── CMakeLists.txt ├── buffer.cpp ├── buffer.h ├── classicui.cpp ├── classicui.h ├── classicui_public.h ├── common.h ├── fcitx-utils ├── endian_p.h └── misc_p.h ├── fcitx-wayland ├── CMakeLists.txt ├── core │ ├── CMakeLists.txt │ ├── display.cpp │ ├── display.h │ ├── outputinfomation.cpp │ ├── outputinformation.h │ ├── wl_buffer.cpp │ ├── wl_buffer.h │ ├── wl_callback.cpp │ ├── wl_callback.h │ ├── wl_compositor.cpp │ ├── wl_compositor.h │ ├── wl_data_device.cpp │ ├── wl_data_device.h │ ├── wl_data_device_manager.cpp │ ├── wl_data_device_manager.h │ ├── wl_data_offer.cpp │ ├── wl_data_offer.h │ ├── wl_data_source.cpp │ ├── wl_data_source.h │ ├── wl_keyboard.cpp │ ├── wl_keyboard.h │ ├── wl_output.cpp │ ├── wl_output.h │ ├── wl_pointer.cpp │ ├── wl_pointer.h │ ├── wl_region.cpp │ ├── wl_region.h │ ├── wl_registry.cpp │ ├── wl_registry.h │ ├── wl_seat.cpp │ ├── wl_seat.h │ ├── wl_shell.cpp │ ├── wl_shell.h │ ├── wl_shell_surface.cpp │ ├── wl_shell_surface.h │ ├── wl_shm.cpp │ ├── wl_shm.h │ ├── wl_shm_pool.cpp │ ├── wl_shm_pool.h │ ├── wl_subcompositor.cpp │ ├── wl_subcompositor.h │ ├── wl_subsurface.cpp │ ├── wl_subsurface.h │ ├── wl_surface.cpp │ ├── wl_surface.h │ ├── wl_touch.cpp │ └── wl_touch.h └── input-method │ ├── CMakeLists.txt │ ├── zwp_input_method_context_v1.cpp │ ├── zwp_input_method_context_v1.h │ ├── zwp_input_method_v1.cpp │ ├── zwp_input_method_v1.h │ ├── zwp_input_panel_surface_v1.cpp │ ├── zwp_input_panel_surface_v1.h │ ├── zwp_input_panel_v1.cpp │ └── zwp_input_panel_v1.h ├── fcitx └── misc_p.h ├── inputwindow.cpp ├── inputwindow.h ├── theme.cpp ├── theme.h ├── themes ├── CMakeLists.txt └── default │ ├── CMakeLists.txt │ ├── arrow.png │ ├── highlight.png │ ├── next.png │ ├── panel.png │ ├── prev.png │ ├── radio.png │ └── theme.conf.in ├── virtualkeyboard.cpp ├── virtualkeyboard.h ├── virtualkeyboardanthy.cpp ├── virtualkeyboardanthy.h ├── virtualkeyboardchewing.cpp ├── virtualkeyboardchewing.h ├── virtualkeyboardhangul.cpp ├── virtualkeyboardhangul.h ├── virtualkeyboardi18n.cpp ├── virtualkeyboardi18n.h ├── virtualkeyboardpinyin.cpp ├── virtualkeyboardpinyin.h ├── virtualkeyboardrussian.cpp ├── virtualkeyboardrussian.h ├── virtualkeyboardui.conf.in.in ├── virtualkeyboardus.cpp ├── virtualkeyboardus.h ├── virtualkeygeneral.cpp ├── virtualkeygeneral.h ├── waylandeglwindow.cpp ├── waylandeglwindow.h ├── waylandinputwindow.cpp ├── waylandinputwindow.h ├── waylandpointer.cpp ├── waylandpointer.h ├── waylandshmwindow.cpp ├── waylandshmwindow.h ├── waylandui.cpp ├── waylandui.h ├── waylandwindow.cpp ├── waylandwindow.h ├── window.cpp ├── window.h ├── xcbinputwindow.cpp ├── xcbinputwindow.h ├── xcbmenu.cpp ├── xcbmenu.h ├── xcbtraywindow.cpp ├── xcbtraywindow.h ├── xcbui.cpp ├── xcbui.h ├── xcbwindow.cpp └── xcbwindow.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | project(fcitx5-virtualkeyboard-ui VERSION 5.0.0) 4 | 5 | find_package(ECM 1.0.0 REQUIRED) 6 | set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) 7 | 8 | include(FeatureSummary) 9 | include(GNUInstallDirs) 10 | include(ECMUninstallTarget) 11 | 12 | set(REQUIRED_FCITX5_VERSION 5.0.14) 13 | find_package(Fcitx5Core "${REQUIRED_FCITX5_VERSION}" REQUIRED) 14 | find_package(Fcitx5Module REQUIRED COMPONENTS NotificationItem) 15 | find_package(Gettext REQUIRED) 16 | find_package(PkgConfig REQUIRED) 17 | 18 | if (NOT (TARGET fmt::fmt OR TARGET fmt::fmt-header-only)) 19 | find_package(fmt REQUIRED) 20 | endif() 21 | 22 | if (TARGET fmt::fmt-header-only) 23 | set(FMT_TARGET fmt::fmt-header-only) 24 | else() 25 | set(FMT_TARGET fmt::fmt) 26 | endif () 27 | 28 | pkg_check_modules(Cairo IMPORTED_TARGET cairo) 29 | pkg_check_modules(Pango IMPORTED_TARGET pango pangocairo) 30 | pkg_check_modules(GdkPixbuf IMPORTED_TARGET gdk-pixbuf-2.0) 31 | pkg_check_modules(GioUnix IMPORTED_TARGET gio-unix-2.0) 32 | 33 | option(ENABLE_X11 "Enable X11 support" On) 34 | option(ENABLE_WAYLAND "Enable wayland support" On) 35 | option(INSTALL_THEME "Install theme files" Off) 36 | 37 | if (ENABLE_X11) 38 | set(REQUIRED_XKBCOMMON_COMPONENTS ${REQUIRED_XKBCOMMON_COMPONENTS} X11) 39 | find_package(XCB REQUIRED COMPONENTS XCB AUX XKB XFIXES ICCCM XINERAMA RANDR EWMH KEYSYMS) 40 | pkg_check_modules(CairoXCB IMPORTED_TARGET cairo-xcb) 41 | find_package(Fcitx5Module REQUIRED COMPONENTS XCB) 42 | endif() 43 | 44 | if (ENABLE_WAYLAND) 45 | find_package(Wayland REQUIRED COMPONENTS Client Egl) 46 | find_package(WaylandScanner REQUIRED) 47 | find_package(WaylandProtocols REQUIRED) 48 | find_package(EGL) 49 | find_package(Fcitx5Module REQUIRED COMPONENTS Wayland) 50 | 51 | endif() 52 | 53 | include("${FCITX_INSTALL_CMAKECONFIG_DIR}/Fcitx5Utils/Fcitx5CompilerSettings.cmake") 54 | add_definitions(-DFCITX_GETTEXT_DOMAIN=\"fcitx5-virtualkeyboard-ui\" -D_GNU_SOURCE) 55 | fcitx5_add_i18n_definition() 56 | 57 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) 58 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 59 | 60 | add_subdirectory(src) 61 | 62 | feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fcitx5-virutalkeyboard-ui 2 | 3 | ## What's this? 4 | 5 | A virtual keyboard UI module for [Fcitx5](https://github.com/fcitx/fcitx5), based on ClassicUI bundled in Fcitx5. 6 | The main target environment of this module is [Weston](https://gitlab.freedesktop.org/wayland/weston/). 7 | On X11, it partially works but not yet perfect, need further work. 8 | 9 | Currently following languages/layouts are supported: 10 | 11 | * English (using keyboard-us) 12 | * Japanese (using fcitx5-anthy) 13 | * Korean (using fcitx5-hangul) 14 | * Rusian (using keyboard-ru) 15 | * Simplified Chinese (using fcitx5-chinese-addons) 16 | * Traditional Chinese (using fcitx5-chewing) 17 | 18 | [![Demo Movie for fcitx5-virtualkeyboard-ui](https://img.youtube.com/vi/f1QBqWy_Ps4/0.jpg)](https://www.youtube.com/watch?v=f1QBqWy_Ps4) 19 | 20 | ## Prerequisites 21 | 22 | Currently some patches are required to Fcitx5: 23 | 24 | * For fcitx5-virtualkeyboard-ui `master` branch: 25 | * [fcitx5 5.0.14+virtual-keyboard-prerequisites](https://github.com/clear-code/fcitx5/tree/5.0.14%2Bvirtual-keyboard-prerequisites) 26 | * For fcitx5-virtualkeyboard-ui `fcitx-5.0.8` branch: 27 | * [fcitx5 5.0.8+virtual-keyboard-prerequisites](https://github.com/clear-code/fcitx5/tree/5.0.8%2Bvirtual-keyboard-prerequisites) 28 | 29 | Optionally Fcitx5's inputmethod addons listed above are also required to support each languages. 30 | 31 | In Yocto environment, you can use [meta-inputmethod](https://gitlab.com/clear-code/meta-inputmethod) to install these prerequisites. 32 | The yocto recipe for fcitx5-virtualkeyboard-ui itself isn's published. If you need it, please contact us. 33 | 34 | ## How to build 35 | 36 | ```console 37 | $ cmake -B build 38 | $ cmake --build build 39 | $ cmake --install build 40 | ``` 41 | 42 | ## Example Configuration 43 | 44 | `~/.config/fcitx5/profile` 45 | ```ini 46 | [Groups/0] 47 | # Group Name 48 | Name=US 49 | # Layout 50 | Default Layout=us 51 | # Default Input Method 52 | DefaultIM=keyboard-us 53 | 54 | [Groups/0/Items/0] 55 | # Name 56 | Name=keyboard-us 57 | # Layout 58 | Layout= 59 | 60 | [Groups/1] 61 | # Group Name 62 | Name=JP 63 | # Layout 64 | Default Layout=us 65 | # Default Input Method 66 | DefaultIM=anthy 67 | 68 | [Groups/1/Items/0] 69 | # Name 70 | Name=keyboard-us 71 | # Layout 72 | Layout= 73 | 74 | [Groups/1/Items/1] 75 | # Name 76 | Name=anthy 77 | # Layout 78 | Layout= 79 | 80 | [Groups/2] 81 | # Group Name 82 | Name=CH 83 | # Layout 84 | Default Layout=us 85 | # Default Input Method 86 | DefaultIM=pinyin 87 | 88 | [Groups/2/Items/0] 89 | # Name 90 | Name=keyboard-us 91 | # Layout 92 | Layout= 93 | 94 | [Groups/2/Items/1] 95 | # Name 96 | Name=pinyin 97 | # Layout 98 | Layout= 99 | 100 | [Groups/3] 101 | # Group Name 102 | Name=TW 103 | # Layout 104 | Default Layout=us 105 | # Default Input Method 106 | DefaultIM=chewing 107 | 108 | [Groups/3/Items/0] 109 | # Name 110 | Name=keyboard-us 111 | # Layout 112 | Layout= 113 | 114 | [Groups/3/Items/1] 115 | # Name 116 | Name=chewing 117 | # Layout 118 | Layout= 119 | 120 | [Groups/4] 121 | # Group Name 122 | Name=KR 123 | # Layout 124 | Default Layout=us 125 | # Default Input Method 126 | DefaultIM=hangul 127 | 128 | [Groups/4/Items/0] 129 | # Name 130 | Name=keyboard-us 131 | # Layout 132 | Layout= 133 | 134 | [Groups/4/Items/1] 135 | # Name 136 | Name=hangul 137 | # Layout 138 | Layout= 139 | 140 | [Groups/5] 141 | # Group Name 142 | Name=RU 143 | # Layout 144 | Default Layout=us 145 | # Default Input Method 146 | DefaultIM=keyboard-ru 147 | 148 | [Groups/5/Items/0] 149 | # Name 150 | Name=keyboard-ru 151 | # Layout 152 | Layout= 153 | 154 | [GroupOrder] 155 | 0=US 156 | 1=JP 157 | 2=CH 158 | 3=TW 159 | 4=KR 160 | 5=RU 161 | ``` 162 | 163 | `~/.config/fcitx5/config` 164 | 165 | * Avoid displaying IM information that causes trouble when switching languages. 166 | 167 | ```ini 168 | ... 169 | [Behavior] 170 | ShowInputMethodInformation=False 171 | ... 172 | ``` 173 | -------------------------------------------------------------------------------- /cmake/FindWaylandProtocols.cmake: -------------------------------------------------------------------------------- 1 | find_package(PkgConfig) 2 | 3 | pkg_check_modules(WaylandProtocols QUIET "wayland-protocols>=${WaylandProtocols_FIND_VERSION}") 4 | 5 | pkg_get_variable(WaylandProtocols_PKGDATADIR wayland-protocols pkgdatadir) 6 | 7 | mark_as_advanced(WaylandProtocols_PKGDATADIR) 8 | 9 | string(REGEX REPLACE "[\r\n]" "" WaylandProtocols_PKGDATADIR "${WaylandProtocols_PKGDATADIR}") 10 | 11 | find_package_handle_standard_args(WaylandProtocols 12 | FOUND_VAR 13 | WaylandProtocols_FOUND 14 | REQUIRED_VARS 15 | WaylandProtocols_PKGDATADIR 16 | VERSION_VAR 17 | WaylandProtocols_VERSION 18 | HANDLE_COMPONENTS 19 | ) 20 | 21 | set(WAYLAND_PROTOCOLS_FOUND ${WaylandProtocols_FOUND}) 22 | set(WAYLAND_PROTOCOLS_PKGDATADIR ${WaylandProtocols_PKGDATADIR}) 23 | set(WAYLAND_PROTOCOLS_VERSION ${WaylandProtocols_VERSION}) 24 | 25 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_VIRTUALKEYBOARD_UI_CONFIG_H_IN_ 8 | #define _FCITX5_VIRTUALKEYBOARD_UI_CONFIG_H_IN_ 9 | 10 | #cmakedefine CAIRO_EGL_FOUND 11 | #cmakedefine ENABLE_X11 12 | #cmakedefine WAYLAND_FOUND 13 | 14 | #ifndef _GNU_SOURCE 15 | #define _GNU_SOURCE 16 | #endif 17 | 18 | #endif // _FCITX5_VIRTUALKEYBOARD_UI_CONFIG_H_IN_ 19 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (INSTALL_THEME) 2 | add_subdirectory(themes) 3 | endif() 4 | 5 | set(VIRTUALKEYBOARDUI_WAYLAND_SRCS) 6 | set(VIRTUALKEYBOARDUI_WAYLAND_LIBS) 7 | if (WAYLAND_FOUND) 8 | set(VIRTUALKEYBOARDUI_WAYLAND_SRCS ${VIRTUALKEYBOARDUI_WAYLAND_SRCS} 9 | waylandui.cpp waylandwindow.cpp waylandeglwindow.cpp waylandshmwindow.cpp 10 | waylandpointer.cpp buffer.cpp waylandinputwindow.cpp) 11 | set(VIRTUALKEYBOARDUI_WAYLAND_LIBS ${VIRTUALKEYBOARDUI_WAYLAND_LIBS} 12 | Fcitx5::Module::Wayland Wayland::Client Fcitx5::Wayland::Core 13 | Fcitx5::Wayland::InputMethod) 14 | else() 15 | endif() 16 | 17 | if (ENABLE_X11) 18 | set(VIRTUALKEYBOARDUI_WAYLAND_SRCS ${VIRTUALKEYBOARDUI_WAYLAND_SRCS} 19 | xcbui.cpp xcbwindow.cpp xcbtraywindow.cpp xcbinputwindow.cpp xcbmenu.cpp) 20 | set(VIRTUALKEYBOARDUI_WAYLAND_LIBS ${VIRTUALKEYBOARDUI_WAYLAND_LIBS} PkgConfig::CairoXCB Fcitx5::Module::XCB 21 | XCB::AUX XCB::ICCCM XCB::XINERAMA XCB::RANDR XCB::EWMH) 22 | endif() 23 | 24 | add_library(virtualkeyboardui MODULE 25 | classicui.cpp window.cpp theme.cpp inputwindow.cpp virtualkeyboard.cpp virtualkeygeneral.cpp 26 | virtualkeyboardi18n.cpp virtualkeyboardanthy.cpp virtualkeyboardpinyin.cpp virtualkeyboardrussian.cpp 27 | virtualkeyboardhangul.cpp virtualkeyboardchewing.cpp virtualkeyboardus.cpp ${VIRTUALKEYBOARDUI_WAYLAND_SRCS} 28 | ) 29 | 30 | if (CAIRO_EGL_FOUND) 31 | set(CAIRO_EGL_LIBRARY PkgConfig::CairoEGL Wayland::Egl EGL::EGL) 32 | else() 33 | set(CAIRO_EGL_LIBRARY) 34 | endif() 35 | 36 | target_link_libraries(virtualkeyboardui 37 | Fcitx5::Core 38 | PkgConfig::Cairo PkgConfig::Pango 39 | PkgConfig::GdkPixbuf PkgConfig::GioUnix 40 | Fcitx5::Module::NotificationItem 41 | ${CAIRO_EGL_LIBRARY} 42 | ${VIRTUALKEYBOARDUI_WAYLAND_LIBS} 43 | ${FMT_TARGET}) 44 | install(TARGETS virtualkeyboardui DESTINATION "${FCITX_INSTALL_ADDONDIR}") 45 | configure_file(virtualkeyboardui.conf.in.in virtualkeyboardui.conf.in @ONLY) 46 | fcitx5_translate_desktop_file(${CMAKE_CURRENT_BINARY_DIR}/virtualkeyboardui.conf.in virtualkeyboardui.conf) 47 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/virtualkeyboardui.conf" DESTINATION "${FCITX_INSTALL_PKGDATADIR}/addon") 48 | 49 | add_subdirectory(fcitx-wayland) 50 | -------------------------------------------------------------------------------- /src/buffer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "buffer.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "fcitx-utils/stringutils.h" 20 | #include "theme.h" 21 | #include "wl_buffer.h" 22 | #include "wl_callback.h" 23 | #include "wl_shm.h" 24 | #include "wl_shm_pool.h" 25 | #include "wl_surface.h" 26 | 27 | namespace fcitx::wayland { 28 | 29 | #define RETRY_ON_EINTR(...) \ 30 | do { \ 31 | __VA_ARGS__; \ 32 | } while (ret < 0 && errno == EINTR) 33 | 34 | UnixFD openShm(void) { 35 | int ret; 36 | // We support multiple different methods, memfd / shm_open on BSD / 37 | // O_TMPFILE. While linux has shm_open, it doesn't have SHM_ANON extension 38 | // like bsd. Since memfd is introduced in 3.17, which is already quite old, 39 | // don't bother to add another implementation for Linux, since we need to 40 | // fallback to file as a final resolution. 41 | #if defined(__NR_memfd_create) 42 | do { 43 | static bool hasMemfdCreate = true; 44 | if (!hasMemfdCreate) { 45 | break; 46 | } 47 | int options = MFD_CLOEXEC; 48 | #if defined(MFD_ALLOW_SEALING) 49 | options |= MFD_ALLOW_SEALING; 50 | #endif 51 | RETRY_ON_EINTR( 52 | ret = syscall(__NR_memfd_create, "fcitx-wayland-shm", options)); 53 | 54 | if (ret < 0 && errno == ENOSYS) { 55 | hasMemfdCreate = false; 56 | break; 57 | } 58 | #if defined(F_ADD_SEALS) && defined(F_SEAL_SHRINK) 59 | if (ret >= 0) { 60 | fcntl(ret, F_ADD_SEALS, F_SEAL_SHRINK); 61 | return UnixFD::own(ret); 62 | } 63 | #endif 64 | } while (0); 65 | #endif 66 | 67 | // Try shm_open(SHM_ANON) on BSD. 68 | #if defined(__FreeBSD__) 69 | RETRY_ON_EINTR( 70 | ret = shm_open(SHM_ANON, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600)); 71 | if (ret >= 0) { 72 | return UnixFD::own(ret); 73 | } 74 | #endif 75 | 76 | const char *path = getenv("XDG_RUNTIME_DIR"); 77 | if (!path) { 78 | throw std::runtime_error("XDG_RUNTIME_DIR is not set"); 79 | } 80 | 81 | // Prefer O_TMPFILE over mkstemp. 82 | // The value check is to ensure it has the right value. 83 | // It is said that some old glibc may have problem. 84 | #if defined(O_TMPFILE) && (O_TMPFILE & O_DIRECTORY) == O_DIRECTORY 85 | do { 86 | std::string pathStr = fs::cleanPath(path); 87 | RETRY_ON_EINTR(ret = 88 | open(pathStr.data(), 89 | O_TMPFILE | O_CLOEXEC | O_EXCL | O_RDWR, 0600)); 90 | if (errno == EOPNOTSUPP || errno == EISDIR) { 91 | break; 92 | } 93 | if (ret >= 0) { 94 | return UnixFD::own(ret); 95 | } 96 | return {}; 97 | } while (0); 98 | #endif 99 | 100 | auto filename = stringutils::joinPath(path, "fcitx-wayland-shm-XXXXXX"); 101 | std::vector v(filename.begin(), filename.end()); 102 | v.push_back('\0'); 103 | RETRY_ON_EINTR(ret = mkstemp(v.data())); 104 | 105 | if (ret >= 0) { 106 | unlink(v.data()); 107 | if (int flags = fcntl(ret, F_GETFD); flags != -1) { 108 | fcntl(ret, F_SETFD, flags | FD_CLOEXEC); 109 | } 110 | return UnixFD::own(ret); 111 | } 112 | 113 | return {}; 114 | } 115 | 116 | Buffer::Buffer(WlShm *shm, uint32_t width, uint32_t height, 117 | wl_shm_format format) 118 | : width_(width), height_(height) { 119 | uint32_t stride = width * 4; 120 | uint32_t alloc = stride * height; 121 | UnixFD fd = openShm(); 122 | if (!fd.isValid()) { 123 | return; 124 | } 125 | 126 | if (posix_fallocate(fd.fd(), 0, alloc) != 0) { 127 | return; 128 | } 129 | uint8_t *data = (uint8_t *)mmap(nullptr, alloc, PROT_READ | PROT_WRITE, 130 | MAP_SHARED, fd.fd(), 0); 131 | 132 | if (data == static_cast(MAP_FAILED)) { 133 | return; 134 | } 135 | 136 | data_ = data; 137 | dataSize_ = alloc; 138 | 139 | pool_.reset(shm->createPool(fd.fd(), alloc)); 140 | buffer_.reset(pool_->createBuffer(0, width, height, stride, format)); 141 | buffer_->release().connect([this]() { busy_ = false; }); 142 | 143 | surface_.reset(cairo_image_surface_create_for_data( 144 | data, CAIRO_FORMAT_ARGB32, width, height, stride)); 145 | } 146 | 147 | Buffer::~Buffer() { 148 | callback_.reset(); 149 | surface_.reset(); 150 | buffer_.reset(); 151 | pool_.reset(); 152 | if (data_) { 153 | munmap(data_, dataSize_); 154 | } 155 | } 156 | 157 | void Buffer::attachToSurface(WlSurface *surface, int scale) { 158 | if (busy_) { 159 | return; 160 | } 161 | busy_ = true; 162 | callback_.reset(surface->frame()); 163 | callback_->done().connect([this](uint32_t) { 164 | // CLASSICUI_DEBUG() << "Shm window rendered. " << this; 165 | // Need to ensure buffer won't be deleted. 166 | busy_ = false; 167 | rendered_(); 168 | callback_.reset(); 169 | }); 170 | 171 | surface->attach(buffer(), 0, 0); 172 | surface->setBufferScale(scale); 173 | surface->damage(0, 0, width_, height_); 174 | surface->commit(); 175 | } 176 | 177 | } // namespace fcitx::wayland 178 | -------------------------------------------------------------------------------- /src/buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_WAYLAND_CORE_BUFFER_H_ 8 | #define _FCITX_WAYLAND_CORE_BUFFER_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "fcitx-utils/signals.h" 14 | 15 | namespace fcitx { 16 | namespace wayland { 17 | 18 | class WlShm; 19 | class WlShmPool; 20 | class WlBuffer; 21 | class WlCallback; 22 | class WlSurface; 23 | 24 | class Buffer { 25 | public: 26 | Buffer(WlShm *shm, uint32_t width, uint32_t height, wl_shm_format format); 27 | ~Buffer(); 28 | 29 | bool busy() const { return busy_; } 30 | uint32_t width() const { return width_; } 31 | uint32_t height() const { return height_; } 32 | cairo_surface_t *cairoSurface() const { return surface_.get(); } 33 | WlBuffer *buffer() const { return buffer_.get(); } 34 | 35 | void attachToSurface(WlSurface *surface, int scale); 36 | 37 | auto &rendered() { return rendered_; } 38 | 39 | private: 40 | uint8_t *data_ = nullptr; 41 | size_t dataSize_ = 0; 42 | Signal rendered_; 43 | std::unique_ptr pool_; 44 | std::unique_ptr buffer_; 45 | std::unique_ptr callback_; 46 | UniqueCPtr surface_; 47 | bool busy_ = false; 48 | uint32_t width_, height_; 49 | }; 50 | } // namespace wayland 51 | } // namespace fcitx 52 | 53 | #endif // _FCITX_WAYLAND_CORE_BUFFER_H_ 54 | -------------------------------------------------------------------------------- /src/classicui_public.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021~2021 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_UI_CLASSIC_CLASSICUI_PUBLIC_H_ 8 | #define _FCITX5_UI_CLASSIC_CLASSICUI_PUBLIC_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | FCITX_ADDON_DECLARE_FUNCTION( 16 | ClassicUI, labelIcon, 17 | std::vector(const std::string &label, unsigned int size)); 18 | FCITX_ADDON_DECLARE_FUNCTION(ClassicUI, preferTextIcon, bool()); 19 | FCITX_ADDON_DECLARE_FUNCTION(ClassicUI, showLayoutNameInIcon, bool()); 20 | 21 | #endif // _FCITX5_UI_CLASSIC_CLASSICUI_PUBLIC_H_ 22 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_UI_CLASSIC_COMMON_H_ 8 | #define _FCITX5_UI_CLASSIC_COMMON_H_ 9 | 10 | #include 11 | #include 12 | #include "fcitx-utils/log.h" 13 | 14 | namespace fcitx { 15 | namespace classicui { 16 | 17 | template 18 | using GObjectUniquePtr = UniqueCPtr; 19 | 20 | FCITX_DECLARE_LOG_CATEGORY(classicui_logcategory); 21 | #define CLASSICUI_DEBUG() \ 22 | FCITX_LOGC(::fcitx::classicui::classicui_logcategory, Debug) 23 | 24 | } // namespace classicui 25 | } // namespace fcitx 26 | 27 | #endif // _FCITX5_UI_CLASSIC_COMMON_H_ 28 | -------------------------------------------------------------------------------- /src/fcitx-utils/endian_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UTILS_ENDIAN_P_H_ 8 | #define _FCITX_UTILS_ENDIAN_P_H_ 9 | 10 | #if defined(__linux__) || defined(__GLIBC__) 11 | #include 12 | #elif defined(__APPLE__) 13 | 14 | #include 15 | 16 | #define htobe16(x) OSSwapHostToBigInt16(x) 17 | #define htole16(x) OSSwapHostToLittleInt16(x) 18 | #define be16toh(x) OSSwapBigToHostInt16(x) 19 | #define le16toh(x) OSSwapLittleToHostInt16(x) 20 | 21 | #define htobe32(x) OSSwapHostToBigInt32(x) 22 | #define htole32(x) OSSwapHostToLittleInt32(x) 23 | #define be32toh(x) OSSwapBigToHostInt32(x) 24 | #define le32toh(x) OSSwapLittleToHostInt32(x) 25 | 26 | #define htobe64(x) OSSwapHostToBigInt64(x) 27 | #define htole64(x) OSSwapHostToLittleInt64(x) 28 | #define be64toh(x) OSSwapBigToHostInt64(x) 29 | #define le64toh(x) OSSwapLittleToHostInt64(x) 30 | 31 | #else 32 | #include 33 | #endif 34 | 35 | enum { BYTE_ORDER_MSB_FIRST = 1, BYTE_ORDER_LSB_FIRST = 0 }; 36 | inline uint8_t hostByteOrder() { 37 | const uint16_t endian = 1; 38 | uint8_t byteOrder = 0; 39 | if (*reinterpret_cast(&endian)) { 40 | byteOrder = BYTE_ORDER_LSB_FIRST; 41 | } else { 42 | byteOrder = BYTE_ORDER_MSB_FIRST; 43 | } 44 | return byteOrder; 45 | } 46 | 47 | inline bool isLittleEndian() { return hostByteOrder() == BYTE_ORDER_LSB_FIRST; } 48 | 49 | #endif // _FCITX_UTILS_ENDIAN_P_H_ 50 | -------------------------------------------------------------------------------- /src/fcitx-utils/misc_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016-2016 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_MISC_P_H_ 8 | #define _FCITX_MISC_P_H_ 9 | 10 | #include 11 | 12 | namespace fcitx { 13 | 14 | template 15 | decltype(&std::declval().begin()->second) findValue(M &&m, K &&key) { 16 | auto iter = m.find(key); 17 | if (iter != m.end()) { 18 | return &iter->second; 19 | } 20 | return nullptr; 21 | } 22 | 23 | } 24 | 25 | #endif // _FCITX_MISC_P_ 26 | -------------------------------------------------------------------------------- /src/fcitx-wayland/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(core) 2 | add_subdirectory(input-method) 3 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(FCITX_WAYLAND_CORE_SOURCES 2 | display.cpp 3 | outputinfomation.cpp 4 | wl_buffer.cpp 5 | wl_callback.cpp 6 | wl_compositor.cpp 7 | wl_data_device.cpp 8 | wl_data_device_manager.cpp 9 | wl_data_offer.cpp 10 | wl_data_source.cpp 11 | wl_keyboard.cpp 12 | wl_output.cpp 13 | wl_pointer.cpp 14 | wl_region.cpp 15 | wl_registry.cpp 16 | wl_seat.cpp 17 | wl_shell.cpp 18 | wl_shell_surface.cpp 19 | wl_shm.cpp 20 | wl_shm_pool.cpp 21 | wl_subcompositor.cpp 22 | wl_subsurface.cpp 23 | wl_surface.cpp 24 | wl_touch.cpp 25 | ) 26 | 27 | add_library(Fcitx5WaylandCore STATIC ${FCITX_WAYLAND_CORE_SOURCES}) 28 | set_target_properties(Fcitx5WaylandCore PROPERTIES 29 | COMPILE_FLAGS "-fPIC" 30 | LINK_FLAGS "-Wl,--no-undefined" 31 | ) 32 | target_include_directories(Fcitx5WaylandCore PUBLIC 33 | "$") 34 | target_link_libraries(Fcitx5WaylandCore Wayland::Client Fcitx5::Utils) 35 | 36 | add_library(Fcitx5::Wayland::Core ALIAS Fcitx5WaylandCore) 37 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/display.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016-2016 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | 8 | #include "display.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "wl_callback.h" 15 | #include "wl_output.h" 16 | #include "wl_registry.h" 17 | 18 | namespace fcitx::wayland { 19 | 20 | void Display::createGlobalHelper( 21 | GlobalsFactoryBase *factory, 22 | std::pair>> &globalsPair) { 24 | std::get>(globalsPair.second) = factory->create( 25 | *registry(), globalsPair.first, std::get<2>(globalsPair.second)); 26 | 27 | globalCreatedSignal_(std::get(globalsPair.second), 28 | std::get>(globalsPair.second)); 29 | sync(); 30 | flush(); 31 | } 32 | 33 | Display::Display(wl_display *display) : display_(display) { 34 | wl_display_set_user_data(display, this); 35 | auto *reg = registry(); 36 | reg->global().connect( 37 | [this](uint32_t name, const char *interface, uint32_t version) { 38 | auto result = globals_.emplace(std::make_pair( 39 | name, std::make_tuple(interface, name, version, nullptr))); 40 | auto iter = requestedGlobals_.find(interface); 41 | if (iter != requestedGlobals_.end()) { 42 | createGlobalHelper(iter->second.get(), *result.first); 43 | } 44 | }); 45 | reg->globalRemove().connect([this](uint32_t name) { 46 | auto iter = globals_.find(name); 47 | if (iter != globals_.end()) { 48 | globalRemovedSignal_(std::get(iter->second), 49 | std::get>(iter->second)); 50 | const auto &interface = std::get(iter->second); 51 | auto localGlobalIter = requestedGlobals_.find(interface); 52 | if (localGlobalIter != requestedGlobals_.end()) { 53 | localGlobalIter->second->erase(name); 54 | } 55 | globals_.erase(iter); 56 | } 57 | }); 58 | 59 | requestGlobals(); 60 | globalCreatedSignal_.connect([this](const std::string &interface, 61 | const std::shared_ptr &data) { 62 | if (interface != wayland::WlOutput::interface) { 63 | return; 64 | } 65 | auto *output = static_cast(data.get()); 66 | addOutput(output); 67 | }); 68 | globalRemovedSignal_.connect([this](const std::string &interface, 69 | const std::shared_ptr &data) { 70 | if (interface != wayland::WlOutput::interface) { 71 | return; 72 | } 73 | auto *output = static_cast(data.get()); 74 | removeOutput(output); 75 | }); 76 | 77 | roundtrip(); 78 | flush(); 79 | } 80 | 81 | Display::~Display() {} 82 | 83 | void Display::roundtrip() { wl_display_roundtrip(*this); } 84 | 85 | void Display::sync() { 86 | callbacks_.emplace_back( 87 | std::make_unique(wl_display_sync(*this))); 88 | callbacks_.back()->done().connect( 89 | [this, iter = std::prev(callbacks_.end())](uint32_t) { 90 | callbacks_.erase(iter); 91 | }); 92 | } 93 | 94 | void Display::flush() { wl_display_flush(*this); } 95 | 96 | void Display::run() { 97 | pollfd pfd; 98 | 99 | pfd.fd = fd(); 100 | pfd.events = POLLIN | POLLERR | POLLHUP; 101 | 102 | while (1) { 103 | wl_display_dispatch_pending(*this); 104 | auto ret = wl_display_flush(*this); 105 | if (ret < 0 && errno != EAGAIN) { 106 | break; 107 | } 108 | 109 | auto count = poll(&pfd, 1, -1); 110 | if (count < 0 && errno != EINTR) { 111 | break; 112 | } 113 | 114 | if (count == 1) { 115 | auto event = pfd.revents; 116 | // We can have cases where POLLIN and POLLHUP are both set for 117 | // example. Don't break if both flags are set. 118 | if ((event & POLLERR || event & POLLHUP) && !(event & POLLIN)) { 119 | break; 120 | } 121 | 122 | if (event & POLLIN) { 123 | ret = wl_display_dispatch(*this); 124 | if (ret == -1) { 125 | break; 126 | } 127 | } 128 | } 129 | } 130 | } 131 | 132 | WlRegistry *Display::registry() { 133 | if (!registry_) { 134 | registry_ = 135 | std::make_unique(wl_display_get_registry(*this)); 136 | } 137 | 138 | return registry_.get(); 139 | } 140 | 141 | const OutputInfomation * 142 | Display::outputInformation(wayland::WlOutput *output) const { 143 | auto iter = outputInfo_.find(output); 144 | if (iter == outputInfo_.end()) { 145 | return nullptr; 146 | } 147 | return &iter->second; 148 | } 149 | 150 | void Display::addOutput(wayland::WlOutput *output) { 151 | outputInfo_.emplace(std::piecewise_construct, std::forward_as_tuple(output), 152 | std::forward_as_tuple(output)); 153 | } 154 | 155 | void Display::removeOutput(wayland::WlOutput *output) { 156 | outputInfo_.erase(output); 157 | } 158 | } // namespace fcitx::wayland 159 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/display.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_WAYLAND_CORE_DISPLAY_H_ 8 | #define _FCITX_WAYLAND_CORE_DISPLAY_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "fcitx-utils/signals.h" 19 | #include "outputinformation.h" 20 | #include "wl_registry.h" 21 | 22 | namespace fcitx { 23 | namespace wayland { 24 | 25 | class WlOutput; 26 | class WlCallback; 27 | 28 | class GlobalsFactoryBase { 29 | public: 30 | virtual ~GlobalsFactoryBase() {} 31 | virtual std::shared_ptr create(WlRegistry &, uint32_t name, 32 | uint32_t version) = 0; 33 | void erase(uint32_t name) { globals_.erase(name); } 34 | 35 | const std::set &globals() { return globals_; } 36 | 37 | protected: 38 | std::set globals_; 39 | }; 40 | 41 | template 42 | class GlobalsFactory : public GlobalsFactoryBase { 43 | public: 44 | virtual std::shared_ptr create(WlRegistry ®istry, uint32_t name, 45 | uint32_t version) { 46 | std::shared_ptr p; 47 | p.reset(registry.bind(name, std::min(version, T::version))); 48 | globals_.insert(name); 49 | return p; 50 | } 51 | }; 52 | 53 | class Display { 54 | public: 55 | Display(wl_display *display); 56 | ~Display(); 57 | 58 | int fd() const { return wl_display_get_fd(display_.get()); } 59 | 60 | operator wl_display *() { return display_.get(); } 61 | 62 | void roundtrip(); 63 | void sync(); 64 | void flush(); 65 | void run(); 66 | 67 | WlRegistry *registry(); 68 | 69 | WlOutput *output() const { 70 | // TODO: should be selectable 71 | return outputInfo_.begin()->first; 72 | }; 73 | 74 | const OutputInfomation *outputInformation(WlOutput *output) const; 75 | 76 | template 77 | std::vector> getGlobals() { 78 | auto iter = requestedGlobals_.find(T::interface); 79 | if (iter == requestedGlobals_.end()) { 80 | return {}; 81 | } 82 | auto &items = iter->second->globals(); 83 | std::vector> results; 84 | for (uint32_t item : items) { 85 | auto iter = globals_.find(item); 86 | results.push_back(std::static_pointer_cast( 87 | std::get>(iter->second))); 88 | } 89 | 90 | return results; 91 | } 92 | 93 | template 94 | std::shared_ptr getGlobal() { 95 | auto globals = getGlobals(); 96 | if (!globals.empty()) { 97 | return globals[0]; 98 | } 99 | return {}; 100 | } 101 | 102 | template 103 | std::shared_ptr getGlobal(uint32_t name) { 104 | auto iter = globals_.find(name); 105 | if (iter != globals_.end() && 106 | std::get(iter->second) == T::interface) { 107 | return std::static_pointer_cast( 108 | std::get>(iter->second)); 109 | } 110 | return {}; 111 | } 112 | 113 | template 114 | void requestGlobals() { 115 | auto result = requestedGlobals_.emplace(std::make_pair( 116 | T::interface, std::make_unique>())); 117 | if (result.second) { 118 | auto iter = result.first; 119 | for (auto &p : globals_) { 120 | if (std::get(p.second) == T::interface) { 121 | createGlobalHelper(iter->second.get(), p); 122 | } 123 | } 124 | } 125 | } 126 | 127 | auto &globalCreated() { return globalCreatedSignal_; } 128 | auto &globalRemoved() { return globalRemovedSignal_; } 129 | 130 | private: 131 | void createGlobalHelper( 132 | GlobalsFactoryBase *factory, 133 | std::pair>> 135 | &globalsPair); 136 | 137 | void addOutput(wayland::WlOutput *output); 138 | void removeOutput(wayland::WlOutput *output); 139 | 140 | fcitx::Signal)> 141 | globalCreatedSignal_; 142 | fcitx::Signal)> 143 | globalRemovedSignal_; 144 | std::unordered_map> 145 | requestedGlobals_; 146 | UniqueCPtr display_; 147 | std::unique_ptr registry_; 148 | std::unordered_map>> 150 | globals_; 151 | std::list conns_; 152 | std::list> callbacks_; 153 | std::unordered_map outputInfo_; 154 | }; 155 | } // namespace wayland 156 | } // namespace fcitx 157 | 158 | #endif // _FCITX_WAYLAND_CORE_DISPLAY_H_ 159 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/outputinfomation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | 8 | #include "outputinformation.h" 9 | 10 | namespace fcitx::wayland { 11 | 12 | class OutputInfomationData { 13 | public: 14 | int32_t x_, y_; 15 | int32_t width_, height_; 16 | int32_t refreshRate_; 17 | int32_t physicalWidth_; 18 | int32_t physicalHeight_; 19 | wl_output_subpixel subpixel_; 20 | std::string make_; 21 | std::string model_; 22 | wl_output_transform transform_; 23 | int32_t scale_; 24 | }; 25 | 26 | class OutputInfomationPrivate { 27 | public: 28 | OutputInfomationData current_, next_; 29 | ScopedConnection geometryConnection_, modeConnection_, scaleConnection_, 30 | doneConnection_; 31 | }; 32 | 33 | OutputInfomation::OutputInfomation(WlOutput *output) 34 | : d_ptr(std::make_unique()) { 35 | FCITX_D(); 36 | d->geometryConnection_ = output->geometry().connect( 37 | [this](int32_t x, int32_t y, int32_t physicalWidth, 38 | int32_t physicalHeight, int32_t subpixel, const char *make, 39 | const char *model, int32_t transform) { 40 | FCITX_D(); 41 | d->next_.x_ = x; 42 | d->next_.y_ = y; 43 | d->next_.physicalWidth_ = physicalWidth; 44 | d->next_.physicalHeight_ = physicalHeight; 45 | d->next_.subpixel_ = static_cast(subpixel); 46 | d->next_.make_ = make; 47 | d->next_.model_ = model; 48 | d->next_.transform_ = static_cast(transform); 49 | }); 50 | d->modeConnection_ = output->mode().connect( 51 | [this](uint32_t flags, int32_t width, int32_t height, int32_t refresh) { 52 | if (!(flags & WL_OUTPUT_MODE_CURRENT)) { 53 | return; 54 | } 55 | 56 | FCITX_D(); 57 | d->next_.width_ = width; 58 | d->next_.height_ = height; 59 | d->next_.refreshRate_ = refresh; 60 | }); 61 | d->scaleConnection_ = output->scale().connect([this](int32_t scale) { 62 | FCITX_D(); 63 | d->next_.scale_ = scale; 64 | }); 65 | d->doneConnection_ = output->done().connect([this]() { 66 | FCITX_D(); 67 | d->current_ = d->next_; 68 | }); 69 | } 70 | 71 | OutputInfomation::~OutputInfomation() {} 72 | 73 | int32_t OutputInfomation::x() const { 74 | FCITX_D(); 75 | return d->current_.x_; 76 | } 77 | int32_t OutputInfomation::y() const { 78 | FCITX_D(); 79 | return d->current_.y_; 80 | } 81 | int32_t OutputInfomation::width() const { 82 | FCITX_D(); 83 | return d->current_.width_; 84 | } 85 | int32_t OutputInfomation::height() const { 86 | FCITX_D(); 87 | return d->current_.height_; 88 | } 89 | int32_t OutputInfomation::refreshRate() const { 90 | FCITX_D(); 91 | return d->current_.refreshRate_; 92 | } 93 | int32_t OutputInfomation::phyiscalWidth() const { 94 | FCITX_D(); 95 | return d->current_.physicalWidth_; 96 | } 97 | int32_t OutputInfomation::phyiscalHeight() const { 98 | FCITX_D(); 99 | return d->current_.physicalHeight_; 100 | } 101 | wl_output_subpixel OutputInfomation::subpixel() const { 102 | FCITX_D(); 103 | return d->current_.subpixel_; 104 | } 105 | const std::string &OutputInfomation::make() const { 106 | FCITX_D(); 107 | return d->current_.make_; 108 | } 109 | const std::string &OutputInfomation::model() const { 110 | FCITX_D(); 111 | return d->current_.model_; 112 | } 113 | wl_output_transform OutputInfomation::transform() const { 114 | FCITX_D(); 115 | return d->current_.transform_; 116 | } 117 | int32_t OutputInfomation::scale() const { 118 | FCITX_D(); 119 | return d->current_.scale_; 120 | } 121 | } // namespace fcitx::wayland 122 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/outputinformation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_WAYLAND_CORE_OUTPUTINFORMATION_H_ 8 | #define _FCITX_WAYLAND_CORE_OUTPUTINFORMATION_H_ 9 | 10 | #include "wl_output.h" 11 | 12 | #include 13 | 14 | namespace fcitx { 15 | namespace wayland { 16 | 17 | class OutputInfomationPrivate; 18 | 19 | class OutputInfomation { 20 | friend class Display; 21 | 22 | public: 23 | OutputInfomation(wayland::WlOutput *output); 24 | ~OutputInfomation(); 25 | 26 | int32_t x() const; 27 | int32_t y() const; 28 | int32_t width() const; 29 | int32_t height() const; 30 | int32_t refreshRate() const; 31 | int32_t phyiscalWidth() const; 32 | int32_t phyiscalHeight() const; 33 | wl_output_subpixel subpixel() const; 34 | const std::string &make() const; 35 | const std::string &model() const; 36 | wl_output_transform transform() const; 37 | int32_t scale() const; 38 | 39 | private: 40 | std::unique_ptr d_ptr; 41 | FCITX_DECLARE_PRIVATE(OutputInfomation); 42 | }; 43 | } // namespace wayland 44 | } // namespace fcitx 45 | 46 | #endif // _FCITX_WAYLAND_CORE_OUTPUTINFORMATION_H_ 47 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_buffer.h" 2 | #include 3 | namespace fcitx::wayland { 4 | const struct wl_buffer_listener WlBuffer::listener = { 5 | [](void *data, wl_buffer *wldata) { 6 | auto *obj = static_cast(data); 7 | assert(*obj == wldata); 8 | { return obj->release()(); } 9 | }, 10 | }; 11 | WlBuffer::WlBuffer(wl_buffer *data) 12 | : version_(wl_buffer_get_version(data)), data_(data) { 13 | wl_buffer_set_user_data(*this, this); 14 | wl_buffer_add_listener(*this, &WlBuffer::listener, this); 15 | } 16 | void WlBuffer::destructor(wl_buffer *data) { 17 | auto version = wl_buffer_get_version(data); 18 | if (version >= 1) { 19 | return wl_buffer_destroy(data); 20 | } 21 | } 22 | } // namespace fcitx::wayland 23 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_BUFFER 2 | #define WL_BUFFER 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlBuffer final { 8 | public: 9 | static constexpr const char *interface = "wl_buffer"; 10 | static constexpr const wl_interface *const wlInterface = 11 | &wl_buffer_interface; 12 | static constexpr const uint32_t version = 1; 13 | typedef wl_buffer wlType; 14 | operator wl_buffer *() { return data_.get(); } 15 | WlBuffer(wlType *data); 16 | WlBuffer(WlBuffer &&other) noexcept = delete; 17 | WlBuffer &operator=(WlBuffer &&other) noexcept = delete; 18 | auto actualVersion() const { return version_; } 19 | void *userData() const { return userData_; } 20 | void setUserData(void *userData) { userData_ = userData; } 21 | auto &release() { return releaseSignal_; } 22 | 23 | private: 24 | static void destructor(wl_buffer *); 25 | static const struct wl_buffer_listener listener; 26 | fcitx::Signal releaseSignal_; 27 | uint32_t version_; 28 | void *userData_ = nullptr; 29 | UniqueCPtr data_; 30 | }; 31 | static inline wl_buffer *rawPointer(WlBuffer *p) { 32 | return p ? static_cast(*p) : nullptr; 33 | } 34 | } // namespace fcitx::wayland 35 | #endif 36 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_callback.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_callback.h" 2 | #include 3 | namespace fcitx::wayland { 4 | const struct wl_callback_listener WlCallback::listener = { 5 | [](void *data, wl_callback *wldata, uint32_t callbackData) { 6 | auto *obj = static_cast(data); 7 | assert(*obj == wldata); 8 | { return obj->done()(callbackData); } 9 | }, 10 | }; 11 | WlCallback::WlCallback(wl_callback *data) 12 | : version_(wl_callback_get_version(data)), data_(data) { 13 | wl_callback_set_user_data(*this, this); 14 | wl_callback_add_listener(*this, &WlCallback::listener, this); 15 | } 16 | void WlCallback::destructor(wl_callback *data) { 17 | { return wl_callback_destroy(data); } 18 | } 19 | } // namespace fcitx::wayland 20 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_callback.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_CALLBACK 2 | #define WL_CALLBACK 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlCallback final { 8 | public: 9 | static constexpr const char *interface = "wl_callback"; 10 | static constexpr const wl_interface *const wlInterface = 11 | &wl_callback_interface; 12 | static constexpr const uint32_t version = 1; 13 | typedef wl_callback wlType; 14 | operator wl_callback *() { return data_.get(); } 15 | WlCallback(wlType *data); 16 | WlCallback(WlCallback &&other) noexcept = delete; 17 | WlCallback &operator=(WlCallback &&other) noexcept = delete; 18 | auto actualVersion() const { return version_; } 19 | void *userData() const { return userData_; } 20 | void setUserData(void *userData) { userData_ = userData; } 21 | auto &done() { return doneSignal_; } 22 | 23 | private: 24 | static void destructor(wl_callback *); 25 | static const struct wl_callback_listener listener; 26 | fcitx::Signal doneSignal_; 27 | uint32_t version_; 28 | void *userData_ = nullptr; 29 | UniqueCPtr data_; 30 | }; 31 | static inline wl_callback *rawPointer(WlCallback *p) { 32 | return p ? static_cast(*p) : nullptr; 33 | } 34 | } // namespace fcitx::wayland 35 | #endif 36 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_compositor.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_compositor.h" 2 | #include 3 | #include "wl_region.h" 4 | #include "wl_surface.h" 5 | namespace fcitx::wayland { 6 | WlCompositor::WlCompositor(wl_compositor *data) 7 | : version_(wl_compositor_get_version(data)), data_(data) { 8 | wl_compositor_set_user_data(*this, this); 9 | } 10 | void WlCompositor::destructor(wl_compositor *data) { 11 | { return wl_compositor_destroy(data); } 12 | } 13 | WlSurface *WlCompositor::createSurface() { 14 | return new WlSurface(wl_compositor_create_surface(*this)); 15 | } 16 | WlRegion *WlCompositor::createRegion() { 17 | return new WlRegion(wl_compositor_create_region(*this)); 18 | } 19 | } // namespace fcitx::wayland 20 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_compositor.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_COMPOSITOR 2 | #define WL_COMPOSITOR 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlRegion; 8 | class WlSurface; 9 | class WlCompositor final { 10 | public: 11 | static constexpr const char *interface = "wl_compositor"; 12 | static constexpr const wl_interface *const wlInterface = 13 | &wl_compositor_interface; 14 | static constexpr const uint32_t version = 4; 15 | typedef wl_compositor wlType; 16 | operator wl_compositor *() { return data_.get(); } 17 | WlCompositor(wlType *data); 18 | WlCompositor(WlCompositor &&other) noexcept = delete; 19 | WlCompositor &operator=(WlCompositor &&other) noexcept = delete; 20 | auto actualVersion() const { return version_; } 21 | void *userData() const { return userData_; } 22 | void setUserData(void *userData) { userData_ = userData; } 23 | WlSurface *createSurface(); 24 | WlRegion *createRegion(); 25 | 26 | private: 27 | static void destructor(wl_compositor *); 28 | uint32_t version_; 29 | void *userData_ = nullptr; 30 | UniqueCPtr data_; 31 | }; 32 | static inline wl_compositor *rawPointer(WlCompositor *p) { 33 | return p ? static_cast(*p) : nullptr; 34 | } 35 | } // namespace fcitx::wayland 36 | #endif 37 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_data_device.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_data_device.h" 2 | #include 3 | #include "wl_data_offer.h" 4 | #include "wl_data_source.h" 5 | #include "wl_surface.h" 6 | namespace fcitx::wayland { 7 | const struct wl_data_device_listener WlDataDevice::listener = { 8 | [](void *data, wl_data_device *wldata, wl_data_offer *id) { 9 | auto *obj = static_cast(data); 10 | assert(*obj == wldata); 11 | { 12 | auto *id_ = new WlDataOffer(id); 13 | return obj->dataOffer()(id_); 14 | } 15 | }, 16 | [](void *data, wl_data_device *wldata, uint32_t serial, wl_surface *surface, 17 | wl_fixed_t x, wl_fixed_t y, wl_data_offer *id) { 18 | auto *obj = static_cast(data); 19 | assert(*obj == wldata); 20 | { 21 | if (!surface) { 22 | return; 23 | } 24 | auto *surface_ = 25 | static_cast(wl_surface_get_user_data(surface)); 26 | auto *id_ = 27 | id ? static_cast(wl_data_offer_get_user_data(id)) 28 | : nullptr; 29 | return obj->enter()(serial, surface_, x, y, id_); 30 | } 31 | }, 32 | [](void *data, wl_data_device *wldata) { 33 | auto *obj = static_cast(data); 34 | assert(*obj == wldata); 35 | { return obj->leave()(); } 36 | }, 37 | [](void *data, wl_data_device *wldata, uint32_t time, wl_fixed_t x, 38 | wl_fixed_t y) { 39 | auto *obj = static_cast(data); 40 | assert(*obj == wldata); 41 | { return obj->motion()(time, x, y); } 42 | }, 43 | [](void *data, wl_data_device *wldata) { 44 | auto *obj = static_cast(data); 45 | assert(*obj == wldata); 46 | { return obj->drop()(); } 47 | }, 48 | [](void *data, wl_data_device *wldata, wl_data_offer *id) { 49 | auto *obj = static_cast(data); 50 | assert(*obj == wldata); 51 | { 52 | auto *id_ = 53 | id ? static_cast(wl_data_offer_get_user_data(id)) 54 | : nullptr; 55 | return obj->selection()(id_); 56 | } 57 | }, 58 | }; 59 | WlDataDevice::WlDataDevice(wl_data_device *data) 60 | : version_(wl_data_device_get_version(data)), data_(data) { 61 | wl_data_device_set_user_data(*this, this); 62 | wl_data_device_add_listener(*this, &WlDataDevice::listener, this); 63 | } 64 | void WlDataDevice::destructor(wl_data_device *data) { 65 | auto version = wl_data_device_get_version(data); 66 | if (version >= 2) { 67 | return wl_data_device_release(data); 68 | } else { 69 | return wl_data_device_destroy(data); 70 | } 71 | } 72 | void WlDataDevice::startDrag(WlDataSource *source, WlSurface *origin, 73 | WlSurface *icon, uint32_t serial) { 74 | return wl_data_device_start_drag(*this, rawPointer(source), 75 | rawPointer(origin), rawPointer(icon), 76 | serial); 77 | } 78 | void WlDataDevice::setSelection(WlDataSource *source, uint32_t serial) { 79 | return wl_data_device_set_selection(*this, rawPointer(source), serial); 80 | } 81 | } // namespace fcitx::wayland 82 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_data_device.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_DATA_DEVICE 2 | #define WL_DATA_DEVICE 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlDataOffer; 8 | class WlDataSource; 9 | class WlSurface; 10 | class WlDataDevice final { 11 | public: 12 | static constexpr const char *interface = "wl_data_device"; 13 | static constexpr const wl_interface *const wlInterface = 14 | &wl_data_device_interface; 15 | static constexpr const uint32_t version = 3; 16 | typedef wl_data_device wlType; 17 | operator wl_data_device *() { return data_.get(); } 18 | WlDataDevice(wlType *data); 19 | WlDataDevice(WlDataDevice &&other) noexcept = delete; 20 | WlDataDevice &operator=(WlDataDevice &&other) noexcept = delete; 21 | auto actualVersion() const { return version_; } 22 | void *userData() const { return userData_; } 23 | void setUserData(void *userData) { userData_ = userData; } 24 | void startDrag(WlDataSource *source, WlSurface *origin, WlSurface *icon, 25 | uint32_t serial); 26 | void setSelection(WlDataSource *source, uint32_t serial); 27 | auto &dataOffer() { return dataOfferSignal_; } 28 | auto &enter() { return enterSignal_; } 29 | auto &leave() { return leaveSignal_; } 30 | auto &motion() { return motionSignal_; } 31 | auto &drop() { return dropSignal_; } 32 | auto &selection() { return selectionSignal_; } 33 | 34 | private: 35 | static void destructor(wl_data_device *); 36 | static const struct wl_data_device_listener listener; 37 | fcitx::Signal dataOfferSignal_; 38 | fcitx::Signal 40 | enterSignal_; 41 | fcitx::Signal leaveSignal_; 42 | fcitx::Signal motionSignal_; 43 | fcitx::Signal dropSignal_; 44 | fcitx::Signal selectionSignal_; 45 | uint32_t version_; 46 | void *userData_ = nullptr; 47 | UniqueCPtr data_; 48 | }; 49 | static inline wl_data_device *rawPointer(WlDataDevice *p) { 50 | return p ? static_cast(*p) : nullptr; 51 | } 52 | } // namespace fcitx::wayland 53 | #endif 54 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_data_device_manager.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_data_device_manager.h" 2 | #include 3 | #include "wl_data_device.h" 4 | #include "wl_data_source.h" 5 | #include "wl_seat.h" 6 | namespace fcitx::wayland { 7 | WlDataDeviceManager::WlDataDeviceManager(wl_data_device_manager *data) 8 | : version_(wl_data_device_manager_get_version(data)), data_(data) { 9 | wl_data_device_manager_set_user_data(*this, this); 10 | } 11 | void WlDataDeviceManager::destructor(wl_data_device_manager *data) { 12 | { return wl_data_device_manager_destroy(data); } 13 | } 14 | WlDataSource *WlDataDeviceManager::createDataSource() { 15 | return new WlDataSource(wl_data_device_manager_create_data_source(*this)); 16 | } 17 | WlDataDevice *WlDataDeviceManager::getDataDevice(WlSeat *seat) { 18 | return new WlDataDevice( 19 | wl_data_device_manager_get_data_device(*this, rawPointer(seat))); 20 | } 21 | } // namespace fcitx::wayland 22 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_data_device_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_DATA_DEVICE_MANAGER 2 | #define WL_DATA_DEVICE_MANAGER 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlDataDevice; 8 | class WlDataSource; 9 | class WlSeat; 10 | class WlDataDeviceManager final { 11 | public: 12 | static constexpr const char *interface = "wl_data_device_manager"; 13 | static constexpr const wl_interface *const wlInterface = 14 | &wl_data_device_manager_interface; 15 | static constexpr const uint32_t version = 3; 16 | typedef wl_data_device_manager wlType; 17 | operator wl_data_device_manager *() { return data_.get(); } 18 | WlDataDeviceManager(wlType *data); 19 | WlDataDeviceManager(WlDataDeviceManager &&other) noexcept = delete; 20 | WlDataDeviceManager & 21 | operator=(WlDataDeviceManager &&other) noexcept = delete; 22 | auto actualVersion() const { return version_; } 23 | void *userData() const { return userData_; } 24 | void setUserData(void *userData) { userData_ = userData; } 25 | WlDataSource *createDataSource(); 26 | WlDataDevice *getDataDevice(WlSeat *seat); 27 | 28 | private: 29 | static void destructor(wl_data_device_manager *); 30 | uint32_t version_; 31 | void *userData_ = nullptr; 32 | UniqueCPtr data_; 33 | }; 34 | static inline wl_data_device_manager *rawPointer(WlDataDeviceManager *p) { 35 | return p ? static_cast(*p) : nullptr; 36 | } 37 | } // namespace fcitx::wayland 38 | #endif 39 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_data_offer.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_data_offer.h" 2 | #include 3 | namespace fcitx::wayland { 4 | const struct wl_data_offer_listener WlDataOffer::listener = { 5 | [](void *data, wl_data_offer *wldata, const char *mimeType) { 6 | auto *obj = static_cast(data); 7 | assert(*obj == wldata); 8 | { return obj->offer()(mimeType); } 9 | }, 10 | [](void *data, wl_data_offer *wldata, uint32_t sourceActions) { 11 | auto *obj = static_cast(data); 12 | assert(*obj == wldata); 13 | { return obj->sourceActions()(sourceActions); } 14 | }, 15 | [](void *data, wl_data_offer *wldata, uint32_t dndAction) { 16 | auto *obj = static_cast(data); 17 | assert(*obj == wldata); 18 | { return obj->action()(dndAction); } 19 | }, 20 | }; 21 | WlDataOffer::WlDataOffer(wl_data_offer *data) 22 | : version_(wl_data_offer_get_version(data)), data_(data) { 23 | wl_data_offer_set_user_data(*this, this); 24 | wl_data_offer_add_listener(*this, &WlDataOffer::listener, this); 25 | } 26 | void WlDataOffer::destructor(wl_data_offer *data) { 27 | auto version = wl_data_offer_get_version(data); 28 | if (version >= 1) { 29 | return wl_data_offer_destroy(data); 30 | } 31 | } 32 | void WlDataOffer::accept(uint32_t serial, const char *mimeType) { 33 | return wl_data_offer_accept(*this, serial, mimeType); 34 | } 35 | void WlDataOffer::receive(const char *mimeType, int32_t fd) { 36 | return wl_data_offer_receive(*this, mimeType, fd); 37 | } 38 | void WlDataOffer::finish() { return wl_data_offer_finish(*this); } 39 | void WlDataOffer::setActions(uint32_t dndActions, uint32_t preferredAction) { 40 | return wl_data_offer_set_actions(*this, dndActions, preferredAction); 41 | } 42 | } // namespace fcitx::wayland 43 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_data_offer.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_DATA_OFFER 2 | #define WL_DATA_OFFER 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlDataOffer final { 8 | public: 9 | static constexpr const char *interface = "wl_data_offer"; 10 | static constexpr const wl_interface *const wlInterface = 11 | &wl_data_offer_interface; 12 | static constexpr const uint32_t version = 3; 13 | typedef wl_data_offer wlType; 14 | operator wl_data_offer *() { return data_.get(); } 15 | WlDataOffer(wlType *data); 16 | WlDataOffer(WlDataOffer &&other) noexcept = delete; 17 | WlDataOffer &operator=(WlDataOffer &&other) noexcept = delete; 18 | auto actualVersion() const { return version_; } 19 | void *userData() const { return userData_; } 20 | void setUserData(void *userData) { userData_ = userData; } 21 | void accept(uint32_t serial, const char *mimeType); 22 | void receive(const char *mimeType, int32_t fd); 23 | void finish(); 24 | void setActions(uint32_t dndActions, uint32_t preferredAction); 25 | auto &offer() { return offerSignal_; } 26 | auto &sourceActions() { return sourceActionsSignal_; } 27 | auto &action() { return actionSignal_; } 28 | 29 | private: 30 | static void destructor(wl_data_offer *); 31 | static const struct wl_data_offer_listener listener; 32 | fcitx::Signal offerSignal_; 33 | fcitx::Signal sourceActionsSignal_; 34 | fcitx::Signal actionSignal_; 35 | uint32_t version_; 36 | void *userData_ = nullptr; 37 | UniqueCPtr data_; 38 | }; 39 | static inline wl_data_offer *rawPointer(WlDataOffer *p) { 40 | return p ? static_cast(*p) : nullptr; 41 | } 42 | } // namespace fcitx::wayland 43 | #endif 44 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_data_source.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_data_source.h" 2 | #include 3 | namespace fcitx::wayland { 4 | const struct wl_data_source_listener WlDataSource::listener = { 5 | [](void *data, wl_data_source *wldata, const char *mimeType) { 6 | auto *obj = static_cast(data); 7 | assert(*obj == wldata); 8 | { return obj->target()(mimeType); } 9 | }, 10 | [](void *data, wl_data_source *wldata, const char *mimeType, int32_t fd) { 11 | auto *obj = static_cast(data); 12 | assert(*obj == wldata); 13 | { return obj->send()(mimeType, fd); } 14 | }, 15 | [](void *data, wl_data_source *wldata) { 16 | auto *obj = static_cast(data); 17 | assert(*obj == wldata); 18 | { return obj->cancelled()(); } 19 | }, 20 | [](void *data, wl_data_source *wldata) { 21 | auto *obj = static_cast(data); 22 | assert(*obj == wldata); 23 | { return obj->dndDropPerformed()(); } 24 | }, 25 | [](void *data, wl_data_source *wldata) { 26 | auto *obj = static_cast(data); 27 | assert(*obj == wldata); 28 | { return obj->dndFinished()(); } 29 | }, 30 | [](void *data, wl_data_source *wldata, uint32_t dndAction) { 31 | auto *obj = static_cast(data); 32 | assert(*obj == wldata); 33 | { return obj->action()(dndAction); } 34 | }, 35 | }; 36 | WlDataSource::WlDataSource(wl_data_source *data) 37 | : version_(wl_data_source_get_version(data)), data_(data) { 38 | wl_data_source_set_user_data(*this, this); 39 | wl_data_source_add_listener(*this, &WlDataSource::listener, this); 40 | } 41 | void WlDataSource::destructor(wl_data_source *data) { 42 | auto version = wl_data_source_get_version(data); 43 | if (version >= 1) { 44 | return wl_data_source_destroy(data); 45 | } 46 | } 47 | void WlDataSource::offer(const char *mimeType) { 48 | return wl_data_source_offer(*this, mimeType); 49 | } 50 | void WlDataSource::setActions(uint32_t dndActions) { 51 | return wl_data_source_set_actions(*this, dndActions); 52 | } 53 | } // namespace fcitx::wayland 54 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_data_source.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_DATA_SOURCE 2 | #define WL_DATA_SOURCE 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlDataSource final { 8 | public: 9 | static constexpr const char *interface = "wl_data_source"; 10 | static constexpr const wl_interface *const wlInterface = 11 | &wl_data_source_interface; 12 | static constexpr const uint32_t version = 3; 13 | typedef wl_data_source wlType; 14 | operator wl_data_source *() { return data_.get(); } 15 | WlDataSource(wlType *data); 16 | WlDataSource(WlDataSource &&other) noexcept = delete; 17 | WlDataSource &operator=(WlDataSource &&other) noexcept = delete; 18 | auto actualVersion() const { return version_; } 19 | void *userData() const { return userData_; } 20 | void setUserData(void *userData) { userData_ = userData; } 21 | void offer(const char *mimeType); 22 | void setActions(uint32_t dndActions); 23 | auto &target() { return targetSignal_; } 24 | auto &send() { return sendSignal_; } 25 | auto &cancelled() { return cancelledSignal_; } 26 | auto &dndDropPerformed() { return dndDropPerformedSignal_; } 27 | auto &dndFinished() { return dndFinishedSignal_; } 28 | auto &action() { return actionSignal_; } 29 | 30 | private: 31 | static void destructor(wl_data_source *); 32 | static const struct wl_data_source_listener listener; 33 | fcitx::Signal targetSignal_; 34 | fcitx::Signal sendSignal_; 35 | fcitx::Signal cancelledSignal_; 36 | fcitx::Signal dndDropPerformedSignal_; 37 | fcitx::Signal dndFinishedSignal_; 38 | fcitx::Signal actionSignal_; 39 | uint32_t version_; 40 | void *userData_ = nullptr; 41 | UniqueCPtr data_; 42 | }; 43 | static inline wl_data_source *rawPointer(WlDataSource *p) { 44 | return p ? static_cast(*p) : nullptr; 45 | } 46 | } // namespace fcitx::wayland 47 | #endif 48 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_keyboard.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_keyboard.h" 2 | #include 3 | #include "wl_surface.h" 4 | namespace fcitx::wayland { 5 | const struct wl_keyboard_listener WlKeyboard::listener = { 6 | [](void *data, wl_keyboard *wldata, uint32_t format, int32_t fd, 7 | uint32_t size) { 8 | auto *obj = static_cast(data); 9 | assert(*obj == wldata); 10 | { return obj->keymap()(format, fd, size); } 11 | }, 12 | [](void *data, wl_keyboard *wldata, uint32_t serial, wl_surface *surface, 13 | wl_array *keys) { 14 | auto *obj = static_cast(data); 15 | assert(*obj == wldata); 16 | { 17 | if (!surface) { 18 | return; 19 | } 20 | auto *surface_ = 21 | static_cast(wl_surface_get_user_data(surface)); 22 | return obj->enter()(serial, surface_, keys); 23 | } 24 | }, 25 | [](void *data, wl_keyboard *wldata, uint32_t serial, wl_surface *surface) { 26 | auto *obj = static_cast(data); 27 | assert(*obj == wldata); 28 | { 29 | if (!surface) { 30 | return; 31 | } 32 | auto *surface_ = 33 | static_cast(wl_surface_get_user_data(surface)); 34 | return obj->leave()(serial, surface_); 35 | } 36 | }, 37 | [](void *data, wl_keyboard *wldata, uint32_t serial, uint32_t time, 38 | uint32_t key, uint32_t state) { 39 | auto *obj = static_cast(data); 40 | assert(*obj == wldata); 41 | { return obj->key()(serial, time, key, state); } 42 | }, 43 | [](void *data, wl_keyboard *wldata, uint32_t serial, uint32_t modsDepressed, 44 | uint32_t modsLatched, uint32_t modsLocked, uint32_t group) { 45 | auto *obj = static_cast(data); 46 | assert(*obj == wldata); 47 | { 48 | return obj->modifiers()(serial, modsDepressed, modsLatched, 49 | modsLocked, group); 50 | } 51 | }, 52 | [](void *data, wl_keyboard *wldata, int32_t rate, int32_t delay) { 53 | auto *obj = static_cast(data); 54 | assert(*obj == wldata); 55 | { return obj->repeatInfo()(rate, delay); } 56 | }, 57 | }; 58 | WlKeyboard::WlKeyboard(wl_keyboard *data) 59 | : version_(wl_keyboard_get_version(data)), data_(data) { 60 | wl_keyboard_set_user_data(*this, this); 61 | wl_keyboard_add_listener(*this, &WlKeyboard::listener, this); 62 | } 63 | void WlKeyboard::destructor(wl_keyboard *data) { 64 | auto version = wl_keyboard_get_version(data); 65 | if (version >= 3) { 66 | return wl_keyboard_release(data); 67 | } else { 68 | return wl_keyboard_destroy(data); 69 | } 70 | } 71 | } // namespace fcitx::wayland 72 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_KEYBOARD 2 | #define WL_KEYBOARD 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlSurface; 8 | class WlKeyboard final { 9 | public: 10 | static constexpr const char *interface = "wl_keyboard"; 11 | static constexpr const wl_interface *const wlInterface = 12 | &wl_keyboard_interface; 13 | static constexpr const uint32_t version = 7; 14 | typedef wl_keyboard wlType; 15 | operator wl_keyboard *() { return data_.get(); } 16 | WlKeyboard(wlType *data); 17 | WlKeyboard(WlKeyboard &&other) noexcept = delete; 18 | WlKeyboard &operator=(WlKeyboard &&other) noexcept = delete; 19 | auto actualVersion() const { return version_; } 20 | void *userData() const { return userData_; } 21 | void setUserData(void *userData) { userData_ = userData; } 22 | auto &keymap() { return keymapSignal_; } 23 | auto &enter() { return enterSignal_; } 24 | auto &leave() { return leaveSignal_; } 25 | auto &key() { return keySignal_; } 26 | auto &modifiers() { return modifiersSignal_; } 27 | auto &repeatInfo() { return repeatInfoSignal_; } 28 | 29 | private: 30 | static void destructor(wl_keyboard *); 31 | static const struct wl_keyboard_listener listener; 32 | fcitx::Signal keymapSignal_; 33 | fcitx::Signal enterSignal_; 34 | fcitx::Signal leaveSignal_; 35 | fcitx::Signal keySignal_; 36 | fcitx::Signal 37 | modifiersSignal_; 38 | fcitx::Signal repeatInfoSignal_; 39 | uint32_t version_; 40 | void *userData_ = nullptr; 41 | UniqueCPtr data_; 42 | }; 43 | static inline wl_keyboard *rawPointer(WlKeyboard *p) { 44 | return p ? static_cast(*p) : nullptr; 45 | } 46 | } // namespace fcitx::wayland 47 | #endif 48 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_output.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_output.h" 2 | #include 3 | namespace fcitx::wayland { 4 | const struct wl_output_listener WlOutput::listener = { 5 | [](void *data, wl_output *wldata, int32_t x, int32_t y, 6 | int32_t physicalWidth, int32_t physicalHeight, int32_t subpixel, 7 | const char *make, const char *model, int32_t transform) { 8 | auto *obj = static_cast(data); 9 | assert(*obj == wldata); 10 | { 11 | return obj->geometry()(x, y, physicalWidth, physicalHeight, 12 | subpixel, make, model, transform); 13 | } 14 | }, 15 | [](void *data, wl_output *wldata, uint32_t flags, int32_t width, 16 | int32_t height, int32_t refresh) { 17 | auto *obj = static_cast(data); 18 | assert(*obj == wldata); 19 | { return obj->mode()(flags, width, height, refresh); } 20 | }, 21 | [](void *data, wl_output *wldata) { 22 | auto *obj = static_cast(data); 23 | assert(*obj == wldata); 24 | { return obj->done()(); } 25 | }, 26 | [](void *data, wl_output *wldata, int32_t factor) { 27 | auto *obj = static_cast(data); 28 | assert(*obj == wldata); 29 | { return obj->scale()(factor); } 30 | }, 31 | }; 32 | WlOutput::WlOutput(wl_output *data) 33 | : version_(wl_output_get_version(data)), data_(data) { 34 | wl_output_set_user_data(*this, this); 35 | wl_output_add_listener(*this, &WlOutput::listener, this); 36 | } 37 | void WlOutput::destructor(wl_output *data) { 38 | auto version = wl_output_get_version(data); 39 | if (version >= 3) { 40 | return wl_output_release(data); 41 | } else { 42 | return wl_output_destroy(data); 43 | } 44 | } 45 | } // namespace fcitx::wayland 46 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_output.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_OUTPUT 2 | #define WL_OUTPUT 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlOutput final { 8 | public: 9 | static constexpr const char *interface = "wl_output"; 10 | static constexpr const wl_interface *const wlInterface = 11 | &wl_output_interface; 12 | static constexpr const uint32_t version = 3; 13 | typedef wl_output wlType; 14 | operator wl_output *() { return data_.get(); } 15 | WlOutput(wlType *data); 16 | WlOutput(WlOutput &&other) noexcept = delete; 17 | WlOutput &operator=(WlOutput &&other) noexcept = delete; 18 | auto actualVersion() const { return version_; } 19 | void *userData() const { return userData_; } 20 | void setUserData(void *userData) { userData_ = userData; } 21 | auto &geometry() { return geometrySignal_; } 22 | auto &mode() { return modeSignal_; } 23 | auto &done() { return doneSignal_; } 24 | auto &scale() { return scaleSignal_; } 25 | 26 | private: 27 | static void destructor(wl_output *); 28 | static const struct wl_output_listener listener; 29 | fcitx::Signal 31 | geometrySignal_; 32 | fcitx::Signal modeSignal_; 33 | fcitx::Signal doneSignal_; 34 | fcitx::Signal scaleSignal_; 35 | uint32_t version_; 36 | void *userData_ = nullptr; 37 | UniqueCPtr data_; 38 | }; 39 | static inline wl_output *rawPointer(WlOutput *p) { 40 | return p ? static_cast(*p) : nullptr; 41 | } 42 | } // namespace fcitx::wayland 43 | #endif 44 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_pointer.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_pointer.h" 2 | #include 3 | #include "wl_surface.h" 4 | namespace fcitx::wayland { 5 | const struct wl_pointer_listener WlPointer::listener = { 6 | [](void *data, wl_pointer *wldata, uint32_t serial, wl_surface *surface, 7 | wl_fixed_t surfaceX, wl_fixed_t surfaceY) { 8 | auto *obj = static_cast(data); 9 | assert(*obj == wldata); 10 | { 11 | if (!surface) { 12 | return; 13 | } 14 | auto *surface_ = 15 | static_cast(wl_surface_get_user_data(surface)); 16 | return obj->enter()(serial, surface_, surfaceX, surfaceY); 17 | } 18 | }, 19 | [](void *data, wl_pointer *wldata, uint32_t serial, wl_surface *surface) { 20 | auto *obj = static_cast(data); 21 | assert(*obj == wldata); 22 | { 23 | if (!surface) { 24 | return; 25 | } 26 | auto *surface_ = 27 | static_cast(wl_surface_get_user_data(surface)); 28 | return obj->leave()(serial, surface_); 29 | } 30 | }, 31 | [](void *data, wl_pointer *wldata, uint32_t time, wl_fixed_t surfaceX, 32 | wl_fixed_t surfaceY) { 33 | auto *obj = static_cast(data); 34 | assert(*obj == wldata); 35 | { return obj->motion()(time, surfaceX, surfaceY); } 36 | }, 37 | [](void *data, wl_pointer *wldata, uint32_t serial, uint32_t time, 38 | uint32_t button, uint32_t state) { 39 | auto *obj = static_cast(data); 40 | assert(*obj == wldata); 41 | { return obj->button()(serial, time, button, state); } 42 | }, 43 | [](void *data, wl_pointer *wldata, uint32_t time, uint32_t axis, 44 | wl_fixed_t value) { 45 | auto *obj = static_cast(data); 46 | assert(*obj == wldata); 47 | { return obj->axis()(time, axis, value); } 48 | }, 49 | [](void *data, wl_pointer *wldata) { 50 | auto *obj = static_cast(data); 51 | assert(*obj == wldata); 52 | { return obj->frame()(); } 53 | }, 54 | [](void *data, wl_pointer *wldata, uint32_t axisSource) { 55 | auto *obj = static_cast(data); 56 | assert(*obj == wldata); 57 | { return obj->axisSource()(axisSource); } 58 | }, 59 | [](void *data, wl_pointer *wldata, uint32_t time, uint32_t axis) { 60 | auto *obj = static_cast(data); 61 | assert(*obj == wldata); 62 | { return obj->axisStop()(time, axis); } 63 | }, 64 | [](void *data, wl_pointer *wldata, uint32_t axis, int32_t discrete) { 65 | auto *obj = static_cast(data); 66 | assert(*obj == wldata); 67 | { return obj->axisDiscrete()(axis, discrete); } 68 | }, 69 | }; 70 | WlPointer::WlPointer(wl_pointer *data) 71 | : version_(wl_pointer_get_version(data)), data_(data) { 72 | wl_pointer_set_user_data(*this, this); 73 | wl_pointer_add_listener(*this, &WlPointer::listener, this); 74 | } 75 | void WlPointer::destructor(wl_pointer *data) { 76 | auto version = wl_pointer_get_version(data); 77 | if (version >= 3) { 78 | return wl_pointer_release(data); 79 | } else { 80 | return wl_pointer_destroy(data); 81 | } 82 | } 83 | void WlPointer::setCursor(uint32_t serial, WlSurface *surface, int32_t hotspotX, 84 | int32_t hotspotY) { 85 | return wl_pointer_set_cursor(*this, serial, rawPointer(surface), hotspotX, 86 | hotspotY); 87 | } 88 | } // namespace fcitx::wayland 89 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_pointer.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_POINTER 2 | #define WL_POINTER 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlSurface; 8 | class WlPointer final { 9 | public: 10 | static constexpr const char *interface = "wl_pointer"; 11 | static constexpr const wl_interface *const wlInterface = 12 | &wl_pointer_interface; 13 | static constexpr const uint32_t version = 7; 14 | typedef wl_pointer wlType; 15 | operator wl_pointer *() { return data_.get(); } 16 | WlPointer(wlType *data); 17 | WlPointer(WlPointer &&other) noexcept = delete; 18 | WlPointer &operator=(WlPointer &&other) noexcept = delete; 19 | auto actualVersion() const { return version_; } 20 | void *userData() const { return userData_; } 21 | void setUserData(void *userData) { userData_ = userData; } 22 | void setCursor(uint32_t serial, WlSurface *surface, int32_t hotspotX, 23 | int32_t hotspotY); 24 | auto &enter() { return enterSignal_; } 25 | auto &leave() { return leaveSignal_; } 26 | auto &motion() { return motionSignal_; } 27 | auto &button() { return buttonSignal_; } 28 | auto &axis() { return axisSignal_; } 29 | auto &frame() { return frameSignal_; } 30 | auto &axisSource() { return axisSourceSignal_; } 31 | auto &axisStop() { return axisStopSignal_; } 32 | auto &axisDiscrete() { return axisDiscreteSignal_; } 33 | 34 | private: 35 | static void destructor(wl_pointer *); 36 | static const struct wl_pointer_listener listener; 37 | fcitx::Signal 38 | enterSignal_; 39 | fcitx::Signal leaveSignal_; 40 | fcitx::Signal motionSignal_; 41 | fcitx::Signal buttonSignal_; 42 | fcitx::Signal axisSignal_; 43 | fcitx::Signal frameSignal_; 44 | fcitx::Signal axisSourceSignal_; 45 | fcitx::Signal axisStopSignal_; 46 | fcitx::Signal axisDiscreteSignal_; 47 | uint32_t version_; 48 | void *userData_ = nullptr; 49 | UniqueCPtr data_; 50 | }; 51 | static inline wl_pointer *rawPointer(WlPointer *p) { 52 | return p ? static_cast(*p) : nullptr; 53 | } 54 | } // namespace fcitx::wayland 55 | #endif 56 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_region.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_region.h" 2 | #include 3 | namespace fcitx::wayland { 4 | WlRegion::WlRegion(wl_region *data) 5 | : version_(wl_region_get_version(data)), data_(data) { 6 | wl_region_set_user_data(*this, this); 7 | } 8 | void WlRegion::destructor(wl_region *data) { 9 | auto version = wl_region_get_version(data); 10 | if (version >= 1) { 11 | return wl_region_destroy(data); 12 | } 13 | } 14 | void WlRegion::add(int32_t x, int32_t y, int32_t width, int32_t height) { 15 | return wl_region_add(*this, x, y, width, height); 16 | } 17 | void WlRegion::subtract(int32_t x, int32_t y, int32_t width, int32_t height) { 18 | return wl_region_subtract(*this, x, y, width, height); 19 | } 20 | } // namespace fcitx::wayland 21 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_region.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_REGION 2 | #define WL_REGION 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlRegion final { 8 | public: 9 | static constexpr const char *interface = "wl_region"; 10 | static constexpr const wl_interface *const wlInterface = 11 | &wl_region_interface; 12 | static constexpr const uint32_t version = 1; 13 | typedef wl_region wlType; 14 | operator wl_region *() { return data_.get(); } 15 | WlRegion(wlType *data); 16 | WlRegion(WlRegion &&other) noexcept = delete; 17 | WlRegion &operator=(WlRegion &&other) noexcept = delete; 18 | auto actualVersion() const { return version_; } 19 | void *userData() const { return userData_; } 20 | void setUserData(void *userData) { userData_ = userData; } 21 | void add(int32_t x, int32_t y, int32_t width, int32_t height); 22 | void subtract(int32_t x, int32_t y, int32_t width, int32_t height); 23 | 24 | private: 25 | static void destructor(wl_region *); 26 | uint32_t version_; 27 | void *userData_ = nullptr; 28 | UniqueCPtr data_; 29 | }; 30 | static inline wl_region *rawPointer(WlRegion *p) { 31 | return p ? static_cast(*p) : nullptr; 32 | } 33 | } // namespace fcitx::wayland 34 | #endif 35 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_registry.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_registry.h" 2 | #include 3 | namespace fcitx::wayland { 4 | const struct wl_registry_listener WlRegistry::listener = { 5 | [](void *data, wl_registry *wldata, uint32_t name, const char *interface, 6 | uint32_t version) { 7 | auto *obj = static_cast(data); 8 | assert(*obj == wldata); 9 | { return obj->global()(name, interface, version); } 10 | }, 11 | [](void *data, wl_registry *wldata, uint32_t name) { 12 | auto *obj = static_cast(data); 13 | assert(*obj == wldata); 14 | { return obj->globalRemove()(name); } 15 | }, 16 | }; 17 | WlRegistry::WlRegistry(wl_registry *data) 18 | : version_(wl_registry_get_version(data)), data_(data) { 19 | wl_registry_set_user_data(*this, this); 20 | wl_registry_add_listener(*this, &WlRegistry::listener, this); 21 | } 22 | void WlRegistry::destructor(wl_registry *data) { 23 | { return wl_registry_destroy(data); } 24 | } 25 | } // namespace fcitx::wayland 26 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_registry.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_REGISTRY 2 | #define WL_REGISTRY 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlRegistry final { 8 | public: 9 | static constexpr const char *interface = "wl_registry"; 10 | static constexpr const wl_interface *const wlInterface = 11 | &wl_registry_interface; 12 | static constexpr const uint32_t version = 1; 13 | typedef wl_registry wlType; 14 | operator wl_registry *() { return data_.get(); } 15 | WlRegistry(wlType *data); 16 | WlRegistry(WlRegistry &&other) noexcept = delete; 17 | WlRegistry &operator=(WlRegistry &&other) noexcept = delete; 18 | auto actualVersion() const { return version_; } 19 | void *userData() const { return userData_; } 20 | void setUserData(void *userData) { userData_ = userData; } 21 | template 22 | T *bind(uint32_t name, uint32_t requested_version) { 23 | return new T(static_cast( 24 | wl_registry_bind(*this, name, T::wlInterface, requested_version))); 25 | } 26 | auto &global() { return globalSignal_; } 27 | auto &globalRemove() { return globalRemoveSignal_; } 28 | 29 | private: 30 | static void destructor(wl_registry *); 31 | static const struct wl_registry_listener listener; 32 | fcitx::Signal globalSignal_; 33 | fcitx::Signal globalRemoveSignal_; 34 | uint32_t version_; 35 | void *userData_ = nullptr; 36 | UniqueCPtr data_; 37 | }; 38 | static inline wl_registry *rawPointer(WlRegistry *p) { 39 | return p ? static_cast(*p) : nullptr; 40 | } 41 | } // namespace fcitx::wayland 42 | #endif 43 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_seat.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_seat.h" 2 | #include 3 | #include "wl_keyboard.h" 4 | #include "wl_pointer.h" 5 | #include "wl_touch.h" 6 | namespace fcitx::wayland { 7 | const struct wl_seat_listener WlSeat::listener = { 8 | [](void *data, wl_seat *wldata, uint32_t capabilities) { 9 | auto *obj = static_cast(data); 10 | assert(*obj == wldata); 11 | { return obj->capabilities()(capabilities); } 12 | }, 13 | [](void *data, wl_seat *wldata, const char *name) { 14 | auto *obj = static_cast(data); 15 | assert(*obj == wldata); 16 | { return obj->name()(name); } 17 | }, 18 | }; 19 | WlSeat::WlSeat(wl_seat *data) 20 | : version_(wl_seat_get_version(data)), data_(data) { 21 | wl_seat_set_user_data(*this, this); 22 | wl_seat_add_listener(*this, &WlSeat::listener, this); 23 | } 24 | void WlSeat::destructor(wl_seat *data) { 25 | auto version = wl_seat_get_version(data); 26 | if (version >= 5) { 27 | return wl_seat_release(data); 28 | } else { 29 | return wl_seat_destroy(data); 30 | } 31 | } 32 | WlPointer *WlSeat::getPointer() { 33 | return new WlPointer(wl_seat_get_pointer(*this)); 34 | } 35 | WlKeyboard *WlSeat::getKeyboard() { 36 | return new WlKeyboard(wl_seat_get_keyboard(*this)); 37 | } 38 | WlTouch *WlSeat::getTouch() { return new WlTouch(wl_seat_get_touch(*this)); } 39 | } // namespace fcitx::wayland 40 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_seat.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_SEAT 2 | #define WL_SEAT 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlKeyboard; 8 | class WlPointer; 9 | class WlTouch; 10 | class WlSeat final { 11 | public: 12 | static constexpr const char *interface = "wl_seat"; 13 | static constexpr const wl_interface *const wlInterface = &wl_seat_interface; 14 | static constexpr const uint32_t version = 7; 15 | typedef wl_seat wlType; 16 | operator wl_seat *() { return data_.get(); } 17 | WlSeat(wlType *data); 18 | WlSeat(WlSeat &&other) noexcept = delete; 19 | WlSeat &operator=(WlSeat &&other) noexcept = delete; 20 | auto actualVersion() const { return version_; } 21 | void *userData() const { return userData_; } 22 | void setUserData(void *userData) { userData_ = userData; } 23 | WlPointer *getPointer(); 24 | WlKeyboard *getKeyboard(); 25 | WlTouch *getTouch(); 26 | auto &capabilities() { return capabilitiesSignal_; } 27 | auto &name() { return nameSignal_; } 28 | 29 | private: 30 | static void destructor(wl_seat *); 31 | static const struct wl_seat_listener listener; 32 | fcitx::Signal capabilitiesSignal_; 33 | fcitx::Signal nameSignal_; 34 | uint32_t version_; 35 | void *userData_ = nullptr; 36 | UniqueCPtr data_; 37 | }; 38 | static inline wl_seat *rawPointer(WlSeat *p) { 39 | return p ? static_cast(*p) : nullptr; 40 | } 41 | } // namespace fcitx::wayland 42 | #endif 43 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_shell.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_shell.h" 2 | #include 3 | #include "wl_shell_surface.h" 4 | #include "wl_surface.h" 5 | namespace fcitx::wayland { 6 | WlShell::WlShell(wl_shell *data) 7 | : version_(wl_shell_get_version(data)), data_(data) { 8 | wl_shell_set_user_data(*this, this); 9 | } 10 | void WlShell::destructor(wl_shell *data) { 11 | { return wl_shell_destroy(data); } 12 | } 13 | WlShellSurface *WlShell::getShellSurface(WlSurface *surface) { 14 | return new WlShellSurface( 15 | wl_shell_get_shell_surface(*this, rawPointer(surface))); 16 | } 17 | } // namespace fcitx::wayland 18 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_shell.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_SHELL 2 | #define WL_SHELL 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlShellSurface; 8 | class WlSurface; 9 | class WlShell final { 10 | public: 11 | static constexpr const char *interface = "wl_shell"; 12 | static constexpr const wl_interface *const wlInterface = 13 | &wl_shell_interface; 14 | static constexpr const uint32_t version = 1; 15 | typedef wl_shell wlType; 16 | operator wl_shell *() { return data_.get(); } 17 | WlShell(wlType *data); 18 | WlShell(WlShell &&other) noexcept = delete; 19 | WlShell &operator=(WlShell &&other) noexcept = delete; 20 | auto actualVersion() const { return version_; } 21 | void *userData() const { return userData_; } 22 | void setUserData(void *userData) { userData_ = userData; } 23 | WlShellSurface *getShellSurface(WlSurface *surface); 24 | 25 | private: 26 | static void destructor(wl_shell *); 27 | uint32_t version_; 28 | void *userData_ = nullptr; 29 | UniqueCPtr data_; 30 | }; 31 | static inline wl_shell *rawPointer(WlShell *p) { 32 | return p ? static_cast(*p) : nullptr; 33 | } 34 | } // namespace fcitx::wayland 35 | #endif 36 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_shell_surface.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_shell_surface.h" 2 | #include 3 | #include "wl_output.h" 4 | #include "wl_seat.h" 5 | #include "wl_surface.h" 6 | namespace fcitx::wayland { 7 | const struct wl_shell_surface_listener WlShellSurface::listener = { 8 | [](void *data, wl_shell_surface *wldata, uint32_t serial) { 9 | auto *obj = static_cast(data); 10 | assert(*obj == wldata); 11 | { return obj->ping()(serial); } 12 | }, 13 | [](void *data, wl_shell_surface *wldata, uint32_t edges, int32_t width, 14 | int32_t height) { 15 | auto *obj = static_cast(data); 16 | assert(*obj == wldata); 17 | { return obj->configure()(edges, width, height); } 18 | }, 19 | [](void *data, wl_shell_surface *wldata) { 20 | auto *obj = static_cast(data); 21 | assert(*obj == wldata); 22 | { return obj->popupDone()(); } 23 | }, 24 | }; 25 | WlShellSurface::WlShellSurface(wl_shell_surface *data) 26 | : version_(wl_shell_surface_get_version(data)), data_(data) { 27 | wl_shell_surface_set_user_data(*this, this); 28 | wl_shell_surface_add_listener(*this, &WlShellSurface::listener, this); 29 | } 30 | void WlShellSurface::destructor(wl_shell_surface *data) { 31 | { return wl_shell_surface_destroy(data); } 32 | } 33 | void WlShellSurface::pong(uint32_t serial) { 34 | return wl_shell_surface_pong(*this, serial); 35 | } 36 | void WlShellSurface::move(WlSeat *seat, uint32_t serial) { 37 | return wl_shell_surface_move(*this, rawPointer(seat), serial); 38 | } 39 | void WlShellSurface::resize(WlSeat *seat, uint32_t serial, uint32_t edges) { 40 | return wl_shell_surface_resize(*this, rawPointer(seat), serial, edges); 41 | } 42 | void WlShellSurface::setToplevel() { 43 | return wl_shell_surface_set_toplevel(*this); 44 | } 45 | void WlShellSurface::setTransient(WlSurface *parent, int32_t x, int32_t y, 46 | uint32_t flags) { 47 | return wl_shell_surface_set_transient(*this, rawPointer(parent), x, y, 48 | flags); 49 | } 50 | void WlShellSurface::setFullscreen(uint32_t method, uint32_t framerate, 51 | WlOutput *output) { 52 | return wl_shell_surface_set_fullscreen(*this, method, framerate, 53 | rawPointer(output)); 54 | } 55 | void WlShellSurface::setPopup(WlSeat *seat, uint32_t serial, WlSurface *parent, 56 | int32_t x, int32_t y, uint32_t flags) { 57 | return wl_shell_surface_set_popup(*this, rawPointer(seat), serial, 58 | rawPointer(parent), x, y, flags); 59 | } 60 | void WlShellSurface::setMaximized(WlOutput *output) { 61 | return wl_shell_surface_set_maximized(*this, rawPointer(output)); 62 | } 63 | void WlShellSurface::setTitle(const char *title) { 64 | return wl_shell_surface_set_title(*this, title); 65 | } 66 | void WlShellSurface::setClass(const char *class_) { 67 | return wl_shell_surface_set_class(*this, class_); 68 | } 69 | } // namespace fcitx::wayland 70 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_shell_surface.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_SHELL_SURFACE 2 | #define WL_SHELL_SURFACE 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlOutput; 8 | class WlSeat; 9 | class WlSurface; 10 | class WlShellSurface final { 11 | public: 12 | static constexpr const char *interface = "wl_shell_surface"; 13 | static constexpr const wl_interface *const wlInterface = 14 | &wl_shell_surface_interface; 15 | static constexpr const uint32_t version = 1; 16 | typedef wl_shell_surface wlType; 17 | operator wl_shell_surface *() { return data_.get(); } 18 | WlShellSurface(wlType *data); 19 | WlShellSurface(WlShellSurface &&other) noexcept = delete; 20 | WlShellSurface &operator=(WlShellSurface &&other) noexcept = delete; 21 | auto actualVersion() const { return version_; } 22 | void *userData() const { return userData_; } 23 | void setUserData(void *userData) { userData_ = userData; } 24 | void pong(uint32_t serial); 25 | void move(WlSeat *seat, uint32_t serial); 26 | void resize(WlSeat *seat, uint32_t serial, uint32_t edges); 27 | void setToplevel(); 28 | void setTransient(WlSurface *parent, int32_t x, int32_t y, uint32_t flags); 29 | void setFullscreen(uint32_t method, uint32_t framerate, WlOutput *output); 30 | void setPopup(WlSeat *seat, uint32_t serial, WlSurface *parent, int32_t x, 31 | int32_t y, uint32_t flags); 32 | void setMaximized(WlOutput *output); 33 | void setTitle(const char *title); 34 | void setClass(const char *class_); 35 | auto &ping() { return pingSignal_; } 36 | auto &configure() { return configureSignal_; } 37 | auto &popupDone() { return popupDoneSignal_; } 38 | 39 | private: 40 | static void destructor(wl_shell_surface *); 41 | static const struct wl_shell_surface_listener listener; 42 | fcitx::Signal pingSignal_; 43 | fcitx::Signal configureSignal_; 44 | fcitx::Signal popupDoneSignal_; 45 | uint32_t version_; 46 | void *userData_ = nullptr; 47 | UniqueCPtr data_; 48 | }; 49 | static inline wl_shell_surface *rawPointer(WlShellSurface *p) { 50 | return p ? static_cast(*p) : nullptr; 51 | } 52 | } // namespace fcitx::wayland 53 | #endif 54 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_shm.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_shm.h" 2 | #include 3 | #include "wl_shm_pool.h" 4 | namespace fcitx::wayland { 5 | const struct wl_shm_listener WlShm::listener = { 6 | [](void *data, wl_shm *wldata, uint32_t format) { 7 | auto *obj = static_cast(data); 8 | assert(*obj == wldata); 9 | { return obj->format()(format); } 10 | }, 11 | }; 12 | WlShm::WlShm(wl_shm *data) : version_(wl_shm_get_version(data)), data_(data) { 13 | wl_shm_set_user_data(*this, this); 14 | wl_shm_add_listener(*this, &WlShm::listener, this); 15 | } 16 | void WlShm::destructor(wl_shm *data) { 17 | { return wl_shm_destroy(data); } 18 | } 19 | WlShmPool *WlShm::createPool(int32_t fd, int32_t size) { 20 | return new WlShmPool(wl_shm_create_pool(*this, fd, size)); 21 | } 22 | } // namespace fcitx::wayland 23 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_shm.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_SHM 2 | #define WL_SHM 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlShmPool; 8 | class WlShm final { 9 | public: 10 | static constexpr const char *interface = "wl_shm"; 11 | static constexpr const wl_interface *const wlInterface = &wl_shm_interface; 12 | static constexpr const uint32_t version = 1; 13 | typedef wl_shm wlType; 14 | operator wl_shm *() { return data_.get(); } 15 | WlShm(wlType *data); 16 | WlShm(WlShm &&other) noexcept = delete; 17 | WlShm &operator=(WlShm &&other) noexcept = delete; 18 | auto actualVersion() const { return version_; } 19 | void *userData() const { return userData_; } 20 | void setUserData(void *userData) { userData_ = userData; } 21 | WlShmPool *createPool(int32_t fd, int32_t size); 22 | auto &format() { return formatSignal_; } 23 | 24 | private: 25 | static void destructor(wl_shm *); 26 | static const struct wl_shm_listener listener; 27 | fcitx::Signal formatSignal_; 28 | uint32_t version_; 29 | void *userData_ = nullptr; 30 | UniqueCPtr data_; 31 | }; 32 | static inline wl_shm *rawPointer(WlShm *p) { 33 | return p ? static_cast(*p) : nullptr; 34 | } 35 | } // namespace fcitx::wayland 36 | #endif 37 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_shm_pool.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_shm_pool.h" 2 | #include 3 | #include "wl_buffer.h" 4 | namespace fcitx::wayland { 5 | WlShmPool::WlShmPool(wl_shm_pool *data) 6 | : version_(wl_shm_pool_get_version(data)), data_(data) { 7 | wl_shm_pool_set_user_data(*this, this); 8 | } 9 | void WlShmPool::destructor(wl_shm_pool *data) { 10 | auto version = wl_shm_pool_get_version(data); 11 | if (version >= 1) { 12 | return wl_shm_pool_destroy(data); 13 | } 14 | } 15 | WlBuffer *WlShmPool::createBuffer(int32_t offset, int32_t width, int32_t height, 16 | int32_t stride, uint32_t format) { 17 | return new WlBuffer(wl_shm_pool_create_buffer(*this, offset, width, height, 18 | stride, format)); 19 | } 20 | void WlShmPool::resize(int32_t size) { return wl_shm_pool_resize(*this, size); } 21 | } // namespace fcitx::wayland 22 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_shm_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_SHM_POOL 2 | #define WL_SHM_POOL 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlBuffer; 8 | class WlShmPool final { 9 | public: 10 | static constexpr const char *interface = "wl_shm_pool"; 11 | static constexpr const wl_interface *const wlInterface = 12 | &wl_shm_pool_interface; 13 | static constexpr const uint32_t version = 1; 14 | typedef wl_shm_pool wlType; 15 | operator wl_shm_pool *() { return data_.get(); } 16 | WlShmPool(wlType *data); 17 | WlShmPool(WlShmPool &&other) noexcept = delete; 18 | WlShmPool &operator=(WlShmPool &&other) noexcept = delete; 19 | auto actualVersion() const { return version_; } 20 | void *userData() const { return userData_; } 21 | void setUserData(void *userData) { userData_ = userData; } 22 | WlBuffer *createBuffer(int32_t offset, int32_t width, int32_t height, 23 | int32_t stride, uint32_t format); 24 | void resize(int32_t size); 25 | 26 | private: 27 | static void destructor(wl_shm_pool *); 28 | uint32_t version_; 29 | void *userData_ = nullptr; 30 | UniqueCPtr data_; 31 | }; 32 | static inline wl_shm_pool *rawPointer(WlShmPool *p) { 33 | return p ? static_cast(*p) : nullptr; 34 | } 35 | } // namespace fcitx::wayland 36 | #endif 37 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_subcompositor.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_subcompositor.h" 2 | #include 3 | #include "wl_subsurface.h" 4 | #include "wl_surface.h" 5 | namespace fcitx::wayland { 6 | WlSubcompositor::WlSubcompositor(wl_subcompositor *data) 7 | : version_(wl_subcompositor_get_version(data)), data_(data) { 8 | wl_subcompositor_set_user_data(*this, this); 9 | } 10 | void WlSubcompositor::destructor(wl_subcompositor *data) { 11 | auto version = wl_subcompositor_get_version(data); 12 | if (version >= 1) { 13 | return wl_subcompositor_destroy(data); 14 | } 15 | } 16 | WlSubsurface *WlSubcompositor::getSubsurface(WlSurface *surface, 17 | WlSurface *parent) { 18 | return new WlSubsurface(wl_subcompositor_get_subsurface( 19 | *this, rawPointer(surface), rawPointer(parent))); 20 | } 21 | } // namespace fcitx::wayland 22 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_subcompositor.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_SUBCOMPOSITOR 2 | #define WL_SUBCOMPOSITOR 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlSubsurface; 8 | class WlSurface; 9 | class WlSubcompositor final { 10 | public: 11 | static constexpr const char *interface = "wl_subcompositor"; 12 | static constexpr const wl_interface *const wlInterface = 13 | &wl_subcompositor_interface; 14 | static constexpr const uint32_t version = 1; 15 | typedef wl_subcompositor wlType; 16 | operator wl_subcompositor *() { return data_.get(); } 17 | WlSubcompositor(wlType *data); 18 | WlSubcompositor(WlSubcompositor &&other) noexcept = delete; 19 | WlSubcompositor &operator=(WlSubcompositor &&other) noexcept = delete; 20 | auto actualVersion() const { return version_; } 21 | void *userData() const { return userData_; } 22 | void setUserData(void *userData) { userData_ = userData; } 23 | WlSubsurface *getSubsurface(WlSurface *surface, WlSurface *parent); 24 | 25 | private: 26 | static void destructor(wl_subcompositor *); 27 | uint32_t version_; 28 | void *userData_ = nullptr; 29 | UniqueCPtr data_; 30 | }; 31 | static inline wl_subcompositor *rawPointer(WlSubcompositor *p) { 32 | return p ? static_cast(*p) : nullptr; 33 | } 34 | } // namespace fcitx::wayland 35 | #endif 36 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_subsurface.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_subsurface.h" 2 | #include 3 | #include "wl_surface.h" 4 | namespace fcitx::wayland { 5 | WlSubsurface::WlSubsurface(wl_subsurface *data) 6 | : version_(wl_subsurface_get_version(data)), data_(data) { 7 | wl_subsurface_set_user_data(*this, this); 8 | } 9 | void WlSubsurface::destructor(wl_subsurface *data) { 10 | auto version = wl_subsurface_get_version(data); 11 | if (version >= 1) { 12 | return wl_subsurface_destroy(data); 13 | } 14 | } 15 | void WlSubsurface::setPosition(int32_t x, int32_t y) { 16 | return wl_subsurface_set_position(*this, x, y); 17 | } 18 | void WlSubsurface::placeAbove(WlSurface *sibling) { 19 | return wl_subsurface_place_above(*this, rawPointer(sibling)); 20 | } 21 | void WlSubsurface::placeBelow(WlSurface *sibling) { 22 | return wl_subsurface_place_below(*this, rawPointer(sibling)); 23 | } 24 | void WlSubsurface::setSync() { return wl_subsurface_set_sync(*this); } 25 | void WlSubsurface::setDesync() { return wl_subsurface_set_desync(*this); } 26 | } // namespace fcitx::wayland 27 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_subsurface.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_SUBSURFACE 2 | #define WL_SUBSURFACE 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlSurface; 8 | class WlSubsurface final { 9 | public: 10 | static constexpr const char *interface = "wl_subsurface"; 11 | static constexpr const wl_interface *const wlInterface = 12 | &wl_subsurface_interface; 13 | static constexpr const uint32_t version = 1; 14 | typedef wl_subsurface wlType; 15 | operator wl_subsurface *() { return data_.get(); } 16 | WlSubsurface(wlType *data); 17 | WlSubsurface(WlSubsurface &&other) noexcept = delete; 18 | WlSubsurface &operator=(WlSubsurface &&other) noexcept = delete; 19 | auto actualVersion() const { return version_; } 20 | void *userData() const { return userData_; } 21 | void setUserData(void *userData) { userData_ = userData; } 22 | void setPosition(int32_t x, int32_t y); 23 | void placeAbove(WlSurface *sibling); 24 | void placeBelow(WlSurface *sibling); 25 | void setSync(); 26 | void setDesync(); 27 | 28 | private: 29 | static void destructor(wl_subsurface *); 30 | uint32_t version_; 31 | void *userData_ = nullptr; 32 | UniqueCPtr data_; 33 | }; 34 | static inline wl_subsurface *rawPointer(WlSubsurface *p) { 35 | return p ? static_cast(*p) : nullptr; 36 | } 37 | } // namespace fcitx::wayland 38 | #endif 39 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_surface.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_surface.h" 2 | #include 3 | #include "wl_buffer.h" 4 | #include "wl_callback.h" 5 | #include "wl_output.h" 6 | #include "wl_region.h" 7 | namespace fcitx::wayland { 8 | const struct wl_surface_listener WlSurface::listener = { 9 | [](void *data, wl_surface *wldata, wl_output *output) { 10 | auto *obj = static_cast(data); 11 | assert(*obj == wldata); 12 | { 13 | if (!output) { 14 | return; 15 | } 16 | auto *output_ = 17 | static_cast(wl_output_get_user_data(output)); 18 | return obj->enter()(output_); 19 | } 20 | }, 21 | [](void *data, wl_surface *wldata, wl_output *output) { 22 | auto *obj = static_cast(data); 23 | assert(*obj == wldata); 24 | { 25 | if (!output) { 26 | return; 27 | } 28 | auto *output_ = 29 | static_cast(wl_output_get_user_data(output)); 30 | return obj->leave()(output_); 31 | } 32 | }, 33 | }; 34 | WlSurface::WlSurface(wl_surface *data) 35 | : version_(wl_surface_get_version(data)), data_(data) { 36 | wl_surface_set_user_data(*this, this); 37 | wl_surface_add_listener(*this, &WlSurface::listener, this); 38 | } 39 | void WlSurface::destructor(wl_surface *data) { 40 | auto version = wl_surface_get_version(data); 41 | if (version >= 1) { 42 | return wl_surface_destroy(data); 43 | } 44 | } 45 | void WlSurface::attach(WlBuffer *buffer, int32_t x, int32_t y) { 46 | return wl_surface_attach(*this, rawPointer(buffer), x, y); 47 | } 48 | void WlSurface::damage(int32_t x, int32_t y, int32_t width, int32_t height) { 49 | return wl_surface_damage(*this, x, y, width, height); 50 | } 51 | WlCallback *WlSurface::frame() { 52 | return new WlCallback(wl_surface_frame(*this)); 53 | } 54 | void WlSurface::setOpaqueRegion(WlRegion *region) { 55 | return wl_surface_set_opaque_region(*this, rawPointer(region)); 56 | } 57 | void WlSurface::setInputRegion(WlRegion *region) { 58 | return wl_surface_set_input_region(*this, rawPointer(region)); 59 | } 60 | void WlSurface::commit() { return wl_surface_commit(*this); } 61 | void WlSurface::setBufferTransform(int32_t transform) { 62 | return wl_surface_set_buffer_transform(*this, transform); 63 | } 64 | void WlSurface::setBufferScale(int32_t scale) { 65 | return wl_surface_set_buffer_scale(*this, scale); 66 | } 67 | void WlSurface::damageBuffer(int32_t x, int32_t y, int32_t width, 68 | int32_t height) { 69 | return wl_surface_damage_buffer(*this, x, y, width, height); 70 | } 71 | } // namespace fcitx::wayland 72 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_surface.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_SURFACE 2 | #define WL_SURFACE 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlBuffer; 8 | class WlCallback; 9 | class WlOutput; 10 | class WlRegion; 11 | class WlSurface final { 12 | public: 13 | static constexpr const char *interface = "wl_surface"; 14 | static constexpr const wl_interface *const wlInterface = 15 | &wl_surface_interface; 16 | static constexpr const uint32_t version = 4; 17 | typedef wl_surface wlType; 18 | operator wl_surface *() { return data_.get(); } 19 | WlSurface(wlType *data); 20 | WlSurface(WlSurface &&other) noexcept = delete; 21 | WlSurface &operator=(WlSurface &&other) noexcept = delete; 22 | auto actualVersion() const { return version_; } 23 | void *userData() const { return userData_; } 24 | void setUserData(void *userData) { userData_ = userData; } 25 | void attach(WlBuffer *buffer, int32_t x, int32_t y); 26 | void damage(int32_t x, int32_t y, int32_t width, int32_t height); 27 | WlCallback *frame(); 28 | void setOpaqueRegion(WlRegion *region); 29 | void setInputRegion(WlRegion *region); 30 | void commit(); 31 | void setBufferTransform(int32_t transform); 32 | void setBufferScale(int32_t scale); 33 | void damageBuffer(int32_t x, int32_t y, int32_t width, int32_t height); 34 | auto &enter() { return enterSignal_; } 35 | auto &leave() { return leaveSignal_; } 36 | 37 | private: 38 | static void destructor(wl_surface *); 39 | static const struct wl_surface_listener listener; 40 | fcitx::Signal enterSignal_; 41 | fcitx::Signal leaveSignal_; 42 | uint32_t version_; 43 | void *userData_ = nullptr; 44 | UniqueCPtr data_; 45 | }; 46 | static inline wl_surface *rawPointer(WlSurface *p) { 47 | return p ? static_cast(*p) : nullptr; 48 | } 49 | } // namespace fcitx::wayland 50 | #endif 51 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_touch.cpp: -------------------------------------------------------------------------------- 1 | #include "wl_touch.h" 2 | #include 3 | #include "wl_surface.h" 4 | namespace fcitx::wayland { 5 | const struct wl_touch_listener WlTouch::listener = { 6 | [](void *data, wl_touch *wldata, uint32_t serial, uint32_t time, 7 | wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y) { 8 | auto *obj = static_cast(data); 9 | assert(*obj == wldata); 10 | { 11 | if (!surface) { 12 | return; 13 | } 14 | auto *surface_ = 15 | static_cast(wl_surface_get_user_data(surface)); 16 | return obj->down()(serial, time, surface_, id, x, y); 17 | } 18 | }, 19 | [](void *data, wl_touch *wldata, uint32_t serial, uint32_t time, 20 | int32_t id) { 21 | auto *obj = static_cast(data); 22 | assert(*obj == wldata); 23 | { return obj->up()(serial, time, id); } 24 | }, 25 | [](void *data, wl_touch *wldata, uint32_t time, int32_t id, wl_fixed_t x, 26 | wl_fixed_t y) { 27 | auto *obj = static_cast(data); 28 | assert(*obj == wldata); 29 | { return obj->motion()(time, id, x, y); } 30 | }, 31 | [](void *data, wl_touch *wldata) { 32 | auto *obj = static_cast(data); 33 | assert(*obj == wldata); 34 | { return obj->frame()(); } 35 | }, 36 | [](void *data, wl_touch *wldata) { 37 | auto *obj = static_cast(data); 38 | assert(*obj == wldata); 39 | { return obj->cancel()(); } 40 | }, 41 | [](void *data, wl_touch *wldata, int32_t id, wl_fixed_t major, 42 | wl_fixed_t minor) { 43 | auto *obj = static_cast(data); 44 | assert(*obj == wldata); 45 | { return obj->shape()(id, major, minor); } 46 | }, 47 | [](void *data, wl_touch *wldata, int32_t id, wl_fixed_t orientation) { 48 | auto *obj = static_cast(data); 49 | assert(*obj == wldata); 50 | { return obj->orientation()(id, orientation); } 51 | }, 52 | }; 53 | WlTouch::WlTouch(wl_touch *data) 54 | : version_(wl_touch_get_version(data)), data_(data) { 55 | wl_touch_set_user_data(*this, this); 56 | wl_touch_add_listener(*this, &WlTouch::listener, this); 57 | } 58 | void WlTouch::destructor(wl_touch *data) { 59 | auto version = wl_touch_get_version(data); 60 | if (version >= 3) { 61 | return wl_touch_release(data); 62 | } else { 63 | return wl_touch_destroy(data); 64 | } 65 | } 66 | } // namespace fcitx::wayland 67 | -------------------------------------------------------------------------------- /src/fcitx-wayland/core/wl_touch.h: -------------------------------------------------------------------------------- 1 | #ifndef WL_TOUCH 2 | #define WL_TOUCH 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | namespace fcitx::wayland { 7 | class WlSurface; 8 | class WlTouch final { 9 | public: 10 | static constexpr const char *interface = "wl_touch"; 11 | static constexpr const wl_interface *const wlInterface = 12 | &wl_touch_interface; 13 | static constexpr const uint32_t version = 7; 14 | typedef wl_touch wlType; 15 | operator wl_touch *() { return data_.get(); } 16 | WlTouch(wlType *data); 17 | WlTouch(WlTouch &&other) noexcept = delete; 18 | WlTouch &operator=(WlTouch &&other) noexcept = delete; 19 | auto actualVersion() const { return version_; } 20 | void *userData() const { return userData_; } 21 | void setUserData(void *userData) { userData_ = userData; } 22 | auto &down() { return downSignal_; } 23 | auto &up() { return upSignal_; } 24 | auto &motion() { return motionSignal_; } 25 | auto &frame() { return frameSignal_; } 26 | auto &cancel() { return cancelSignal_; } 27 | auto &shape() { return shapeSignal_; } 28 | auto &orientation() { return orientationSignal_; } 29 | 30 | private: 31 | static void destructor(wl_touch *); 32 | static const struct wl_touch_listener listener; 33 | fcitx::Signal 35 | downSignal_; 36 | fcitx::Signal upSignal_; 37 | fcitx::Signal 38 | motionSignal_; 39 | fcitx::Signal frameSignal_; 40 | fcitx::Signal cancelSignal_; 41 | fcitx::Signal shapeSignal_; 42 | fcitx::Signal orientationSignal_; 43 | uint32_t version_; 44 | void *userData_ = nullptr; 45 | UniqueCPtr data_; 46 | }; 47 | static inline wl_touch *rawPointer(WlTouch *p) { 48 | return p ? static_cast(*p) : nullptr; 49 | } 50 | } // namespace fcitx::wayland 51 | #endif 52 | -------------------------------------------------------------------------------- /src/fcitx-wayland/input-method/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ecm_add_wayland_client_protocol(WAYLAND_IM_PROTOCOL_SRCS 2 | PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/input-method/input-method-unstable-v1.xml 3 | BASENAME input-method-unstable-v1) 4 | 5 | set(FCITX_WAYLAND_INPUTMETHOD_SOURCES 6 | zwp_input_method_context_v1.cpp 7 | zwp_input_method_v1.cpp 8 | zwp_input_panel_surface_v1.cpp 9 | zwp_input_panel_v1.cpp 10 | ) 11 | 12 | add_library(Fcitx5WaylandInputMethod STATIC ${FCITX_WAYLAND_INPUTMETHOD_SOURCES} ${WAYLAND_IM_PROTOCOL_SRCS}) 13 | set_target_properties(Fcitx5WaylandInputMethod PROPERTIES 14 | COMPILE_FLAGS "-fPIC" 15 | LINK_FLAGS "-Wl,--no-undefined" 16 | ) 17 | target_include_directories(Fcitx5WaylandInputMethod PUBLIC 18 | "$") 19 | target_link_libraries(Fcitx5WaylandInputMethod Wayland::Client Fcitx5::Utils Fcitx5::Wayland::Core) 20 | 21 | add_library(Fcitx5::Wayland::InputMethod ALIAS Fcitx5WaylandInputMethod) 22 | -------------------------------------------------------------------------------- /src/fcitx-wayland/input-method/zwp_input_method_context_v1.cpp: -------------------------------------------------------------------------------- 1 | #include "zwp_input_method_context_v1.h" 2 | #include 3 | #include "wl_keyboard.h" 4 | namespace fcitx::wayland { 5 | const struct zwp_input_method_context_v1_listener 6 | ZwpInputMethodContextV1::listener = { 7 | [](void *data, zwp_input_method_context_v1 *wldata, const char *text, 8 | uint32_t cursor, uint32_t anchor) { 9 | auto *obj = static_cast(data); 10 | assert(*obj == wldata); 11 | { return obj->surroundingText()(text, cursor, anchor); } 12 | }, 13 | [](void *data, zwp_input_method_context_v1 *wldata) { 14 | auto *obj = static_cast(data); 15 | assert(*obj == wldata); 16 | { return obj->reset()(); } 17 | }, 18 | [](void *data, zwp_input_method_context_v1 *wldata, uint32_t hint, 19 | uint32_t purpose) { 20 | auto *obj = static_cast(data); 21 | assert(*obj == wldata); 22 | { return obj->contentType()(hint, purpose); } 23 | }, 24 | [](void *data, zwp_input_method_context_v1 *wldata, uint32_t button, 25 | uint32_t index) { 26 | auto *obj = static_cast(data); 27 | assert(*obj == wldata); 28 | { return obj->invokeAction()(button, index); } 29 | }, 30 | [](void *data, zwp_input_method_context_v1 *wldata, uint32_t serial) { 31 | auto *obj = static_cast(data); 32 | assert(*obj == wldata); 33 | { return obj->commitState()(serial); } 34 | }, 35 | [](void *data, zwp_input_method_context_v1 *wldata, 36 | const char *language) { 37 | auto *obj = static_cast(data); 38 | assert(*obj == wldata); 39 | { return obj->preferredLanguage()(language); } 40 | }, 41 | }; 42 | ZwpInputMethodContextV1::ZwpInputMethodContextV1( 43 | zwp_input_method_context_v1 *data) 44 | : version_(zwp_input_method_context_v1_get_version(data)), data_(data) { 45 | zwp_input_method_context_v1_set_user_data(*this, this); 46 | zwp_input_method_context_v1_add_listener( 47 | *this, &ZwpInputMethodContextV1::listener, this); 48 | } 49 | void ZwpInputMethodContextV1::destructor(zwp_input_method_context_v1 *data) { 50 | auto version = zwp_input_method_context_v1_get_version(data); 51 | if (version >= 1) { 52 | return zwp_input_method_context_v1_destroy(data); 53 | } 54 | } 55 | void ZwpInputMethodContextV1::commitString(uint32_t serial, const char *text) { 56 | return zwp_input_method_context_v1_commit_string(*this, serial, text); 57 | } 58 | void ZwpInputMethodContextV1::preeditString(uint32_t serial, const char *text, 59 | const char *commit) { 60 | return zwp_input_method_context_v1_preedit_string(*this, serial, text, 61 | commit); 62 | } 63 | void ZwpInputMethodContextV1::preeditStyling(uint32_t index, uint32_t length, 64 | uint32_t style) { 65 | return zwp_input_method_context_v1_preedit_styling(*this, index, length, 66 | style); 67 | } 68 | void ZwpInputMethodContextV1::preeditCursor(int32_t index) { 69 | return zwp_input_method_context_v1_preedit_cursor(*this, index); 70 | } 71 | void ZwpInputMethodContextV1::deleteSurroundingText(int32_t index, 72 | uint32_t length) { 73 | return zwp_input_method_context_v1_delete_surrounding_text(*this, index, 74 | length); 75 | } 76 | void ZwpInputMethodContextV1::cursorPosition(int32_t index, int32_t anchor) { 77 | return zwp_input_method_context_v1_cursor_position(*this, index, anchor); 78 | } 79 | void ZwpInputMethodContextV1::modifiersMap(wl_array *map) { 80 | return zwp_input_method_context_v1_modifiers_map(*this, map); 81 | } 82 | void ZwpInputMethodContextV1::keysym(uint32_t serial, uint32_t time, 83 | uint32_t sym, uint32_t state, 84 | uint32_t modifiers) { 85 | return zwp_input_method_context_v1_keysym(*this, serial, time, sym, state, 86 | modifiers); 87 | } 88 | WlKeyboard *ZwpInputMethodContextV1::grabKeyboard() { 89 | return new WlKeyboard(zwp_input_method_context_v1_grab_keyboard(*this)); 90 | } 91 | void ZwpInputMethodContextV1::key(uint32_t serial, uint32_t time, uint32_t key, 92 | uint32_t state) { 93 | return zwp_input_method_context_v1_key(*this, serial, time, key, state); 94 | } 95 | void ZwpInputMethodContextV1::modifiers(uint32_t serial, uint32_t modsDepressed, 96 | uint32_t modsLatched, 97 | uint32_t modsLocked, uint32_t group) { 98 | return zwp_input_method_context_v1_modifiers( 99 | *this, serial, modsDepressed, modsLatched, modsLocked, group); 100 | } 101 | void ZwpInputMethodContextV1::language(uint32_t serial, const char *language) { 102 | return zwp_input_method_context_v1_language(*this, serial, language); 103 | } 104 | void ZwpInputMethodContextV1::textDirection(uint32_t serial, 105 | uint32_t direction) { 106 | return zwp_input_method_context_v1_text_direction(*this, serial, direction); 107 | } 108 | } // namespace fcitx::wayland 109 | -------------------------------------------------------------------------------- /src/fcitx-wayland/input-method/zwp_input_method_context_v1.h: -------------------------------------------------------------------------------- 1 | #ifndef ZWP_INPUT_METHOD_CONTEXT_V1 2 | #define ZWP_INPUT_METHOD_CONTEXT_V1 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | #include "wayland-input-method-unstable-v1-client-protocol.h" 7 | namespace fcitx::wayland { 8 | class WlKeyboard; 9 | class ZwpInputMethodContextV1 final { 10 | public: 11 | static constexpr const char *interface = "zwp_input_method_context_v1"; 12 | static constexpr const wl_interface *const wlInterface = 13 | &zwp_input_method_context_v1_interface; 14 | static constexpr const uint32_t version = 1; 15 | typedef zwp_input_method_context_v1 wlType; 16 | operator zwp_input_method_context_v1 *() { return data_.get(); } 17 | ZwpInputMethodContextV1(wlType *data); 18 | ZwpInputMethodContextV1(ZwpInputMethodContextV1 &&other) noexcept = delete; 19 | ZwpInputMethodContextV1 & 20 | operator=(ZwpInputMethodContextV1 &&other) noexcept = delete; 21 | auto actualVersion() const { return version_; } 22 | void *userData() const { return userData_; } 23 | void setUserData(void *userData) { userData_ = userData; } 24 | void commitString(uint32_t serial, const char *text); 25 | void preeditString(uint32_t serial, const char *text, const char *commit); 26 | void preeditStyling(uint32_t index, uint32_t length, uint32_t style); 27 | void preeditCursor(int32_t index); 28 | void deleteSurroundingText(int32_t index, uint32_t length); 29 | void cursorPosition(int32_t index, int32_t anchor); 30 | void modifiersMap(wl_array *map); 31 | void keysym(uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, 32 | uint32_t modifiers); 33 | WlKeyboard *grabKeyboard(); 34 | void key(uint32_t serial, uint32_t time, uint32_t key, uint32_t state); 35 | void modifiers(uint32_t serial, uint32_t modsDepressed, 36 | uint32_t modsLatched, uint32_t modsLocked, uint32_t group); 37 | void language(uint32_t serial, const char *language); 38 | void textDirection(uint32_t serial, uint32_t direction); 39 | auto &surroundingText() { return surroundingTextSignal_; } 40 | auto &reset() { return resetSignal_; } 41 | auto &contentType() { return contentTypeSignal_; } 42 | auto &invokeAction() { return invokeActionSignal_; } 43 | auto &commitState() { return commitStateSignal_; } 44 | auto &preferredLanguage() { return preferredLanguageSignal_; } 45 | 46 | private: 47 | static void destructor(zwp_input_method_context_v1 *); 48 | static const struct zwp_input_method_context_v1_listener listener; 49 | fcitx::Signal 50 | surroundingTextSignal_; 51 | fcitx::Signal resetSignal_; 52 | fcitx::Signal contentTypeSignal_; 53 | fcitx::Signal invokeActionSignal_; 54 | fcitx::Signal commitStateSignal_; 55 | fcitx::Signal preferredLanguageSignal_; 56 | uint32_t version_; 57 | void *userData_ = nullptr; 58 | UniqueCPtr data_; 59 | }; 60 | static inline zwp_input_method_context_v1 * 61 | rawPointer(ZwpInputMethodContextV1 *p) { 62 | return p ? static_cast(*p) : nullptr; 63 | } 64 | } // namespace fcitx::wayland 65 | #endif 66 | -------------------------------------------------------------------------------- /src/fcitx-wayland/input-method/zwp_input_method_v1.cpp: -------------------------------------------------------------------------------- 1 | #include "zwp_input_method_v1.h" 2 | #include 3 | #include "zwp_input_method_context_v1.h" 4 | namespace fcitx::wayland { 5 | const struct zwp_input_method_v1_listener ZwpInputMethodV1::listener = { 6 | [](void *data, zwp_input_method_v1 *wldata, 7 | zwp_input_method_context_v1 *id) { 8 | auto *obj = static_cast(data); 9 | assert(*obj == wldata); 10 | { 11 | auto *id_ = new ZwpInputMethodContextV1(id); 12 | return obj->activate()(id_); 13 | } 14 | }, 15 | [](void *data, zwp_input_method_v1 *wldata, 16 | zwp_input_method_context_v1 *context) { 17 | auto *obj = static_cast(data); 18 | assert(*obj == wldata); 19 | { 20 | if (!context) { 21 | return; 22 | } 23 | auto *context_ = static_cast( 24 | zwp_input_method_context_v1_get_user_data(context)); 25 | return obj->deactivate()(context_); 26 | } 27 | }, 28 | }; 29 | ZwpInputMethodV1::ZwpInputMethodV1(zwp_input_method_v1 *data) 30 | : version_(zwp_input_method_v1_get_version(data)), data_(data) { 31 | zwp_input_method_v1_set_user_data(*this, this); 32 | zwp_input_method_v1_add_listener(*this, &ZwpInputMethodV1::listener, this); 33 | } 34 | void ZwpInputMethodV1::destructor(zwp_input_method_v1 *data) { 35 | { return zwp_input_method_v1_destroy(data); } 36 | } 37 | } // namespace fcitx::wayland 38 | -------------------------------------------------------------------------------- /src/fcitx-wayland/input-method/zwp_input_method_v1.h: -------------------------------------------------------------------------------- 1 | #ifndef ZWP_INPUT_METHOD_V1 2 | #define ZWP_INPUT_METHOD_V1 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | #include "wayland-input-method-unstable-v1-client-protocol.h" 7 | namespace fcitx::wayland { 8 | class ZwpInputMethodContextV1; 9 | class ZwpInputMethodV1 final { 10 | public: 11 | static constexpr const char *interface = "zwp_input_method_v1"; 12 | static constexpr const wl_interface *const wlInterface = 13 | &zwp_input_method_v1_interface; 14 | static constexpr const uint32_t version = 1; 15 | typedef zwp_input_method_v1 wlType; 16 | operator zwp_input_method_v1 *() { return data_.get(); } 17 | ZwpInputMethodV1(wlType *data); 18 | ZwpInputMethodV1(ZwpInputMethodV1 &&other) noexcept = delete; 19 | ZwpInputMethodV1 &operator=(ZwpInputMethodV1 &&other) noexcept = delete; 20 | auto actualVersion() const { return version_; } 21 | void *userData() const { return userData_; } 22 | void setUserData(void *userData) { userData_ = userData; } 23 | auto &activate() { return activateSignal_; } 24 | auto &deactivate() { return deactivateSignal_; } 25 | 26 | private: 27 | static void destructor(zwp_input_method_v1 *); 28 | static const struct zwp_input_method_v1_listener listener; 29 | fcitx::Signal activateSignal_; 30 | fcitx::Signal deactivateSignal_; 31 | uint32_t version_; 32 | void *userData_ = nullptr; 33 | UniqueCPtr data_; 34 | }; 35 | static inline zwp_input_method_v1 *rawPointer(ZwpInputMethodV1 *p) { 36 | return p ? static_cast(*p) : nullptr; 37 | } 38 | } // namespace fcitx::wayland 39 | #endif 40 | -------------------------------------------------------------------------------- /src/fcitx-wayland/input-method/zwp_input_panel_surface_v1.cpp: -------------------------------------------------------------------------------- 1 | #include "zwp_input_panel_surface_v1.h" 2 | #include 3 | #include "wl_output.h" 4 | namespace fcitx::wayland { 5 | ZwpInputPanelSurfaceV1::ZwpInputPanelSurfaceV1(zwp_input_panel_surface_v1 *data) 6 | : version_(zwp_input_panel_surface_v1_get_version(data)), data_(data) { 7 | zwp_input_panel_surface_v1_set_user_data(*this, this); 8 | } 9 | void ZwpInputPanelSurfaceV1::destructor(zwp_input_panel_surface_v1 *data) { 10 | { return zwp_input_panel_surface_v1_destroy(data); } 11 | } 12 | void ZwpInputPanelSurfaceV1::setToplevel(WlOutput *output, uint32_t position) { 13 | return zwp_input_panel_surface_v1_set_toplevel(*this, rawPointer(output), 14 | position); 15 | } 16 | void ZwpInputPanelSurfaceV1::setOverlayPanel() { 17 | return zwp_input_panel_surface_v1_set_overlay_panel(*this); 18 | } 19 | } // namespace fcitx::wayland 20 | -------------------------------------------------------------------------------- /src/fcitx-wayland/input-method/zwp_input_panel_surface_v1.h: -------------------------------------------------------------------------------- 1 | #ifndef ZWP_INPUT_PANEL_SURFACE_V1 2 | #define ZWP_INPUT_PANEL_SURFACE_V1 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | #include "wayland-input-method-unstable-v1-client-protocol.h" 7 | namespace fcitx::wayland { 8 | class WlOutput; 9 | class ZwpInputPanelSurfaceV1 final { 10 | public: 11 | static constexpr const char *interface = "zwp_input_panel_surface_v1"; 12 | static constexpr const wl_interface *const wlInterface = 13 | &zwp_input_panel_surface_v1_interface; 14 | static constexpr const uint32_t version = 1; 15 | typedef zwp_input_panel_surface_v1 wlType; 16 | operator zwp_input_panel_surface_v1 *() { return data_.get(); } 17 | ZwpInputPanelSurfaceV1(wlType *data); 18 | ZwpInputPanelSurfaceV1(ZwpInputPanelSurfaceV1 &&other) noexcept = delete; 19 | ZwpInputPanelSurfaceV1 & 20 | operator=(ZwpInputPanelSurfaceV1 &&other) noexcept = delete; 21 | auto actualVersion() const { return version_; } 22 | void *userData() const { return userData_; } 23 | void setUserData(void *userData) { userData_ = userData; } 24 | void setToplevel(WlOutput *output, uint32_t position); 25 | void setOverlayPanel(); 26 | 27 | private: 28 | static void destructor(zwp_input_panel_surface_v1 *); 29 | uint32_t version_; 30 | void *userData_ = nullptr; 31 | UniqueCPtr data_; 32 | }; 33 | static inline zwp_input_panel_surface_v1 * 34 | rawPointer(ZwpInputPanelSurfaceV1 *p) { 35 | return p ? static_cast(*p) : nullptr; 36 | } 37 | } // namespace fcitx::wayland 38 | #endif 39 | -------------------------------------------------------------------------------- /src/fcitx-wayland/input-method/zwp_input_panel_v1.cpp: -------------------------------------------------------------------------------- 1 | #include "zwp_input_panel_v1.h" 2 | #include 3 | #include "wl_surface.h" 4 | #include "zwp_input_panel_surface_v1.h" 5 | namespace fcitx::wayland { 6 | ZwpInputPanelV1::ZwpInputPanelV1(zwp_input_panel_v1 *data) 7 | : version_(zwp_input_panel_v1_get_version(data)), data_(data) { 8 | zwp_input_panel_v1_set_user_data(*this, this); 9 | } 10 | void ZwpInputPanelV1::destructor(zwp_input_panel_v1 *data) { 11 | { return zwp_input_panel_v1_destroy(data); } 12 | } 13 | ZwpInputPanelSurfaceV1 * 14 | ZwpInputPanelV1::getInputPanelSurface(WlSurface *surface) { 15 | return new ZwpInputPanelSurfaceV1( 16 | zwp_input_panel_v1_get_input_panel_surface(*this, rawPointer(surface))); 17 | } 18 | } // namespace fcitx::wayland 19 | -------------------------------------------------------------------------------- /src/fcitx-wayland/input-method/zwp_input_panel_v1.h: -------------------------------------------------------------------------------- 1 | #ifndef ZWP_INPUT_PANEL_V1 2 | #define ZWP_INPUT_PANEL_V1 3 | #include 4 | #include 5 | #include "fcitx-utils/signals.h" 6 | #include "wayland-input-method-unstable-v1-client-protocol.h" 7 | namespace fcitx::wayland { 8 | class WlSurface; 9 | class ZwpInputPanelSurfaceV1; 10 | class ZwpInputPanelV1 final { 11 | public: 12 | static constexpr const char *interface = "zwp_input_panel_v1"; 13 | static constexpr const wl_interface *const wlInterface = 14 | &zwp_input_panel_v1_interface; 15 | static constexpr const uint32_t version = 1; 16 | typedef zwp_input_panel_v1 wlType; 17 | operator zwp_input_panel_v1 *() { return data_.get(); } 18 | ZwpInputPanelV1(wlType *data); 19 | ZwpInputPanelV1(ZwpInputPanelV1 &&other) noexcept = delete; 20 | ZwpInputPanelV1 &operator=(ZwpInputPanelV1 &&other) noexcept = delete; 21 | auto actualVersion() const { return version_; } 22 | void *userData() const { return userData_; } 23 | void setUserData(void *userData) { userData_ = userData; } 24 | ZwpInputPanelSurfaceV1 *getInputPanelSurface(WlSurface *surface); 25 | 26 | private: 27 | static void destructor(zwp_input_panel_v1 *); 28 | uint32_t version_; 29 | void *userData_ = nullptr; 30 | UniqueCPtr data_; 31 | }; 32 | static inline zwp_input_panel_v1 *rawPointer(ZwpInputPanelV1 *p) { 33 | return p ? static_cast(*p) : nullptr; 34 | } 35 | } // namespace fcitx::wayland 36 | #endif 37 | -------------------------------------------------------------------------------- /src/fcitx/misc_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * SPDX-FileCopyrightText: 2016-2020 CSSlayer 4 | * 5 | * SPDX-License-Identifier: LGPL-2.1-or-later 6 | * 7 | */ 8 | #ifndef _FCITX_UTILS_MISC_P_H_ 9 | #define _FCITX_UTILS_MISC_P_H_ 10 | 11 | #include 12 | #include "../fcitx-utils/misc_p.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace fcitx { 19 | 20 | static inline const fcitx::CandidateWord * 21 | nthCandidateIgnorePlaceholder(const CandidateList &candidateList, int idx) { 22 | int total = 0; 23 | if (idx < 0 || idx >= candidateList.size()) { 24 | return nullptr; 25 | } 26 | for (int i = 0, e = candidateList.size(); i < e; i++) { 27 | const auto &candidate = candidateList.candidate(i); 28 | if (candidate.isPlaceHolder()) { 29 | continue; 30 | } 31 | if (idx == total) { 32 | return &candidate; 33 | } 34 | ++total; 35 | } 36 | return nullptr; 37 | } 38 | 39 | static inline bool hasTwoKeyboardInCurrentGroup(Instance *instance) { 40 | size_t numOfKeyboard = 0; 41 | for (const auto &item : 42 | instance->inputMethodManager().currentGroup().inputMethodList()) { 43 | if (auto entry = instance->inputMethodManager().entry(item.name()); 44 | entry && entry->isKeyboard()) { 45 | ++numOfKeyboard; 46 | } 47 | if (numOfKeyboard >= 2) { 48 | return true; 49 | } 50 | } 51 | 52 | std::unordered_set groupLayouts; 53 | for (const auto &groupName : instance->inputMethodManager().groups()) { 54 | if (auto group = instance->inputMethodManager().group(groupName)) { 55 | groupLayouts.insert(group->defaultLayout()); 56 | } 57 | if (groupLayouts.size() >= 2) { 58 | return true; 59 | } 60 | } 61 | return false; 62 | } 63 | 64 | } 65 | 66 | #endif // _FCITX_UTILS_MISC_P_H_ 67 | -------------------------------------------------------------------------------- /src/inputwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_INPUTWINDOW_H_ 8 | #define _FCITX_UI_CLASSIC_INPUTWINDOW_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "fcitx/candidatelist.h" 14 | #include "fcitx/inputcontext.h" 15 | #include "common.h" 16 | #include "virtualkeyboard.h" 17 | 18 | namespace fcitx { 19 | namespace classicui { 20 | 21 | class ClassicUI; 22 | 23 | using PangoAttrListUniquePtr = UniqueCPtr; 24 | 25 | class MultilineLayout { 26 | public: 27 | MultilineLayout() = default; 28 | FCITX_INLINE_DEFINE_DEFAULT_DTOR_AND_MOVE(MultilineLayout); 29 | 30 | void contextChanged() { 31 | for (const auto &layout : lines_) { 32 | pango_layout_context_changed(layout.get()); 33 | } 34 | } 35 | int characterCount() const { 36 | int count = 0; 37 | for (const auto &layout : lines_) { 38 | count += pango_layout_get_character_count(layout.get()); 39 | } 40 | return count; 41 | } 42 | 43 | int width() const; 44 | 45 | int size() { return lines_.size(); } 46 | void render(cairo_t *cr, int x, int y, int lineHeight, bool highlight); 47 | 48 | std::vector> lines_; 49 | std::vector attrLists_; 50 | std::vector highlightAttrLists_; 51 | }; 52 | 53 | class InputWindow { 54 | public: 55 | InputWindow(ClassicUI *parent); 56 | void update(InputContext *inputContext); 57 | std::pair sizeHint(); 58 | void paint(cairo_t *cr, unsigned int width, unsigned int height); 59 | void hide(); 60 | bool visible() const { return visible_; } 61 | bool hover(int x, int y); 62 | void click(int x, int y, bool isRelease = false); 63 | void wheel(bool up); 64 | 65 | protected: 66 | void resizeCandidates(size_t n); 67 | void appendText(std::string &s, PangoAttrList *attrList, 68 | PangoAttrList *highlightAttrList, const Text &text); 69 | void insertAttr(PangoAttrList *attrList, TextFormatFlags format, int start, 70 | int end, bool highlight) const; 71 | void setTextToLayout( 72 | InputContext *inputContext, PangoLayout *layout, 73 | PangoAttrListUniquePtr *attrList, 74 | PangoAttrListUniquePtr *highlightAttrList, 75 | std::initializer_list> texts); 76 | void setTextToMultilineLayout(InputContext *inputContext, 77 | MultilineLayout &layout, const Text &text); 78 | int highlight() const; 79 | bool hasVirtualKeyboard() { return !!keyboard_; } 80 | 81 | ClassicUI *parent_; 82 | GObjectUniquePtr fontMap_; 83 | double fontMapDefaultDPI_ = 96.0; 84 | GObjectUniquePtr context_; 85 | GObjectUniquePtr upperLayout_; 86 | GObjectUniquePtr lowerLayout_; 87 | std::vector labelLayouts_; 88 | std::vector candidateLayouts_; 89 | std::vector candidateRegions_; 90 | std::unique_ptr keyboard_; 91 | TrackableObjectReference inputContext_; 92 | bool visible_ = false; 93 | int cursor_ = 0; 94 | size_t nCandidates_ = 0; 95 | bool hasPrev_ = false; 96 | bool hasNext_ = false; 97 | Rect prevRegion_; 98 | Rect nextRegion_; 99 | bool prevHovered_ = false; 100 | bool nextHovered_ = false; 101 | int candidateIndex_ = -1; 102 | CandidateLayoutHint layoutHint_ = CandidateLayoutHint::NotSet; 103 | size_t candidatesHeight_ = 0; 104 | int hoverIndex_ = -1; 105 | }; 106 | } // namespace classicui 107 | } // namespace fcitx 108 | 109 | #endif // _FCITX_UI_CLASSIC_INPUTWINDOW_H_ 110 | -------------------------------------------------------------------------------- /src/themes/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(default) 2 | -------------------------------------------------------------------------------- /src/themes/default/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB IMAGE_FILES *.png) 2 | 3 | fcitx5_translate_desktop_file(theme.conf.in theme.conf) 4 | 5 | install(FILES ${IMAGE_FILES} ${CMAKE_CURRENT_BINARY_DIR}/theme.conf DESTINATION ${FCITX_INSTALL_PKGDATADIR}/themes/default) 6 | -------------------------------------------------------------------------------- /src/themes/default/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clear-code/fcitx5-virtualkeyboard-ui/7d41746a3726f85b2f6e2f65725bc630c4fe0d93/src/themes/default/arrow.png -------------------------------------------------------------------------------- /src/themes/default/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clear-code/fcitx5-virtualkeyboard-ui/7d41746a3726f85b2f6e2f65725bc630c4fe0d93/src/themes/default/highlight.png -------------------------------------------------------------------------------- /src/themes/default/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clear-code/fcitx5-virtualkeyboard-ui/7d41746a3726f85b2f6e2f65725bc630c4fe0d93/src/themes/default/next.png -------------------------------------------------------------------------------- /src/themes/default/panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clear-code/fcitx5-virtualkeyboard-ui/7d41746a3726f85b2f6e2f65725bc630c4fe0d93/src/themes/default/panel.png -------------------------------------------------------------------------------- /src/themes/default/prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clear-code/fcitx5-virtualkeyboard-ui/7d41746a3726f85b2f6e2f65725bc630c4fe0d93/src/themes/default/prev.png -------------------------------------------------------------------------------- /src/themes/default/radio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clear-code/fcitx5-virtualkeyboard-ui/7d41746a3726f85b2f6e2f65725bc630c4fe0d93/src/themes/default/radio.png -------------------------------------------------------------------------------- /src/themes/default/theme.conf.in: -------------------------------------------------------------------------------- 1 | [Metadata] 2 | Name=Default 3 | Version=1 4 | Author=Fcitx 5 | Description=Default Theme 6 | ScaleWithDPI=True 7 | 8 | [InputPanel] 9 | Font=Sans 10 10 | NormalColor=#000000 11 | HighlightColor=#ffffff 12 | Spacing=3 13 | 14 | [InputPanel/TextMargin] 15 | Left=5 16 | Right=5 17 | Top=5 18 | Bottom=5 19 | 20 | [InputPanel/ContentMargin] 21 | Left=2 22 | Right=2 23 | Top=2 24 | Bottom=2 25 | 26 | [InputPanel/Background] 27 | Image=panel.png 28 | 29 | [InputPanel/Background/Margin] 30 | Left=2 31 | Right=2 32 | Top=2 33 | Bottom=2 34 | 35 | [InputPanel/Highlight] 36 | Image=highlight.png 37 | 38 | [InputPanel/Highlight/Margin] 39 | Left=5 40 | Right=5 41 | Top=5 42 | Bottom=5 43 | 44 | [InputPanel/PrevPage] 45 | Image=prev.png 46 | 47 | [InputPanel/PrevPage/ClickMargin] 48 | Left=5 49 | Right=5 50 | Top=4 51 | Bottom=4 52 | 53 | [InputPanel/NextPage] 54 | Image=next.png 55 | 56 | [InputPanel/NextPage/ClickMargin] 57 | Left=5 58 | Right=5 59 | Top=4 60 | Bottom=4 61 | 62 | [Menu/Background] 63 | Image=panel.png 64 | 65 | [Menu/Background/Margin] 66 | Left=2 67 | Right=2 68 | Top=2 69 | Bottom=2 70 | 71 | [Menu/ContentMargin] 72 | Left=2 73 | Right=2 74 | Top=2 75 | Bottom=2 76 | 77 | [Menu/CheckBox] 78 | Image=radio.png 79 | 80 | [Menu/SubMenu] 81 | Image=arrow.png 82 | 83 | [Menu/Highlight] 84 | Image=highlight.png 85 | 86 | [Menu/Highlight/Margin] 87 | Left=5 88 | Right=5 89 | Top=5 90 | Bottom=5 91 | 92 | [Menu/Separator] 93 | Color=#c0c0c0 94 | 95 | [Menu/CheckBox] 96 | Image=radio.png 97 | 98 | [Menu/SubMenu] 99 | Image=arrow.png 100 | 101 | [Menu/TextMargin] 102 | Left=5 103 | Right=5 104 | Top=5 105 | Bottom=5 106 | -------------------------------------------------------------------------------- /src/virtualkeyboard.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2021 daipom 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_VIRTUALKEYBOARD_H_ 8 | #define _FCITX_UI_CLASSIC_VIRTUALKEYBOARD_H_ 9 | 10 | #include "common.h" 11 | #include "virtualkeyboardi18n.h" 12 | #include 13 | #include 14 | #include "fcitx/instance.h" 15 | #include "fcitx/inputcontext.h" 16 | #include "fcitx/inputmethodmanager.h" 17 | #include "fcitx/inputmethodentry.h" 18 | #include "fcitx/userinterfacemanager.h" 19 | #include "fcitx/action.h" 20 | #include "fcitx/inputpanel.h" 21 | #include 22 | #include "fcitx-utils/log.h" 23 | 24 | namespace fcitx { 25 | namespace classicui { 26 | 27 | class VirtualKeyboard; 28 | class VirtualKey { 29 | public: 30 | using PangoAttrListUniquePtr = UniqueCPtr; 31 | static constexpr double DefaultFontSize = 22; 32 | static void addForegroundAttr(PangoAttrList *attrList, 33 | double r, double g, double b, 34 | guint start_index = 0, 35 | guint end_index = G_MAXUINT) { 36 | const auto scale = std::numeric_limits::max(); 37 | auto attr = pango_attr_foreground_new(r * scale, g * scale, b * scale); 38 | attr->start_index = start_index; 39 | attr->end_index = end_index; 40 | pango_attr_list_insert(attrList, attr); 41 | } 42 | 43 | public: 44 | virtual const char* label(VirtualKeyboard *keyboard) const = 0; 45 | virtual void click(VirtualKeyboard *keyboard, InputContext *inputContext, bool isRelease) = 0; 46 | virtual void paintLabel(VirtualKeyboard *keyboard, cairo_t *cr, PangoLayout *layout); 47 | void paintBackground(cairo_t *cr, bool highlight); 48 | 49 | void setRegion(int x, int y) { 50 | region_ 51 | .setPosition(x, y) 52 | .setSize(width_, height_); 53 | } 54 | bool contains(int x, int y) const { return region_.contains(x, y); } 55 | 56 | void setCustomLayout(double scale, bool newLine = false) { 57 | newLine_ = newLine; 58 | width_ *= scale; 59 | } 60 | 61 | void setFontColor(std::tuple colorRgb) { 62 | fontColorRgb_ = colorRgb; 63 | } 64 | 65 | void setFontSize(double size) { 66 | fontSize_ = size; 67 | } 68 | 69 | void setCustomBackgroundColor(std::tuple colorRgb) { 70 | useCustomBackgroundColor_ = true; 71 | customBackgroundColorRgb_ = colorRgb; 72 | } 73 | 74 | double width() { return width_; } 75 | double height() { return height_; } 76 | bool newLine() { return newLine_; } 77 | bool visible() { return visible_; } 78 | 79 | protected: 80 | virtual void applyFont( 81 | VirtualKeyboard *keyboard, 82 | PangoLayout *layout, 83 | PangoAttrList *attrList 84 | ); 85 | virtual void fillLayout( 86 | VirtualKeyboard *keyboard, 87 | PangoLayout *layout, 88 | PangoAttrList *attrList 89 | ); 90 | 91 | Rect region_; 92 | double fontSize_ = DefaultFontSize; 93 | std::tuple fontColorRgb_ = {0.3, 0.35, 0.4}; 94 | bool useCustomBackgroundColor_ = false; 95 | std::tuple customBackgroundColorRgb_ = {0, 0, 0}; 96 | double width_ = 60; 97 | double height_ = 50; 98 | bool newLine_ = false; 99 | bool visible_ = true; 100 | }; 101 | 102 | class VirtualKeyboard { 103 | public: 104 | VirtualKeyboard(Instance *instance, PangoContext *pangoContext); 105 | void paint(cairo_t *cr, unsigned int offsetX, unsigned int offsetY); 106 | bool click(InputContext *inputContext, int x, int y, bool isRelease); 107 | bool syncState(); 108 | void setInputContext(InputContext *inputContext) { 109 | lastInputContext_ = inputContext->watch(); 110 | } 111 | void switchLanguage(); 112 | void setCurrentInputMethod(const std::string &name); 113 | void enumerateGroup(); 114 | std::tuple getIMActionText( 115 | const std::string &name, 116 | bool getShort 117 | ); 118 | bool activateIMAction(const std::string &name); 119 | 120 | /// Some IMs needs to handle the single Shift key event, 121 | /// not only the states of the main key. 122 | /// Ex. In IMs using customXkbState such as keyboard-ru, some states of modifiers are not 123 | /// propagated. 124 | /// So it is not enough to process states of the main key in `WaylandIMInputContextV1` 125 | /// in these IMs. 126 | /// (See event implementation of 127 | /// `EventWatcherPhase::ReservedFirst` of `EventType::InputContextKeyEvent` in `Instance`.) 128 | void sendShiftModifierToIM(InputContext *inputContext, bool isRelease); 129 | 130 | bool isPreediting(); 131 | bool isSelectingCandidates(); 132 | void updateInputPanel(); 133 | 134 | std::string languageCode() const { return i18nKeyboard_->languageCode(); } 135 | std::vector> &keys() const { return i18nKeyboard_->keys(); } 136 | I18nKeyboard *i18nKeyboard() const { return i18nKeyboard_.get(); } 137 | template 138 | T *i18nKeyboard() const { 139 | static_assert(std::is_base_of::value, 140 | "type parameter of this function must derive from I18nKeyboard"); 141 | return static_cast(i18nKeyboard_.get()); 142 | } 143 | 144 | std::pair size(); 145 | unsigned int marginX() { return 15; } 146 | unsigned int marginY() { return 6; } 147 | VirtualKey *pushingKey() { return pushingKey_; } 148 | bool isShiftOn() { return isShiftOn_; } 149 | void toggleShift() { isShiftOn_ = !isShiftOn_; } 150 | 151 | const PangoFontDescription *getFontDesc(double fontSize) { 152 | int size = fontSize * PANGO_SCALE; 153 | auto context = pango_layout_get_context(pangoLayout_.get()); 154 | if (fontDescMap_.find(size) == fontDescMap_.end()) { 155 | auto origFontDesc = pango_context_get_font_description(context); 156 | auto fontDesc = pango_font_description_copy(origFontDesc); 157 | pango_font_description_set_absolute_size(fontDesc, size); 158 | fontDescMap_[size].reset(fontDesc); 159 | } 160 | return fontDescMap_[size].get(); 161 | } 162 | 163 | private: 164 | Instance *instance_; 165 | GObjectUniquePtr pangoLayout_; 166 | std::map> fontDescMap_; 167 | TrackableObjectReference lastInputContext_; 168 | 169 | std::tuple findClickedKey(int x, int y); 170 | void paintBackground(cairo_t *cr); 171 | void setI18nKeyboard(I18nKeyboard *i18nKeyboard); 172 | 173 | VirtualKey *pushingKey_ = nullptr; 174 | bool isShiftOn_ = false; 175 | std::unique_ptr i18nKeyboard_; 176 | I18nKeyboardSelector i18nKeyboardSelector_; 177 | }; 178 | 179 | } // namespace classicui 180 | } // namespace fcitx 181 | 182 | FCITX_DECLARE_LOG_CATEGORY(keyboard); 183 | 184 | #define FCITX_KEYBOARD() FCITX_LOGC(::keyboard, Debug) 185 | 186 | #endif // _FCITX_UI_CLASSIC_VIRTUALKEYBOARD_H_ 187 | -------------------------------------------------------------------------------- /src/virtualkeyboardchewing.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2022-2021 daipom 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_VIRTUALKEYBOARDCHEWING_H_ 8 | #define _FCITX_UI_CLASSIC_VIRTUALKEYBOARDCHEWING_H_ 9 | 10 | #include "virtualkeyboard.h" 11 | #include "virtualkeyboardi18n.h" 12 | #include "virtualkeygeneral.h" 13 | 14 | namespace fcitx { 15 | namespace classicui { 16 | 17 | enum class ChewingKeyboardMode { 18 | Text, 19 | Mark, 20 | }; 21 | 22 | class ChewingKeyboard : public I18nKeyboard { 23 | public: 24 | KeyboardType type() const override { return KeyboardType::Chewing; }; 25 | const char *label() const override { return "TW"; } 26 | const std::string languageCode() const override { return "zh_TW"; } 27 | void updateKeys() override; 28 | void switchMode(); 29 | ChewingKeyboardMode mode() const { return mode_; } 30 | bool isAdditionalMarkOn() const { return isAdditionalMarkOn_; } 31 | void toggleMark(); 32 | 33 | private: 34 | void setTextKeys(); 35 | void setMarkKeys(); 36 | void setAdditionalMarkKeys(); 37 | ChewingKeyboardMode mode_ = ChewingKeyboardMode::Text; 38 | bool isAdditionalMarkOn_ = false; 39 | }; 40 | 41 | class ChewingNumberKey : public NormalKey { 42 | public: 43 | ChewingNumberKey( 44 | const std::string &label, 45 | const std::string &number, 46 | uint32_t code 47 | ) : NormalKey( 48 | label, 49 | code, 50 | "", 51 | number, 52 | "" 53 | ), 54 | number_(number) {} 55 | const char* label(VirtualKeyboard *keyboard) const override; 56 | 57 | private: 58 | const std::string number_; 59 | }; 60 | 61 | class ChewingNumPadKey : public NumberKey { 62 | public: 63 | ChewingNumPadKey(const std::string &number) : NumberKey(number) {} 64 | void click(VirtualKeyboard *keyboard, InputContext *inputContext, bool isRelease) override; 65 | }; 66 | 67 | class ChewingEnterKey : public EnterKey { 68 | public: 69 | ChewingEnterKey() { 70 | setFontSize(18); 71 | } 72 | const char* label(VirtualKeyboard *keyboard) const override; 73 | void click(VirtualKeyboard *keyboard, InputContext *inputContext, bool isRelease) override; 74 | 75 | private: 76 | typedef EnterKey super; 77 | }; 78 | 79 | class ChewingSpaceKey : public SpaceKey { 80 | public: 81 | ChewingSpaceKey() { 82 | setFontSize(18); 83 | } 84 | const char* label(VirtualKeyboard *keyboard) const override; 85 | }; 86 | 87 | class ChewingModeSwitchKey : public SwitchKey { 88 | public: 89 | ChewingModeSwitchKey() : SwitchKey() {} 90 | const char* label(VirtualKeyboard *) const override { return "注#"; } 91 | 92 | protected: 93 | int numberOfStates() const override { return 2; } 94 | const char *stateLabel(int index) const override { 95 | return index == 0 ? "注" : "#"; 96 | } 97 | void switchState(VirtualKeyboard *keyboard, InputContext *inputContext) override; 98 | int currentIndex(VirtualKeyboard *keyboard) override; 99 | }; 100 | 101 | class ChewingMarkToggleKey : public ToggleKey { 102 | public: 103 | ChewingMarkToggleKey() { 104 | setFontSize(18); 105 | } 106 | const char* label(VirtualKeyboard *) const override { return "更多"; } 107 | 108 | protected: 109 | void toggle(VirtualKeyboard *keyboard, InputContext *inputContext) override; 110 | bool isOn(VirtualKeyboard *keyboard) override; 111 | }; 112 | 113 | } // namespace classicui 114 | } // namespace fcitx 115 | 116 | #endif // _FCITX_UI_CLASSIC_VIRTUALKEYBOARDCHEWING_H_ 117 | -------------------------------------------------------------------------------- /src/virtualkeyboardhangul.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2021 daipom 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_VIRTUALKEYBOARDHANGUL_H_ 8 | #define _FCITX_UI_CLASSIC_VIRTUALKEYBOARDHANGUL_H_ 9 | 10 | #include "virtualkeyboard.h" 11 | #include "virtualkeyboardi18n.h" 12 | #include "virtualkeygeneral.h" 13 | 14 | namespace fcitx { 15 | namespace classicui { 16 | 17 | enum class HangulKeyboardMode { 18 | Text, 19 | Mark, 20 | }; 21 | 22 | class HangulKeyboard : public I18nKeyboard { 23 | public: 24 | KeyboardType type() const override { return KeyboardType::Hangul; }; 25 | const char *label() const override { return "KR"; } 26 | const std::string languageCode() const override { return "ko"; } 27 | void updateKeys() override; 28 | void switchMode(); 29 | HangulKeyboardMode mode() const { return mode_; } 30 | 31 | private: 32 | void setTextKeys(); 33 | void setMarkKeys(); 34 | HangulKeyboardMode mode_ = HangulKeyboardMode::Text; 35 | }; 36 | 37 | class HangulModeSwitchKey : public SwitchKey { 38 | public: 39 | HangulModeSwitchKey() : SwitchKey() {} 40 | const char* label(VirtualKeyboard *) const override { return "한#"; } 41 | 42 | protected: 43 | int numberOfStates() const override { return 2; } 44 | const char *stateLabel(int index) const override { 45 | return index == 0 ? "한" : "#"; 46 | } 47 | void switchState(VirtualKeyboard *keyboard, InputContext *inputContext) override; 48 | int currentIndex(VirtualKeyboard *keyboard) override; 49 | }; 50 | 51 | } // namespace classicui 52 | } // namespace fcitx 53 | 54 | #endif // _FCITX_UI_CLASSIC_VIRTUALKEYBOARDHANGUL_H_ 55 | -------------------------------------------------------------------------------- /src/virtualkeyboardi18n.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2021 daipom 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "fcitx-utils/stringutils.h" 8 | #include "virtualkeyboardi18n.h" 9 | #include "virtualkeyboard.h" 10 | #include "virtualkeyboardus.h" 11 | #include "virtualkeyboardanthy.h" 12 | #include "virtualkeyboardpinyin.h" 13 | #include "virtualkeyboardrussian.h" 14 | #include "virtualkeyboardhangul.h" 15 | #include "virtualkeyboardchewing.h" 16 | 17 | namespace fcitx::classicui { 18 | 19 | std::tuple I18nKeyboardSelector::selectByType(KeyboardType type) { 20 | // Add case here when adding new keyboard type. 21 | switch (type) { 22 | case KeyboardType::Us: 23 | return {new UsKeyboard(), true}; 24 | case KeyboardType::Anthy: 25 | return {new AnthyKeyboard(), true}; 26 | case KeyboardType::Pinyin: 27 | return {new PinyinKeyboard(), true}; 28 | case KeyboardType::Russian: 29 | return {new RussianKeyboard(), true}; 30 | case KeyboardType::Hangul: 31 | return {new HangulKeyboard(), true}; 32 | case KeyboardType::Chewing: 33 | return {new ChewingKeyboard(), true}; 34 | default: 35 | break; 36 | } 37 | return {new NullI18nKeyboard(), false}; 38 | } 39 | 40 | std::tuple I18nKeyboardSelector::select( 41 | std::vector &inputMethodItems 42 | ) { 43 | // First, select from addon imes such as `anthy` or `pinyin`. 44 | for (const auto &ime : inputMethodItems) 45 | { 46 | auto isSimpleKeyboard = stringutils::startsWith(ime.name(), "keyboard-"); 47 | if (isSimpleKeyboard) continue; 48 | 49 | if (canSelect(inputMethodItems, ime.name())) { 50 | return selectByType(getTypeByName(ime.name())); 51 | } 52 | } 53 | 54 | // Second, select from simple keyboards such as `keyboard-us`. 55 | for (const auto &ime : inputMethodItems) 56 | { 57 | auto isSimpleKeyboard = stringutils::startsWith(ime.name(), "keyboard-"); 58 | if (!isSimpleKeyboard) continue; 59 | 60 | if (canSelect(inputMethodItems, ime.name())) { 61 | return selectByType(getTypeByName(ime.name())); 62 | } 63 | } 64 | 65 | return selectByType(KeyboardType::Unknown); 66 | } 67 | 68 | KeyboardType I18nKeyboardSelector::getTypeByName(const std::string &inputMethodName) { 69 | for (const auto &[type, name] : imeNames) 70 | { 71 | if (inputMethodName == name) { 72 | return type; 73 | } 74 | } 75 | return KeyboardType::Unknown; 76 | } 77 | 78 | bool I18nKeyboardSelector::canSelect( 79 | std::vector &allItems, 80 | const std::string &inputMethodNameToSelect 81 | ) { 82 | auto type = getTypeByName(inputMethodNameToSelect); 83 | if (type == KeyboardType::Unknown) return false; 84 | 85 | auto [keyboard, hasFound] = selectByType(type); 86 | if (!hasFound) return false; 87 | return keyboard->checkOtherNecessaryImesExist(allItems); 88 | } 89 | 90 | bool I18nKeyboard::checkOtherNecessaryImesExist( 91 | std::vector &allItems 92 | ) { 93 | for (const auto &anotherIme : otherNecessaryImeList()) 94 | { 95 | if (!containInputMethod(allItems, anotherIme)) { 96 | return false; 97 | } 98 | } 99 | return true; 100 | } 101 | 102 | bool I18nKeyboard::containInputMethod( 103 | std::vector &items, 104 | const std::string &name 105 | ) { 106 | auto iter = std::find_if(items.begin(), items.end(), 107 | [&name](const InputMethodGroupItem &item) { 108 | return item.name() == name; 109 | }); 110 | return iter != items.end(); 111 | } 112 | 113 | void I18nKeyboard::syncState( 114 | VirtualKeyboard *keyboard, 115 | const std::string ¤tInputMethodName 116 | ) { 117 | // Always fix to this keyboard's input-method 118 | 119 | // Note: The 0th item in each group is usually set to a simple keyboard 120 | // such as `keyboard-us`, but most virtual keyboards using IME add-ons 121 | // don't use the 0th item and use only the 1th item, which is the IME for 122 | // the keyboard's language. 123 | // Such keyboards do not normally select the 0th item, but it is possible 124 | // that the 0th item is selected at the initiation of Fcitx5, so this process 125 | // is necessary. 126 | // On the other hand, for keyboards like AnthyKeyboard that have the function of 127 | // switching items, this process should not be used and should be overridden. 128 | 129 | if (imeNames[type()] == currentInputMethodName) { 130 | return; 131 | } 132 | keyboard->setCurrentInputMethod(imeNames[type()]); 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/virtualkeyboardi18n.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2021 daipom 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_VIRTUALKEYBOARDI18N_H_ 8 | #define _FCITX_UI_CLASSIC_VIRTUALKEYBOARDI18N_H_ 9 | 10 | #include "common.h" 11 | #include "fcitx/inputmethodmanager.h" 12 | 13 | namespace fcitx { 14 | namespace classicui { 15 | 16 | enum class KeyboardType { 17 | Unknown, 18 | Us, 19 | Anthy, 20 | Pinyin, 21 | Russian, 22 | Hangul, 23 | Chewing, 24 | }; 25 | 26 | static std::map imeNames = { 27 | {KeyboardType::Unknown, ""}, 28 | {KeyboardType::Us, "keyboard-us"}, 29 | {KeyboardType::Anthy, "anthy"}, 30 | {KeyboardType::Pinyin, "pinyin"}, 31 | {KeyboardType::Russian, "keyboard-ru"}, 32 | {KeyboardType::Hangul, "hangul"}, 33 | {KeyboardType::Chewing, "chewing"}, 34 | }; 35 | 36 | class VirtualKey; 37 | class VirtualKeyboard; 38 | class I18nKeyboard { 39 | public: 40 | virtual KeyboardType type() const = 0; 41 | virtual const char *label() const = 0; 42 | virtual void updateKeys() = 0; 43 | virtual const std::string languageCode() const { return ""; } 44 | 45 | /// Override this if you need to do language-specific sync-process 46 | /// (especially if you need to switch items within one group as in AnthyKeyboard). 47 | virtual void syncState( 48 | VirtualKeyboard *keyboard, 49 | const std::string ¤tInputMethodName 50 | ); 51 | 52 | std::vector> &keys() { return keys_; } 53 | bool checkOtherNecessaryImesExist(std::vector &allItems); 54 | protected: 55 | virtual std::vector otherNecessaryImeList() { return {}; } 56 | std::vector> keys_; 57 | private: 58 | bool containInputMethod(std::vector &items, 59 | const std::string &name); 60 | }; 61 | 62 | class I18nKeyboardSelector { 63 | public: 64 | std::tuple select(std::vector &inputMethodItems); 65 | private: 66 | KeyboardType getTypeByName(const std::string &inputMethodName); 67 | std::tuple selectByType(KeyboardType type); 68 | bool canSelect( 69 | std::vector &allItems, 70 | const std::string &inputMethodNameToSelect 71 | ); 72 | }; 73 | 74 | class NullI18nKeyboard : public I18nKeyboard { 75 | public: 76 | KeyboardType type() const override { return KeyboardType::Unknown; } 77 | const char *label() const override { return "X"; } 78 | void updateKeys() override { 79 | // do nothing 80 | } 81 | }; 82 | 83 | } // namespace classicui 84 | } // namespace fcitx 85 | 86 | #endif // _FCITX_UI_CLASSIC_VIRTUALKEYBOARDI18N_H_ 87 | -------------------------------------------------------------------------------- /src/virtualkeyboardpinyin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2021 daipom 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_VIRTUALKEYBOARDPINYIN_H_ 8 | #define _FCITX_UI_CLASSIC_VIRTUALKEYBOARDPINYIN_H_ 9 | 10 | #include "virtualkeyboard.h" 11 | #include "virtualkeyboardi18n.h" 12 | #include "virtualkeygeneral.h" 13 | 14 | namespace fcitx { 15 | namespace classicui { 16 | 17 | enum class PinyinKeyboardMode { 18 | Text, 19 | Mark, 20 | }; 21 | 22 | class PinyinKeyboard : public I18nKeyboard { 23 | public: 24 | KeyboardType type() const override { return KeyboardType::Pinyin; }; 25 | const char *label() const override { return "CH"; } 26 | const std::string languageCode() const override { return "zh_CN"; } 27 | void updateKeys() override; 28 | void switchMode(); 29 | PinyinKeyboardMode mode() const { return mode_; } 30 | bool isAdditionalMarkOn() const { return isAdditionalMarkOn_; } 31 | void toggleMark(); 32 | 33 | private: 34 | void setTextKeys(); 35 | void setMarkKeys(); 36 | void setAdditionalMarkKeys(); 37 | PinyinKeyboardMode mode_ = PinyinKeyboardMode::Text; 38 | bool isAdditionalMarkOn_ = false; 39 | }; 40 | 41 | class PinyinSpaceKey : public SpaceKey { 42 | public: 43 | PinyinSpaceKey() { 44 | setFontSize(18); 45 | } 46 | const char* label(VirtualKeyboard *keyboard) const override; 47 | }; 48 | 49 | class PinyinEnterKey : public EnterKey { 50 | public: 51 | PinyinEnterKey() { 52 | setFontSize(18); 53 | } 54 | const char* label(VirtualKeyboard *keyboard) const override; 55 | }; 56 | 57 | class PinyinModeSwitchKey : public SwitchKey { 58 | public: 59 | PinyinModeSwitchKey() : SwitchKey() {} 60 | const char* label(VirtualKeyboard *) const override { return "A#"; } 61 | 62 | protected: 63 | int numberOfStates() const override { return 2; } 64 | const char *stateLabel(int index) const override { 65 | return index == 0 ? "A" : "#"; 66 | } 67 | void switchState(VirtualKeyboard *keyboard, InputContext *inputContext) override; 68 | int currentIndex(VirtualKeyboard *keyboard) override; 69 | }; 70 | 71 | class PinyinMarkToggleKey : public ToggleKey { 72 | public: 73 | PinyinMarkToggleKey() { 74 | setFontSize(18); 75 | } 76 | const char* label(VirtualKeyboard *) const override { return "更多"; } 77 | 78 | protected: 79 | void toggle(VirtualKeyboard *keyboard, InputContext *inputContext) override; 80 | bool isOn(VirtualKeyboard *keyboard) override; 81 | }; 82 | 83 | } // namespace classicui 84 | } // namespace fcitx 85 | 86 | #endif // _FCITX_UI_CLASSIC_VIRTUALKEYBOARDPINYIN_H_ 87 | -------------------------------------------------------------------------------- /src/virtualkeyboardrussian.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2021 daipom 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_VIRTUALKEYBOARDRUSSIAN_H_ 8 | #define _FCITX_UI_CLASSIC_VIRTUALKEYBOARDRUSSIAN_H_ 9 | 10 | #include "virtualkeyboard.h" 11 | #include "virtualkeyboardi18n.h" 12 | #include "virtualkeygeneral.h" 13 | 14 | namespace fcitx { 15 | namespace classicui { 16 | 17 | enum class RussianKeyboardMode { 18 | Text, 19 | Mark, 20 | }; 21 | 22 | class RussianKeyboard : public I18nKeyboard { 23 | public: 24 | KeyboardType type() const override { return KeyboardType::Russian; }; 25 | const char *label() const override { return "RU"; } 26 | const std::string languageCode() const override { return "ru"; } 27 | void updateKeys() override; 28 | void switchMode(); 29 | RussianKeyboardMode mode() const { return mode_; } 30 | 31 | private: 32 | void setCyrillicTextKeys(); 33 | void setMarkKeys(); 34 | RussianKeyboardMode mode_ = RussianKeyboardMode::Text; 35 | }; 36 | 37 | class RussianDummyKey : public DummyKey { 38 | public: 39 | RussianDummyKey(double width) : DummyKey() { 40 | width_ = width; 41 | } 42 | }; 43 | 44 | class RussianShiftToggleKey : public ShiftToggleKey { 45 | public: 46 | RussianShiftToggleKey() : ShiftToggleKey() { 47 | width_ = 40; 48 | } 49 | }; 50 | 51 | class RussianNormalKey : public NormalKey { 52 | public: 53 | RussianNormalKey( 54 | const std::string &label, 55 | uint32_t code, 56 | const std::string &upperLabel 57 | ) : NormalKey(label, code, upperLabel, false) { 58 | width_ = 50; 59 | } 60 | }; 61 | 62 | class RussianModeSwitchKey : public SwitchKey { 63 | public: 64 | RussianModeSwitchKey() : SwitchKey() {} 65 | const char* label(VirtualKeyboard *) const override { return "A#"; } 66 | 67 | protected: 68 | int numberOfStates() const override { return 2; } 69 | const char *stateLabel(int index) const override { 70 | return index == 0 ? "A" : "#"; 71 | } 72 | void switchState(VirtualKeyboard *keyboard, InputContext *inputContext) override; 73 | int currentIndex(VirtualKeyboard *keyboard) override; 74 | }; 75 | 76 | } // namespace classicui 77 | } // namespace fcitx 78 | 79 | #endif // _FCITX_UI_CLASSIC_VIRTUALKEYBOARDRUSSIAN_H_ 80 | -------------------------------------------------------------------------------- /src/virtualkeyboardui.conf.in.in: -------------------------------------------------------------------------------- 1 | [Addon] 2 | Name=Virtual Keyboard User Inteface 3 | Type=SharedLibrary 4 | Library=libvirtualkeyboardui 5 | Category=UI 6 | Version=@PROJECT_VERSION@ 7 | OnDemand=True 8 | Configurable=True 9 | 10 | [Addon/Dependencies] 11 | 0=core:@REQUIRED_FCITX5_VERSION@ 12 | 13 | [Addon/OptionalDependencies] 14 | 0=xcb 15 | 1=wayland 16 | 2=notificationitem 17 | -------------------------------------------------------------------------------- /src/virtualkeyboardus.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2021 daipom 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_VIRTUALKEYBOARDUS_H_ 8 | #define _FCITX_UI_CLASSIC_VIRTUALKEYBOARDUS_H_ 9 | 10 | #include "virtualkeyboard.h" 11 | #include "virtualkeyboardi18n.h" 12 | #include "virtualkeygeneral.h" 13 | 14 | namespace fcitx { 15 | namespace classicui { 16 | 17 | enum class UsKeyboardMode { 18 | Text, 19 | Mark, 20 | }; 21 | 22 | class UsKeyboard : public I18nKeyboard { 23 | public: 24 | KeyboardType type() const override { return KeyboardType::Us; }; 25 | const char *label() const override { return "US"; } 26 | const std::string languageCode() const override { return "us"; } 27 | void updateKeys() override; 28 | void switchMode(); 29 | UsKeyboardMode mode() const { return mode_; } 30 | 31 | private: 32 | void setTextKeys(); 33 | void setMarkKeys(); 34 | UsKeyboardMode mode_ = UsKeyboardMode::Text; 35 | }; 36 | 37 | class UsModeSwitchKey : public SwitchKey { 38 | public: 39 | UsModeSwitchKey() : SwitchKey() {} 40 | const char* label(VirtualKeyboard *) const override { return "A#"; } 41 | 42 | protected: 43 | int numberOfStates() const override { return 2; } 44 | const char *stateLabel(int index) const override { 45 | return index == 0 ? "A" : "#"; 46 | } 47 | void switchState(VirtualKeyboard *keyboard, InputContext *inputContext) override; 48 | int currentIndex(VirtualKeyboard *keyboard) override; 49 | }; 50 | 51 | } // namespace classicui 52 | } // namespace fcitx 53 | 54 | #endif // _FCITX_UI_CLASSIC_VIRTUALKEYBOARDUS_H_ 55 | -------------------------------------------------------------------------------- /src/virtualkeygeneral.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2021 daipom 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "virtualkeygeneral.h" 8 | #include 9 | 10 | namespace fcitx::classicui { 11 | 12 | const char* NormalKey::label(VirtualKeyboard *keyboard) const { 13 | if (!keyboard->isShiftOn() || upperLabel_.empty()) { 14 | return label_.c_str(); 15 | } 16 | return upperLabel_.c_str(); 17 | } 18 | 19 | void NormalKey::click(VirtualKeyboard *keyboard, InputContext *inputContext, bool isRelease) { 20 | FCITX_KEYBOARD() << "NormalKey pushed: " << label(keyboard); 21 | 22 | if (keyboard->isShiftOn()) { 23 | keyboard->sendShiftModifierToIM(inputContext, false); 24 | } 25 | 26 | auto event = KeyEvent(inputContext, convert(keyboard->isShiftOn()), isRelease); 27 | inputContext->virtualKeyEvent(event); 28 | 29 | if (keyboard->isShiftOn()) { 30 | keyboard->sendShiftModifierToIM(inputContext, true); 31 | } 32 | } 33 | 34 | const char* MarkKey::label(VirtualKeyboard *) const { 35 | return label_.c_str(); 36 | } 37 | 38 | void MarkKey::click(VirtualKeyboard *keyboard, InputContext *inputContext, bool isRelease) { 39 | FCITX_KEYBOARD() << "MarkKey pushed: " << label(keyboard); 40 | 41 | if (sendKeyEventFirst()) { 42 | if (withShift_) { 43 | keyboard->sendShiftModifierToIM(inputContext, false); 44 | } 45 | 46 | auto event = KeyEvent(inputContext, convert(withShift_), isRelease); 47 | const auto hasProcessedInIME = inputContext->keyEvent(event); 48 | 49 | if (withShift_) { 50 | keyboard->sendShiftModifierToIM(inputContext, true); 51 | } 52 | 53 | if (hasProcessedInIME) return; 54 | } 55 | 56 | if (isRelease) { 57 | return; 58 | } 59 | 60 | inputContext->commitString(label(keyboard)); 61 | } 62 | 63 | const char* NumberKey::label(VirtualKeyboard *) const { 64 | return name_.c_str(); 65 | } 66 | 67 | void NumberKey::click(VirtualKeyboard *keyboard, InputContext *inputContext, bool isRelease) { 68 | FCITX_KEYBOARD() << "NumberKey pushed: " << label(keyboard); 69 | 70 | auto event = fcitx::KeyEvent(inputContext, convert(false), isRelease); 71 | const auto hasProcessedInIME = inputContext->keyEvent(event); 72 | if (hasProcessedInIME || isRelease) return; 73 | 74 | inputContext->commitString(label(keyboard)); 75 | } 76 | 77 | void ToggleKey::click(VirtualKeyboard *keyboard, InputContext *inputContext, bool isRelease) { 78 | FCITX_KEYBOARD() << "ToggleKey pushed: " << label(keyboard); 79 | // This may be used for changing key layouts. 80 | // Changin key layouts must be executed on key-release, 81 | // because VirtualKeyboard has `pushingKey_` pointer. 82 | if (!isRelease) { 83 | return; 84 | } 85 | toggle(keyboard, inputContext); 86 | } 87 | 88 | void ToggleKey::fillLayout( 89 | VirtualKeyboard *keyboard, 90 | PangoLayout *layout, 91 | PangoAttrList *attrList 92 | ) { 93 | if (isOn(keyboard)) { 94 | addForegroundAttr(attrList, 0.2, 0.7, 0.6); 95 | } else { 96 | addForegroundAttr(attrList, 0.8, 0.8, 0.8); 97 | } 98 | pango_layout_set_text(layout, label(keyboard), -1); 99 | } 100 | 101 | void ShiftToggleKey::toggle(VirtualKeyboard *keyboard, InputContext *) { 102 | keyboard->toggleShift(); 103 | } 104 | 105 | bool ShiftToggleKey::isOn(VirtualKeyboard *keyboard) { 106 | return keyboard->isShiftOn(); 107 | } 108 | 109 | void SwitchKey::click(VirtualKeyboard *keyboard, InputContext *inputContext, bool isRelease) { 110 | FCITX_KEYBOARD() << "SwitchKey pushed: " << label(keyboard); 111 | 112 | // This may be used for changing key layouts. 113 | // Changin key layouts must be executed on key-release, 114 | // because VirtualKeyboard has `pushingKey_` pointer. 115 | if (!isRelease) { 116 | return; 117 | } 118 | 119 | switchState(keyboard, inputContext); 120 | } 121 | 122 | void SwitchKey::fillLayout( 123 | VirtualKeyboard *keyboard, 124 | PangoLayout *layout, 125 | PangoAttrList *attrList 126 | ) { 127 | std::string label; 128 | 129 | for (int i = 0; i < numberOfStates(); i++) 130 | { 131 | int end_index = label.size() + strlen(stateLabel(i)); 132 | if (i == currentIndex(keyboard)) { 133 | addForegroundAttr(attrList, 0.2, 0.7, 0.6, label.size(), end_index); 134 | } else { 135 | addForegroundAttr(attrList, 0.8, 0.8, 0.8, label.size(), end_index); 136 | } 137 | label.append(stateLabel(i)); 138 | } 139 | 140 | pango_layout_set_text(layout, label.c_str(), -1); 141 | } 142 | 143 | const char *LanguageSwitchKey::label(VirtualKeyboard *keyboard) const { 144 | return keyboard->i18nKeyboard()->label(); 145 | } 146 | 147 | void LanguageSwitchKey::click(VirtualKeyboard *keyboard, InputContext *, bool isRelease) { 148 | FCITX_KEYBOARD() << "LanguageSwitchKey pushed"; 149 | if (!isRelease) { 150 | return; 151 | } 152 | 153 | // check this key has been pushed and released in order to prevent miss click this key. 154 | if (dynamic_cast(keyboard->pushingKey())) { 155 | keyboard->switchLanguage(); 156 | } 157 | 158 | keyboard->updateInputPanel(); 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /src/waylandeglwindow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "config.h" 8 | 9 | #ifdef CAIRO_EGL_FOUND 10 | 11 | #include 12 | #include 13 | #include "waylandeglwindow.h" 14 | #include "wl_callback.h" 15 | 16 | namespace fcitx { 17 | namespace classicui { 18 | WaylandEGLWindow::WaylandEGLWindow(WaylandUI *ui) 19 | : WaylandWindow(ui), window_(nullptr), cairoSurface_(nullptr) {} 20 | 21 | WaylandEGLWindow::~WaylandEGLWindow() { destroyWindow(); } 22 | 23 | void WaylandEGLWindow::createWindow() { WaylandWindow::createWindow(); } 24 | 25 | void WaylandEGLWindow::destroyWindow() { 26 | hide(); 27 | WaylandWindow::destroyWindow(); 28 | } 29 | 30 | cairo_surface_t *WaylandEGLWindow::prerender() { 31 | if (width_ == 0 || height_ == 0) { 32 | hide(); 33 | return nullptr; 34 | } 35 | 36 | auto bufferWidth = width_ * scale_; 37 | auto bufferHeight = height_ * scale_; 38 | if (!window_) { 39 | window_.reset( 40 | wl_egl_window_create(*surface_, bufferWidth, bufferHeight)); 41 | } 42 | if (window_ && !eglSurface_) { 43 | eglSurface_ = ui_->createEGLSurface(window_.get(), nullptr); 44 | } 45 | if (eglSurface_ && !cairoSurface_) { 46 | cairoSurface_.reset( 47 | ui_->createEGLCairoSurface(eglSurface_, bufferWidth, bufferHeight)); 48 | } 49 | if (!cairoSurface_) { 50 | return nullptr; 51 | } 52 | int width, height; 53 | wl_egl_window_get_attached_size(window_.get(), &width, &height); 54 | if (width != static_cast(bufferWidth) || 55 | height != static_cast(bufferHeight)) { 56 | wl_egl_window_resize(window_.get(), bufferWidth, bufferHeight, 0, 0); 57 | } 58 | cairo_gl_surface_set_size(cairoSurface_.get(), bufferWidth, bufferHeight); 59 | if (cairo_surface_status(cairoSurface_.get()) != CAIRO_STATUS_SUCCESS) { 60 | return nullptr; 61 | } 62 | 63 | return cairoSurface_.get(); 64 | } 65 | 66 | void WaylandEGLWindow::render() { 67 | if (cairo_surface_status(cairoSurface_.get()) != CAIRO_STATUS_SUCCESS) { 68 | return; 69 | } 70 | cairo_gl_surface_swapbuffers(cairoSurface_.get()); 71 | callback_.reset(surface_->frame()); 72 | callback_->done().connect([this](uint32_t) { callback_.reset(); }); 73 | surface_->setBufferScale(scale_); 74 | surface_->commit(); 75 | } 76 | 77 | void WaylandEGLWindow::hide() { 78 | cairoSurface_.reset(); 79 | if (eglSurface_) { 80 | ui_->destroyEGLSurface(eglSurface_); 81 | eglSurface_ = nullptr; 82 | } 83 | window_.reset(); 84 | surface_->attach(nullptr, 0, 0); 85 | surface_->commit(); 86 | } 87 | } // namespace classicui 88 | } // namespace fcitx 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /src/waylandeglwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_WAYLANDEGLWINDOW_H_ 8 | #define _FCITX_UI_CLASSIC_WAYLANDEGLWINDOW_H_ 9 | 10 | #include "config.h" 11 | 12 | #ifdef CAIRO_EGL_FOUND 13 | 14 | #include 15 | #include 16 | #include "waylandui.h" 17 | #include "waylandwindow.h" 18 | 19 | namespace fcitx { 20 | namespace classicui { 21 | 22 | class WaylandEGLWindow : public WaylandWindow { 23 | public: 24 | WaylandEGLWindow(WaylandUI *ui); 25 | ~WaylandEGLWindow(); 26 | 27 | void createWindow() override; 28 | void destroyWindow() override; 29 | 30 | cairo_surface_t *prerender() override; 31 | void render() override; 32 | void hide() override; 33 | 34 | private: 35 | UniqueCPtr window_; 36 | EGLSurface eglSurface_ = nullptr; 37 | UniqueCPtr cairoSurface_; 38 | std::unique_ptr callback_; 39 | }; 40 | } // namespace classicui 41 | } // namespace fcitx 42 | 43 | #endif 44 | 45 | #endif // _FCITX_UI_CLASSIC_WAYLANDEGLWINDOW_H_ 46 | -------------------------------------------------------------------------------- /src/waylandinputwindow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "waylandinputwindow.h" 8 | #include "waylandui.h" 9 | #include "waylandwindow.h" 10 | #include "zwp_input_panel_v1.h" 11 | 12 | #ifdef __linux__ 13 | #include 14 | #elif __FreeBSD__ 15 | #include 16 | #else 17 | #define BTN_LEFT 0x110 18 | #endif 19 | 20 | namespace fcitx::classicui { 21 | 22 | WaylandInputWindow::WaylandInputWindow(WaylandUI *ui) 23 | : InputWindow(ui->parent()), ui_(ui), window_(ui->newWindow()) { 24 | window_->createWindow(); 25 | window_->repaint().connect([this]() { 26 | if (auto *ic = repaintIC_.get()) { 27 | if (ic->hasFocus()) { 28 | update(ic); 29 | } 30 | } 31 | }); 32 | window_->click().connect([this](int x, int y, uint32_t button, 33 | uint32_t state) { 34 | if (hasVirtualKeyboard()) { 35 | // Work around to correct the position of the pointer. 36 | // Because the position is updated only on hover(), x & y points old 37 | // position when the window size is changed while clicking. 38 | // See also waylandpointer.cpp for more detail. 39 | // The window type is assumed to be `toplevel` of 40 | // `zwp_input_panel_surface_v1` which is always placed at certer- 41 | // bottom of the screen. Please note that this correction is wrong 42 | // for the window type `overlay_panel`. 43 | if (window_->width() != widthAtPrevPointerEvent_) 44 | x += (window_->width() - widthAtPrevPointerEvent_) / 2; 45 | if (window_->height() != heightAtPrevPointerEvent_) 46 | y += window_->height() - heightAtPrevPointerEvent_; 47 | } 48 | if (button == BTN_LEFT) { 49 | click(x, y, state == WL_POINTER_BUTTON_STATE_RELEASED); 50 | repaint(); 51 | } 52 | }); 53 | window_->hover().connect([this](int x, int y) { 54 | widthAtPrevPointerEvent_ = window_->width(); 55 | heightAtPrevPointerEvent_ = window_->height(); 56 | if (hover(x, y)) { 57 | repaint(); 58 | } 59 | }); 60 | window_->leave().connect([this]() { 61 | widthAtPrevPointerEvent_ = 0; 62 | heightAtPrevPointerEvent_ = 0; 63 | if (hover(-1, -1)) { 64 | repaint(); 65 | } 66 | }); 67 | window_->touchDown().connect([this](int x, int y) { 68 | widthAtPrevPointerEvent_ = window_->width(); 69 | heightAtPrevPointerEvent_ = window_->height(); 70 | click(x, y, false); 71 | repaint(); 72 | }); 73 | window_->touchUp().connect([this](int x, int y) { 74 | if (hasVirtualKeyboard()) { 75 | // Ditto 76 | if (window_->width() != widthAtPrevPointerEvent_) 77 | x += (window_->width() - widthAtPrevPointerEvent_) / 2; 78 | if (window_->height() != heightAtPrevPointerEvent_) 79 | y += window_->height() - heightAtPrevPointerEvent_; 80 | } 81 | click(x, y, true); 82 | repaint(); 83 | }); 84 | window_->axis().connect([this](int, int, uint32_t axis, wl_fixed_t value) { 85 | if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) { 86 | return; 87 | } 88 | scroll_ += value; 89 | bool triggered = false; 90 | while (scroll_ >= 2560) { 91 | scroll_ -= 2560; 92 | wheel(/*up=*/false); 93 | triggered = true; 94 | } 95 | while (scroll_ <= -2560) { 96 | scroll_ += 2560; 97 | wheel(/*up=*/true); 98 | triggered = true; 99 | } 100 | if (triggered) { 101 | repaint(); 102 | } 103 | }); 104 | initPanel(); 105 | } 106 | 107 | void WaylandInputWindow::initPanel() { 108 | if (!window_->surface()) { 109 | window_->createWindow(); 110 | return; 111 | } 112 | } 113 | 114 | void WaylandInputWindow::resetPanel() { panelSurface_.reset(); } 115 | 116 | void WaylandInputWindow::update(fcitx::InputContext *ic) { 117 | const auto oldVisible = visible(); 118 | InputWindow::update(ic); 119 | 120 | if (!oldVisible && !visible()) { 121 | return; 122 | } 123 | 124 | if (!visible()) { 125 | window_->hide(); 126 | panelSurface_.reset(); 127 | window_->destroyWindow(); 128 | return; 129 | } 130 | 131 | assert(!visible() || ic != nullptr); 132 | initPanel(); 133 | if (ic->frontend() == std::string_view("wayland")) { 134 | auto panel = ui_->display()->getGlobal(); 135 | if (!panel) { 136 | return; 137 | } 138 | if (!panelSurface_) { 139 | panelSurface_.reset( 140 | panel->getInputPanelSurface(window_->surface())); 141 | if (hasVirtualKeyboard()) 142 | panelSurface_->setToplevel(ui_->display()->output(), 0); 143 | else 144 | panelSurface_->setOverlayPanel(); 145 | } 146 | } 147 | if (!panelSurface_) { 148 | return; 149 | } 150 | auto pair = sizeHint(); 151 | int width = pair.first, height = pair.second; 152 | 153 | if (width != window_->width() || height != window_->height()) { 154 | window_->resize(width, height); 155 | } 156 | 157 | if (auto *surface = window_->prerender()) { 158 | cairo_t *c = cairo_create(surface); 159 | cairo_scale(c, window_->scale(), window_->scale()); 160 | paint(c, width, height); 161 | cairo_destroy(c); 162 | window_->render(); 163 | } else { 164 | repaintIC_ = ic->watch(); 165 | } 166 | } 167 | 168 | void WaylandInputWindow::repaint() { 169 | if (!visible()) { 170 | return; 171 | } 172 | 173 | if (auto *surface = window_->prerender()) { 174 | cairo_t *c = cairo_create(surface); 175 | cairo_scale(c, window_->scale(), window_->scale()); 176 | paint(c, window_->width(), window_->height()); 177 | cairo_destroy(c); 178 | window_->render(); 179 | } 180 | } 181 | 182 | } // namespace fcitx::classicui 183 | -------------------------------------------------------------------------------- /src/waylandinputwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_WAYLANDINPUTWINDOW_H_ 8 | #define _FCITX_UI_CLASSIC_WAYLANDINPUTWINDOW_H_ 9 | 10 | #include "inputwindow.h" 11 | #include "zwp_input_panel_surface_v1.h" 12 | 13 | namespace fcitx { 14 | namespace classicui { 15 | 16 | class WaylandUI; 17 | class WaylandWindow; 18 | 19 | class WaylandInputWindow : public InputWindow { 20 | public: 21 | WaylandInputWindow(WaylandUI *ui); 22 | 23 | void initPanel(); 24 | void resetPanel(); 25 | void update(InputContext *ic); 26 | void repaint(); 27 | 28 | private: 29 | WaylandUI *ui_; 30 | wl_fixed_t scroll_ = 0; 31 | std::unique_ptr panelSurface_; 32 | std::unique_ptr window_; 33 | TrackableObjectReference repaintIC_; 34 | int widthAtPrevPointerEvent_ = 0; 35 | int heightAtPrevPointerEvent_ = 0; 36 | }; 37 | 38 | } // namespace classicui 39 | } // namespace fcitx 40 | 41 | #endif // _FCITX_UI_CLASSIC_WAYLANDINPUTWINDOW_H_ 42 | -------------------------------------------------------------------------------- /src/waylandpointer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | 8 | #include "waylandpointer.h" 9 | #include "waylandwindow.h" 10 | #include "wl_surface.h" 11 | 12 | namespace fcitx::classicui { 13 | 14 | WaylandPointer::WaylandPointer(wayland::WlSeat *seat) { 15 | capConn_ = seat->capabilities().connect([this, seat](uint32_t caps) { 16 | if ((caps & WL_SEAT_CAPABILITY_POINTER) && !pointer_) { 17 | pointer_.reset(seat->getPointer()); 18 | initPointer(); 19 | } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && pointer_) { 20 | pointer_.reset(); 21 | } 22 | 23 | if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !touch_) { 24 | touch_.reset(seat->getTouch()); 25 | initTouch(); 26 | } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && touch_) { 27 | touch_.reset(); 28 | } 29 | }); 30 | } 31 | 32 | void WaylandPointer::initPointer() { 33 | pointer_->enter().connect([this](uint32_t, wayland::WlSurface *surface, 34 | wl_fixed_t sx, wl_fixed_t sy) { 35 | auto *window = static_cast(surface->userData()); 36 | if (!window) { 37 | return; 38 | } 39 | pointerFocus_ = window->watch(); 40 | pointerFocusX_ = wl_fixed_to_int(sx); 41 | pointerFocusY_ = wl_fixed_to_int(sy); 42 | window->hover()(pointerFocusX_, pointerFocusY_); 43 | }); 44 | pointer_->leave().connect([this](uint32_t, wayland::WlSurface *surface) { 45 | if (auto *window = pointerFocus_.get()) { 46 | if (window->surface() == surface) { 47 | pointerFocus_.unwatch(); 48 | window->leave()(); 49 | } 50 | } 51 | }); 52 | pointer_->motion().connect([this](uint32_t, wl_fixed_t sx, wl_fixed_t sy) { 53 | if (auto *window = pointerFocus_.get()) { 54 | pointerFocusX_ = wl_fixed_to_int(sx); 55 | pointerFocusY_ = wl_fixed_to_int(sy); 56 | window->hover()(pointerFocusX_, pointerFocusY_); 57 | } 58 | }); 59 | pointer_->button().connect( 60 | [this](uint32_t, uint32_t, uint32_t button, uint32_t state) { 61 | if (auto *window = pointerFocus_.get()) { 62 | window->click()(pointerFocusX_, pointerFocusY_, button, state); 63 | } 64 | }); 65 | pointer_->axis().connect([this](uint32_t, uint32_t axis, wl_fixed_t value) { 66 | if (auto *window = pointerFocus_.get()) { 67 | window->axis()(pointerFocusX_, pointerFocusY_, axis, value); 68 | } 69 | }); 70 | } 71 | 72 | void WaylandPointer::initTouch() { 73 | touch_->down().connect([this](uint32_t, uint32_t, 74 | wayland::WlSurface *surface, int, 75 | wl_fixed_t sx, wl_fixed_t sy) { 76 | // TODO handle id for multiple touch 77 | auto *window = static_cast(surface->userData()); 78 | if (!window) { 79 | return; 80 | } 81 | touchFocus_ = window->watch(); 82 | touchFocusX_ = wl_fixed_to_int(sx); 83 | touchFocusY_ = wl_fixed_to_int(sy); 84 | window->touchDown()(touchFocusX_, touchFocusY_); 85 | }); 86 | touch_->up().connect([this](uint32_t, uint32_t, int) { 87 | // TODO handle id for multiple touch 88 | if (auto *window = touchFocus_.get()) { 89 | window->touchUp()(touchFocusX_, touchFocusY_); 90 | touchFocus_.unwatch(); 91 | window->leave()(); 92 | } 93 | }); 94 | } 95 | 96 | } // namespace fcitx::classicui 97 | -------------------------------------------------------------------------------- /src/waylandpointer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_WAYLANDPOINTER_H_ 8 | #define _FCITX_UI_CLASSIC_WAYLANDPOINTER_H_ 9 | 10 | #include 11 | #include "wl_pointer.h" 12 | #include "wl_seat.h" 13 | #include "wl_touch.h" 14 | 15 | namespace fcitx { 16 | namespace classicui { 17 | 18 | class WaylandWindow; 19 | 20 | class WaylandPointer { 21 | public: 22 | WaylandPointer(wayland::WlSeat *seat); 23 | 24 | private: 25 | void initPointer(); 26 | void initTouch(); 27 | std::unique_ptr pointer_; 28 | TrackableObjectReference pointerFocus_; 29 | int pointerFocusX_ = 0, pointerFocusY_ = 0; 30 | std::unique_ptr touch_; 31 | TrackableObjectReference touchFocus_; 32 | int touchFocusX_ = 0, touchFocusY_ = 0; 33 | ScopedConnection capConn_; 34 | }; 35 | 36 | } // namespace classicui 37 | } // namespace fcitx 38 | 39 | #endif // _FCITX_UI_CLASSIC_WAYLANDPOINTER_H_ 40 | -------------------------------------------------------------------------------- /src/waylandshmwindow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | 8 | #include "waylandshmwindow.h" 9 | #include "common.h" 10 | 11 | namespace fcitx::classicui { 12 | 13 | namespace { 14 | 15 | void surfaceToBufferSize(int32_t buffer_scale, uint32_t *width, 16 | uint32_t *height) { 17 | *width *= buffer_scale; 18 | *height *= buffer_scale; 19 | } 20 | 21 | } // namespace 22 | 23 | WaylandShmWindow::WaylandShmWindow(WaylandUI *ui) 24 | : WaylandWindow(ui), shm_(ui->display()->getGlobal()) {} 25 | 26 | WaylandShmWindow::~WaylandShmWindow() {} 27 | 28 | void WaylandShmWindow::destroyWindow() { 29 | buffers_.clear(); 30 | buffer_ = nullptr; 31 | WaylandWindow::destroyWindow(); 32 | } 33 | 34 | void WaylandShmWindow::newBuffer(uint32_t width, uint32_t height) { 35 | if (!shm_) { 36 | return; 37 | } 38 | buffers_.emplace_back(std::make_unique( 39 | shm_.get(), width, height, WL_SHM_FORMAT_ARGB8888)); 40 | buffers_.back()->rendered().connect([this]() { 41 | // Use defer event here, otherwise repaint may delete buffer and cause 42 | // problem. 43 | deferEvent_ = ui_->parent()->instance()->eventLoop().addDeferEvent( 44 | [this](EventSource *) { 45 | if (pending_) { 46 | pending_ = false; 47 | 48 | CLASSICUI_DEBUG() << "Trigger repaint"; 49 | repaint_(); 50 | } 51 | deferEvent_.reset(); 52 | return true; 53 | }); 54 | }); 55 | } 56 | 57 | cairo_surface_t *WaylandShmWindow::prerender() { 58 | // We use double buffer. 59 | decltype(buffers_)::iterator iter; 60 | for (iter = buffers_.begin(); iter != buffers_.end(); iter++) { 61 | CLASSICUI_DEBUG() << "Buffer state: " << (*iter).get() << " " 62 | << (*iter)->busy(); 63 | if (!(*iter)->busy()) { 64 | break; 65 | } 66 | } 67 | 68 | uint32_t bufferWidth = width_, bufferHeight = height_; 69 | surfaceToBufferSize(scale_, &bufferWidth, &bufferHeight); 70 | 71 | if (iter != buffers_.end() && ((*iter)->width() != bufferWidth || 72 | (*iter)->height() != bufferHeight)) { 73 | buffers_.erase(iter); 74 | iter = buffers_.end(); 75 | } 76 | 77 | if (iter == buffers_.end() && buffers_.size() < 2) { 78 | newBuffer(bufferWidth, bufferHeight); 79 | if (!buffers_.empty()) { 80 | iter = std::prev(buffers_.end()); 81 | } 82 | } 83 | 84 | if (iter == buffers_.end()) { 85 | CLASSICUI_DEBUG() << "Couldn't find avail buffer."; 86 | pending_ = true; 87 | // All buffers are busy. 88 | buffer_ = nullptr; 89 | return nullptr; 90 | } 91 | pending_ = false; 92 | buffer_ = iter->get(); 93 | 94 | auto *cairoSurface = buffer_->cairoSurface(); 95 | if (!cairoSurface) { 96 | buffer_ = nullptr; 97 | return nullptr; 98 | } 99 | return cairoSurface; 100 | } 101 | 102 | void WaylandShmWindow::render() { 103 | if (!buffer_) { 104 | return; 105 | } 106 | 107 | buffer_->attachToSurface(surface_.get(), scale_); 108 | } 109 | 110 | void WaylandShmWindow::hide() { 111 | surface_->attach(nullptr, 0, 0); 112 | surface_->commit(); 113 | } 114 | 115 | } // namespace fcitx::classicui 116 | -------------------------------------------------------------------------------- /src/waylandshmwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_WAYLANDSHMWINDOW_H_ 8 | #define _FCITX_UI_CLASSIC_WAYLANDSHMWINDOW_H_ 9 | 10 | #include 11 | #include "buffer.h" 12 | #include "waylandui.h" 13 | #include "waylandwindow.h" 14 | #include "wl_callback.h" 15 | #include "wl_shm.h" 16 | 17 | namespace fcitx { 18 | namespace classicui { 19 | 20 | class WaylandShmWindow : public WaylandWindow { 21 | public: 22 | WaylandShmWindow(WaylandUI *ui); 23 | ~WaylandShmWindow(); 24 | 25 | void destroyWindow() override; 26 | cairo_surface_t *prerender() override; 27 | void render() override; 28 | void hide() override; 29 | 30 | private: 31 | void newBuffer(uint32_t width, uint32_t height); 32 | 33 | std::shared_ptr shm_; 34 | std::vector> buffers_; 35 | // Pointer to the current buffer. 36 | wayland::Buffer *buffer_ = nullptr; 37 | bool pending_ = false; 38 | std::unique_ptr deferEvent_; 39 | }; 40 | } // namespace classicui 41 | } // namespace fcitx 42 | 43 | #endif // _FCITX_UI_CLASSIC_WAYLANDSHMWINDOW_H_ 44 | -------------------------------------------------------------------------------- /src/waylandui.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016-2016 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_WAYLANDUI_H_ 8 | #define _FCITX_UI_CLASSIC_WAYLANDUI_H_ 9 | 10 | #include 11 | #include "classicui.h" 12 | #include "config.h" 13 | #include "display.h" 14 | #include "waylandpointer.h" 15 | #include "wl_pointer.h" 16 | 17 | #ifdef CAIRO_EGL_FOUND 18 | 19 | #include 20 | #include 21 | 22 | #endif 23 | 24 | namespace fcitx { 25 | namespace classicui { 26 | 27 | class WaylandWindow; 28 | class WaylandInputWindow; 29 | 30 | class WaylandUI : public UIInterface { 31 | public: 32 | WaylandUI(ClassicUI *parent, const std::string &name, wl_display *display); 33 | ~WaylandUI(); 34 | 35 | #ifdef CAIRO_EGL_FOUND 36 | 37 | bool initEGL(); 38 | EGLSurface createEGLSurface(wl_egl_window *window, 39 | const EGLint *attrib_list); 40 | void destroyEGLSurface(EGLSurface surface); 41 | EGLContext argbCtx() { return argbCtx_; } 42 | EGLDisplay eglDisplay() { return eglDisplay_; } 43 | 44 | cairo_surface_t *createEGLCairoSurface(EGLSurface surface, int width, 45 | int height); 46 | #endif 47 | 48 | ClassicUI *parent() const { return parent_; } 49 | const std::string &name() const { return name_; } 50 | wayland::Display *display() const { return display_; } 51 | void update(UserInterfaceComponent component, 52 | InputContext *inputContext) override; 53 | void suspend() override; 54 | void resume() override; 55 | void setEnableTray(bool) override {} 56 | 57 | std::unique_ptr newWindow(); 58 | 59 | private: 60 | void setupInputWindow(); 61 | 62 | ClassicUI *parent_; 63 | std::string name_; 64 | wayland::Display *display_; 65 | ScopedConnection panelConn_, panelRemovedConn_; 66 | std::unique_ptr pointer_; 67 | std::unique_ptr inputWindow_; 68 | 69 | bool hasEgl_ = false; 70 | #ifdef CAIRO_EGL_FOUND 71 | // EGL stuff 72 | EGLDisplay eglDisplay_ = nullptr; 73 | EGLConfig argbConfig_ = nullptr; 74 | EGLContext argbCtx_ = nullptr; 75 | cairo_device_t *argbDevice_ = nullptr; 76 | #endif 77 | }; 78 | } // namespace classicui 79 | } // namespace fcitx 80 | 81 | #endif // _FCITX_UI_CLASSIC_WAYLANDUI_H_ 82 | -------------------------------------------------------------------------------- /src/waylandwindow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016-2016 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | 8 | #include "waylandwindow.h" 9 | #include "wl_compositor.h" 10 | #include "wl_output.h" 11 | #include "wl_surface.h" 12 | 13 | namespace fcitx::classicui { 14 | 15 | WaylandWindow::WaylandWindow(WaylandUI *ui) : ui_(ui) {} 16 | 17 | WaylandWindow::~WaylandWindow() {} 18 | 19 | void WaylandWindow::createWindow() { 20 | auto compositor = ui_->display()->getGlobal(); 21 | if (!compositor) { 22 | return; 23 | } 24 | surface_.reset(compositor->createSurface()); 25 | surface_->setUserData(this); 26 | conns_.emplace_back( 27 | surface_->enter().connect([this](wayland::WlOutput *output) { 28 | const auto *info = ui_->display()->outputInformation(output); 29 | if (!info) { 30 | return; 31 | } 32 | if (setScaleAndTransform(info->scale(), info->transform())) { 33 | repaint_(); 34 | } 35 | })); 36 | } 37 | 38 | void WaylandWindow::destroyWindow() { surface_.reset(); } 39 | 40 | } // namespace fcitx::classicui 41 | -------------------------------------------------------------------------------- /src/waylandwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016-2016 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_WAYLANDWINDOW_H_ 8 | #define _FCITX_UI_CLASSIC_WAYLANDWINDOW_H_ 9 | 10 | #include 11 | #include "fcitx-utils/rect.h" 12 | #include "waylandui.h" 13 | #include "window.h" 14 | #include "wl_surface.h" 15 | 16 | namespace fcitx { 17 | namespace classicui { 18 | 19 | class WaylandWindow : public Window, public TrackableObject { 20 | public: 21 | WaylandWindow(WaylandUI *ui); 22 | ~WaylandWindow(); 23 | 24 | virtual void createWindow(); 25 | virtual void destroyWindow(); 26 | virtual void hide() = 0; 27 | 28 | int32_t scale() const { return scale_; } 29 | wl_output_transform transform() const { return transform_; } 30 | bool setScaleAndTransform(int32_t scale, wl_output_transform transform) { 31 | if (scale_ != scale || transform_ != transform) { 32 | scale_ = scale; 33 | transform_ = transform; 34 | return true; 35 | } 36 | return false; 37 | } 38 | wayland::WlSurface *surface() { return surface_.get(); } 39 | 40 | auto &repaint() { return repaint_; } 41 | auto &hover() { return hover_; } 42 | auto &click() { return click_; } 43 | auto &axis() { return axis_; } 44 | auto &leave() { return leave_; } 45 | 46 | auto &touchDown() { return touchDown_; } 47 | auto &touchUp() { return touchUp_; } 48 | 49 | protected: 50 | WaylandUI *ui_; 51 | std::unique_ptr surface_; 52 | std::list conns_; 53 | Signal repaint_; 54 | Signal hover_; 55 | Signal click_; 56 | Signal axis_; 57 | Signal leave_; 58 | 59 | Signal touchDown_; 60 | Signal touchUp_; 61 | 62 | Rect serverAllocation_; 63 | Rect allocation_; 64 | 65 | int scale_ = 1; 66 | wl_output_transform transform_ = WL_OUTPUT_TRANSFORM_NORMAL; 67 | }; 68 | 69 | void bufferToSurfaceSize(enum wl_output_transform buffer_transform, 70 | int32_t buffer_scale, int32_t *width, int32_t *height); 71 | } // namespace classicui 72 | } // namespace fcitx 73 | 74 | #endif // _FCITX_UI_CLASSIC_WAYLANDWINDOW_H_ 75 | -------------------------------------------------------------------------------- /src/window.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016-2016 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | 8 | #include "window.h" 9 | 10 | namespace fcitx::classicui { 11 | 12 | Window::Window() {} 13 | 14 | void Window::resize(unsigned int width, unsigned int height) { 15 | width_ = width; 16 | height_ = height; 17 | } 18 | } // namespace fcitx::classicui 19 | -------------------------------------------------------------------------------- /src/window.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016-2016 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_WINDOW_H_ 8 | #define _FCITX_UI_CLASSIC_WINDOW_H_ 9 | 10 | #include 11 | #include "fcitx/userinterface.h" 12 | 13 | namespace fcitx { 14 | namespace classicui { 15 | 16 | class Window { 17 | public: 18 | Window(); 19 | virtual ~Window() = default; 20 | 21 | int width() const { return width_; } 22 | int height() const { return height_; } 23 | virtual void resize(unsigned int width, unsigned int height); 24 | 25 | virtual cairo_surface_t *prerender() = 0; 26 | virtual void render() = 0; 27 | 28 | protected: 29 | unsigned int width_ = 100; 30 | unsigned int height_ = 100; 31 | }; 32 | } // namespace classicui 33 | } // namespace fcitx 34 | 35 | #endif // _FCITX_UI_CLASSIC_WINDOW_H_ 36 | -------------------------------------------------------------------------------- /src/xcbinputwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_XCBINPUTWINDOW_H_ 8 | #define _FCITX_UI_CLASSIC_XCBINPUTWINDOW_H_ 9 | 10 | #include "inputwindow.h" 11 | #include "xcbwindow.h" 12 | 13 | namespace fcitx { 14 | namespace classicui { 15 | 16 | class XCBInputWindow : public XCBWindow, protected InputWindow { 17 | public: 18 | XCBInputWindow(XCBUI *ui); 19 | 20 | void postCreateWindow() override; 21 | void update(InputContext *inputContext); 22 | void updatePosition(InputContext *inputContext); 23 | 24 | bool filterEvent(xcb_generic_event_t *event) override; 25 | 26 | void updateDPI(InputContext *inputContext); 27 | 28 | private: 29 | void repaint(); 30 | xcb_atom_t atomBlur_; 31 | int dpi_ = -1; 32 | }; 33 | } // namespace classicui 34 | } // namespace fcitx 35 | 36 | #endif // _FCITX_UI_CLASSIC_XCBINPUTWINDOW_H_ 37 | -------------------------------------------------------------------------------- /src/xcbmenu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_XCBMENU_H_ 8 | #define _FCITX_UI_CLASSIC_XCBMENU_H_ 9 | 10 | #include 11 | #include "fcitx/menu.h" 12 | #include "common.h" 13 | #include "xcbwindow.h" 14 | 15 | namespace fcitx { 16 | namespace classicui { 17 | 18 | class MenuPool; 19 | 20 | struct MenuItem { 21 | MenuItem(PangoContext *context) : layout_(pango_layout_new(context)) {} 22 | 23 | bool hasSubMenu_ = false; 24 | bool isHighlight_ = false; 25 | bool isSeparator_ = false; 26 | bool isChecked_ = false; 27 | GObjectUniquePtr layout_; 28 | int layoutX_ = 0, layoutY_ = 0; 29 | Rect region_; 30 | int textWidth_ = 0, textHeight_ = 0; 31 | int checkBoxX_ = 0, checkBoxY_ = 0; 32 | int subMenuX_ = 0, subMenuY_ = 0; 33 | }; 34 | 35 | class XCBMenu : public XCBWindow, public TrackableObject { 36 | public: 37 | XCBMenu(XCBUI *ui, MenuPool *pool, Menu *menu); 38 | ~XCBMenu(); 39 | void show(Rect rect); 40 | 41 | // Hide menu itself. 42 | void hide(); 43 | 44 | // Hide all of its parent. 45 | void hideParents(); 46 | 47 | // Hide all menu on the chain until the one has mouse. 48 | void hideTillMenuHasMouseOrTopLevel(); 49 | 50 | // Hide all of its child. 51 | void hideChilds(); 52 | 53 | // Raise the menu. 54 | void raise(); 55 | 56 | bool filterEvent(xcb_generic_event_t *event) override; 57 | void postCreateWindow() override; 58 | 59 | void setParent(XCBMenu *parent); 60 | void setInputContext(TrackableObjectReference ic); 61 | TrackableObjectReference inputContext() const { 62 | return lastRelevantIc_; 63 | } 64 | 65 | bool childHasMouse() const; 66 | 67 | private: 68 | void hideTillMenuHasMouseOrTopLevelHelper(); 69 | InputContext *lastRelevantIc(); 70 | void update(); 71 | void setHoveredIndex(int idx); 72 | void setChild(XCBMenu *child); 73 | void setFocus(); 74 | std::pair actionAt(size_t index); 75 | 76 | MenuPool *pool_; 77 | 78 | GObjectUniquePtr fontMap_; 79 | GObjectUniquePtr context_; 80 | std::vector items_; 81 | 82 | ScopedConnection destroyed_; 83 | TrackableObjectReference lastRelevantIc_; 84 | Menu *menu_; 85 | TrackableObjectReference parent_; 86 | TrackableObjectReference child_; 87 | int dpi_ = 96; 88 | int x_ = 0; 89 | int y_ = 0; 90 | bool hasMouse_ = false; 91 | bool visible_ = false; 92 | int subMenuIndex_ = -1; 93 | int hoveredIndex_ = -1; 94 | std::unique_ptr activateTimer_; 95 | }; 96 | 97 | class MenuPool { 98 | public: 99 | XCBMenu *requestMenu(XCBUI *ui, Menu *menu, XCBMenu *parent); 100 | 101 | void setPopupMenuTimer(std::unique_ptr popupMenuTimer) { 102 | popupMenuTimer_ = std::move(popupMenuTimer); 103 | } 104 | 105 | private: 106 | XCBMenu *findOrCreateMenu(XCBUI *ui, Menu *menu); 107 | 108 | std::unordered_map> pool_; 109 | std::unique_ptr popupMenuTimer_; 110 | }; 111 | 112 | } // namespace classicui 113 | } // namespace fcitx 114 | 115 | #endif // _FCITX_UI_CLASSIC_XCBMENU_H_ 116 | -------------------------------------------------------------------------------- /src/xcbtraywindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_XCBTRAYWINDOW_H_ 8 | #define _FCITX_UI_CLASSIC_XCBTRAYWINDOW_H_ 9 | 10 | #include "fcitx/menu.h" 11 | #include "xcbmenu.h" 12 | #include "xcbwindow.h" 13 | 14 | namespace fcitx { 15 | namespace classicui { 16 | 17 | class XCBTrayWindow : public XCBWindow { 18 | public: 19 | XCBTrayWindow(XCBUI *ui); 20 | void initTray(); 21 | 22 | bool filterEvent(xcb_generic_event_t *event) override; 23 | void resume(); 24 | void suspend(); 25 | void update(); 26 | void postCreateWindow() override; 27 | 28 | void updateMenu(); 29 | void updateGroupMenu(); 30 | void updateInputMethodMenu(); 31 | 32 | void render() override; 33 | 34 | private: 35 | void findDock(); 36 | void sendTrayOpcode(long message, long data1, long data2, long data3); 37 | void refreshDockWindow(); 38 | xcb_visualid_t trayVisual(); 39 | bool trayOrientation(); 40 | void paint(cairo_t *cr); 41 | void createTrayWindow(); 42 | void resizeTrayWindow(); 43 | 44 | xcb_window_t dockWindow_ = XCB_WINDOW_NONE; 45 | std::unique_ptr> 46 | dockCallback_; 47 | 48 | xcb_atom_t atoms_[5]; 49 | 50 | MenuPool menuPool_; 51 | 52 | Menu menu_; 53 | SimpleAction groupAction_; 54 | SimpleAction separatorActions_[2]; 55 | SimpleAction configureAction_; 56 | SimpleAction restartAction_; 57 | SimpleAction exitAction_; 58 | 59 | #if 0 60 | SimpleAction testAction1_; 61 | SimpleAction testAction2_; 62 | Menu testMenu1_; 63 | Menu testMenu2_; 64 | SimpleAction testSubAction1_; 65 | SimpleAction testSubAction2_; 66 | #endif 67 | 68 | xcb_visualid_t trayVid_ = 0; 69 | int trayDepth_ = 0; 70 | 71 | bool isHorizontal_ = true; 72 | int hintWidth_ = 0; 73 | int hintHeight_ = 0; 74 | 75 | Menu groupMenu_; 76 | std::list groupActions_; 77 | std::list inputMethodActions_; 78 | }; 79 | } // namespace classicui 80 | } // namespace fcitx 81 | 82 | #endif // _FCITX_UI_CLASSIC_XCBTRAYWINDOW_H_ 83 | -------------------------------------------------------------------------------- /src/xcbui.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016-2016 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_XCBUI_H_ 8 | #define _FCITX_UI_CLASSIC_XCBUI_H_ 9 | 10 | #include 11 | #include "fcitx-utils/rect.h" 12 | #include "classicui.h" 13 | 14 | namespace fcitx { 15 | namespace classicui { 16 | 17 | class XCBInputWindow; 18 | class XCBTrayWindow; 19 | 20 | enum class MultiScreenExtension { Randr, Xinerama, EXTNone }; 21 | 22 | enum class XCBHintStyle { Default, NoHint, Medium, Slight, Full }; 23 | 24 | enum class XCBRGBA { Default, NoRGBA, RGB, BGR, VRGB, VBGR }; 25 | 26 | struct XCBFontOption { 27 | int dpi = -1; 28 | bool antialias = true; 29 | XCBHintStyle hint = XCBHintStyle::Default; 30 | XCBRGBA rgba = XCBRGBA::Default; 31 | 32 | void setupPangoContext(PangoContext *context) const; 33 | }; 34 | 35 | class XCBUI : public UIInterface { 36 | public: 37 | XCBUI(ClassicUI *parent, const std::string &name, xcb_connection_t *conn, 38 | int defaultScreen); 39 | ~XCBUI(); 40 | 41 | ClassicUI *parent() const { return parent_; } 42 | const std::string &name() const { return name_; } 43 | xcb_connection_t *connection() const { return conn_; } 44 | xcb_ewmh_connection_t *ewmh() const { return ewmh_; } 45 | xcb_window_t root() const { return root_; } 46 | int defaultScreen() const { return defaultScreen_; } 47 | xcb_colormap_t colorMap() const { return colorMap_; } 48 | xcb_visualid_t visualId() const; 49 | void update(UserInterfaceComponent component, 50 | InputContext *inputContext) override; 51 | void updateCursor(InputContext *inputContext) override; 52 | void updateCurrentInputMethod(InputContext *inputContext) override; 53 | void suspend() override; 54 | void resume() override; 55 | void setEnableTray(bool) override; 56 | 57 | const auto &screenRects() { return rects_; } 58 | int dpiByPosition(int x, int y); 59 | int scaledDPI(int dpi); 60 | const XCBFontOption &fontOption() const { return fontOption_; } 61 | 62 | private: 63 | void refreshCompositeManager(); 64 | void refreshManager(); 65 | void readXSettings(); 66 | void initScreen(); 67 | void updateTray(); 68 | void scheduleUpdateScreen(); 69 | 70 | ClassicUI *parent_; 71 | std::string name_; 72 | xcb_connection_t *conn_; 73 | xcb_window_t root_ = XCB_WINDOW_NONE; 74 | xcb_ewmh_connection_t *ewmh_; 75 | int defaultScreen_; 76 | xcb_colormap_t colorMap_; 77 | bool needFreeColorMap_ = false; 78 | std::unique_ptr inputWindow_; 79 | std::unique_ptr trayWindow_; 80 | bool enableTray_ = false; 81 | 82 | std::string iconThemeName_; 83 | 84 | std::string compMgrAtomString_; 85 | xcb_atom_t compMgrAtom_ = XCB_ATOM_NONE; 86 | xcb_window_t compMgrWindow_ = XCB_WINDOW_NONE; 87 | 88 | xcb_atom_t managerAtom_ = XCB_ATOM_NONE; 89 | xcb_atom_t xsettingsSelectionAtom_ = XCB_ATOM_NONE; 90 | xcb_atom_t xsettingsWindow_ = XCB_WINDOW_NONE; 91 | xcb_atom_t xsettingsAtom_ = XCB_ATOM_NONE; 92 | 93 | XCBFontOption fontOption_; 94 | int maxDpi_ = -1; 95 | int primaryDpi_ = -1; 96 | int screenDpi_ = 96; 97 | MultiScreenExtension multiScreen_ = MultiScreenExtension::EXTNone; 98 | int xrandrFirstEvent_ = 0; 99 | std::unique_ptr initScreenEvent_; 100 | 101 | std::vector> rects_; 102 | 103 | std::vector> eventHandlers_; 104 | }; 105 | 106 | void addEventMaskToWindow(xcb_connection_t *conn, xcb_window_t wid, 107 | uint32_t mask); 108 | } // namespace classicui 109 | } // namespace fcitx 110 | 111 | #endif // _FCITX_UI_CLASSIC_XCBUI_H_ 112 | -------------------------------------------------------------------------------- /src/xcbwindow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016-2016 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | 8 | #include "xcbwindow.h" 9 | #include 10 | #include 11 | #include 12 | #include "common.h" 13 | 14 | namespace fcitx::classicui { 15 | 16 | XCBWindow::XCBWindow(XCBUI *ui, int width, int height) : ui_(ui) { 17 | Window::resize(width, height); 18 | } 19 | 20 | XCBWindow::~XCBWindow() { destroyWindow(); } 21 | 22 | void XCBWindow::createWindow(xcb_visualid_t vid, bool overrideRedirect) { 23 | auto *conn = ui_->connection(); 24 | 25 | if (wid_) { 26 | destroyWindow(); 27 | } 28 | xcb_screen_t *screen = xcb_aux_get_screen(conn, ui_->defaultScreen()); 29 | 30 | xcb_colormap_t colorMap; 31 | CLASSICUI_DEBUG() << "Create window with vid: " << vid; 32 | if (vid == ui_->visualId()) { 33 | colorMap = ui_->colorMap(); 34 | colorMapNeedFree_ = 0; 35 | CLASSICUI_DEBUG() << "Use shared color map: " << colorMap; 36 | } else if (vid) { 37 | colorMapNeedFree_ = xcb_generate_id(conn); 38 | xcb_create_colormap(conn, XCB_COLORMAP_ALLOC_NONE, colorMapNeedFree_, 39 | screen->root, vid); 40 | colorMap = colorMapNeedFree_; 41 | CLASSICUI_DEBUG() << "Use new color map: " << colorMapNeedFree_; 42 | } else { 43 | colorMapNeedFree_ = 0; 44 | colorMap = XCB_COPY_FROM_PARENT; 45 | CLASSICUI_DEBUG() << "Use color map copy from parent"; 46 | } 47 | 48 | wid_ = xcb_generate_id(conn); 49 | 50 | auto depth = xcb_aux_get_depth_of_visual(screen, vid); 51 | 52 | uint32_t valueMask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | 53 | XCB_CW_BIT_GRAVITY | XCB_CW_BACKING_STORE | 54 | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | 55 | XCB_CW_COLORMAP; 56 | 57 | if (overrideRedirect) { 58 | valueMask |= XCB_CW_OVERRIDE_REDIRECT; 59 | } 60 | 61 | xcb_params_cw_t params; 62 | memset(¶ms, 0, sizeof(params)); 63 | params.back_pixel = 0; 64 | params.border_pixel = 0; 65 | params.bit_gravity = XCB_GRAVITY_NORTH_WEST; 66 | params.backing_store = XCB_BACKING_STORE_WHEN_MAPPED; 67 | params.override_redirect = overrideRedirect ? 1 : 0; 68 | params.save_under = 1; 69 | params.colormap = colorMap; 70 | vid_ = vid; 71 | 72 | auto cookie = xcb_aux_create_window_checked( 73 | conn, depth, wid_, screen->root, 0, 0, width_, height_, 0, 74 | XCB_WINDOW_CLASS_INPUT_OUTPUT, vid, valueMask, ¶ms); 75 | if (auto error = makeUniqueCPtr(xcb_request_check(conn, cookie))) { 76 | CLASSICUI_DEBUG() << "Create window failed: " 77 | << static_cast(error->error_code) << " " << vid 78 | << " " << colorMap; 79 | } else { 80 | CLASSICUI_DEBUG() << "Window created id: " << wid_; 81 | } 82 | constexpr uint32_t XEMBED_VERSION = 0; 83 | constexpr uint32_t XEMBED_MAPPED = (1 << 0); 84 | uint32_t data[] = {XEMBED_VERSION, XEMBED_MAPPED}; 85 | xcb_atom_t _XEMBED_INFO = ui_->parent()->xcb()->call( 86 | ui_->name(), "_XEMBED_INFO", false); 87 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, wid_, _XEMBED_INFO, 88 | _XEMBED_INFO, 32, 2, data); 89 | 90 | eventFilter_ = ui_->parent()->xcb()->call( 91 | ui_->name(), [this](xcb_connection_t *, xcb_generic_event_t *event) { 92 | return filterEvent(event); 93 | }); 94 | 95 | surface_.reset(cairo_xcb_surface_create( 96 | conn, wid_, 97 | vid ? xcb_aux_find_visual_by_id(screen, vid) 98 | : xcb_aux_find_visual_by_id(screen, screen->root_visual), 99 | width_, height_)); 100 | contentSurface_.reset(); 101 | 102 | postCreateWindow(); 103 | xcb_flush(ui_->connection()); 104 | } 105 | 106 | void XCBWindow::destroyWindow() { 107 | auto *conn = ui_->connection(); 108 | eventFilter_.reset(); 109 | if (wid_) { 110 | xcb_destroy_window(conn, wid_); 111 | wid_ = 0; 112 | } 113 | if (colorMapNeedFree_) { 114 | xcb_free_colormap(conn, colorMapNeedFree_); 115 | colorMapNeedFree_ = 0; 116 | } 117 | xcb_flush(conn); 118 | } 119 | 120 | void XCBWindow::resize(unsigned int width, unsigned int height) { 121 | const uint32_t vals[2] = {width, height}; 122 | xcb_configure_window(ui_->connection(), wid_, 123 | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, 124 | vals); 125 | xcb_flush(ui_->connection()); 126 | cairo_xcb_surface_set_size(surface_.get(), width, height); 127 | Window::resize(width, height); 128 | CLASSICUI_DEBUG() << "Resize: " << width << " " << height; 129 | } 130 | 131 | cairo_surface_t *XCBWindow::prerender() { 132 | #if 1 133 | contentSurface_.reset(cairo_surface_create_similar( 134 | surface_.get(), CAIRO_CONTENT_COLOR_ALPHA, width(), height())); 135 | #else 136 | contentSurface_.reset( 137 | cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width(), height())); 138 | #endif 139 | return contentSurface_.get(); 140 | } 141 | 142 | void XCBWindow::render() { 143 | auto *cr = cairo_create(surface_.get()); 144 | cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); 145 | cairo_set_source_surface(cr, contentSurface_.get(), 0, 0); 146 | cairo_paint(cr); 147 | cairo_destroy(cr); 148 | xcb_flush(ui_->connection()); 149 | CLASSICUI_DEBUG() << "Render"; 150 | } 151 | } // namespace fcitx::classicui 152 | -------------------------------------------------------------------------------- /src/xcbwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016-2016 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX_UI_CLASSIC_XCBWINDOW_H_ 8 | #define _FCITX_UI_CLASSIC_XCBWINDOW_H_ 9 | 10 | #include 11 | #include 12 | #include "window.h" 13 | #include "xcbui.h" 14 | 15 | namespace fcitx { 16 | namespace classicui { 17 | 18 | class XCBWindow : public Window { 19 | public: 20 | XCBWindow(XCBUI *ui, int width = 1, int height = 1); 21 | ~XCBWindow(); 22 | 23 | void createWindow(xcb_visualid_t vid, bool overrideRedirect = true); 24 | virtual void postCreateWindow() {} 25 | void destroyWindow(); 26 | void resize(unsigned int width, unsigned int height) override; 27 | 28 | cairo_surface_t *prerender() override; 29 | void render() override; 30 | 31 | virtual bool filterEvent(xcb_generic_event_t *event) = 0; 32 | 33 | protected: 34 | XCBUI *ui_; 35 | xcb_window_t wid_ = 0; 36 | xcb_colormap_t colorMapNeedFree_ = 0; 37 | xcb_visualid_t vid_ = 0; 38 | std::unique_ptr> eventFilter_; 39 | UniqueCPtr surface_; 40 | UniqueCPtr contentSurface_; 41 | }; 42 | } // namespace classicui 43 | } // namespace fcitx 44 | 45 | #endif // _FCITX_UI_CLASSIC_XCBWINDOW_H_ 46 | --------------------------------------------------------------------------------