From 667c1b154622f3c2794acf878df876107917c7cd Mon Sep 17 00:00:00 2001 From: Weng Xuetian Date: Sat, 15 Aug 2026 15:37:19 -0700 Subject: [PATCH] Add support for app monitor for wayland protocol on cosmic --- src/frontend/waylandim/CMakeLists.txt | 12 +- src/frontend/waylandim/cosmicappmonitor.cpp | 152 +++++++ src/frontend/waylandim/cosmicappmonitor.h | 54 +++ src/frontend/waylandim/waylandim.cpp | 19 +- src/frontend/waylandim/wlrappmonitor.cpp | 16 +- src/lib/fcitx-wayland/CMakeLists.txt | 2 + .../CMakeLists.txt | 30 ++ .../cosmic-toplevel-info-unstable-v1.xml | 262 ++++++++++++ .../cosmic-workspace-unstable-v1.xml | 400 ++++++++++++++++++ .../zcosmic_toplevel_handle_v1.cpp | 196 +++++++++ .../zcosmic_toplevel_handle_v1.h | 72 ++++ .../zcosmic_toplevel_info_v1.cpp | 67 +++ .../zcosmic_toplevel_info_v1.h | 58 +++ .../ext-foreign-toplevel-list/CMakeLists.txt | 19 + .../ext_foreign_toplevel_handle_v1.cpp | 76 ++++ .../ext_foreign_toplevel_handle_v1.h | 54 +++ .../ext_foreign_toplevel_list_v1.cpp | 50 +++ .../ext_foreign_toplevel_list_v1.h | 53 +++ src/lib/fcitx/misc_p.h | 4 + 19 files changed, 1582 insertions(+), 14 deletions(-) create mode 100644 src/frontend/waylandim/cosmicappmonitor.cpp create mode 100644 src/frontend/waylandim/cosmicappmonitor.h create mode 100644 src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/CMakeLists.txt create mode 100644 src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/cosmic-toplevel-info-unstable-v1.xml create mode 100644 src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/cosmic-workspace-unstable-v1.xml create mode 100644 src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_handle_v1.cpp create mode 100644 src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_handle_v1.h create mode 100644 src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_info_v1.cpp create mode 100644 src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_info_v1.h create mode 100644 src/lib/fcitx-wayland/ext-foreign-toplevel-list/CMakeLists.txt create mode 100644 src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_handle_v1.cpp create mode 100644 src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_handle_v1.h create mode 100644 src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_list_v1.cpp create mode 100644 src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_list_v1.h diff --git a/src/frontend/waylandim/CMakeLists.txt b/src/frontend/waylandim/CMakeLists.txt index fc4d2b4cd..753f5e478 100644 --- a/src/frontend/waylandim/CMakeLists.txt +++ b/src/frontend/waylandim/CMakeLists.txt @@ -16,11 +16,21 @@ add_fcitx5_addon(waylandim plasmaappmonitor.cpp virtualinputcontext.cpp wlrappmonitor.cpp + cosmicappmonitor.cpp appmonitor.cpp ${WAYLAND_IM_PROTOCOL_SRCS} ) target_include_directories(waylandim PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(waylandim Fcitx5::Core Wayland::Client XKBCommon::XKBCommon Fcitx5::Wayland::PlasmaWindowManagement Fcitx5::Wayland::WLRForeignToplevelManagement Fcitx5::Module::Wayland Fcitx5::Wayland::Core Fcitx5::Wayland::InputMethod Fcitx5::Wayland::InputMethodV2) +target_link_libraries(waylandim + Fcitx5::Core Wayland::Client XKBCommon::XKBCommon + Fcitx5::Wayland::PlasmaWindowManagement + Fcitx5::Wayland::WLRForeignToplevelManagement + Fcitx5::Module::Wayland + Fcitx5::Wayland::Core + Fcitx5::Wayland::InputMethod + Fcitx5::Wayland::InputMethodV2 + Fcitx5::Wayland::ExtForeignToplevelList + Fcitx5::Wayland::CosmicToplevelInfo) install(TARGETS waylandim DESTINATION "${FCITX_INSTALL_ADDONDIR}") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/waylandim.conf.in.in ${CMAKE_CURRENT_BINARY_DIR}/waylandim.conf.in @ONLY) fcitx5_translate_desktop_file(${CMAKE_CURRENT_BINARY_DIR}/waylandim.conf.in waylandim.conf) diff --git a/src/frontend/waylandim/cosmicappmonitor.cpp b/src/frontend/waylandim/cosmicappmonitor.cpp new file mode 100644 index 000000000..f70dcdee7 --- /dev/null +++ b/src/frontend/waylandim/cosmicappmonitor.cpp @@ -0,0 +1,152 @@ +/* + * SPDX-FileCopyrightText: 2022~2022 CSSlayer + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + */ +#include "cosmicappmonitor.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fcitx-utils/signals.h" +#include "display.h" +#include "ext_foreign_toplevel_handle_v1.h" +#include "ext_foreign_toplevel_list_v1.h" +#include "zcosmic_toplevel_handle_v1.h" +#include "zcosmic_toplevel_info_v1.h" + +namespace fcitx { +class CosmicWindow { +public: + CosmicWindow(CosmicAppMonitor *parent, + wayland::ExtForeignToplevelHandleV1 *window) + : parent_(parent), window_(window), + key_(std::to_string(wl_proxy_get_id(reinterpret_cast( + static_cast(*window))))) { + if (parent->info()) { + setup(parent->info()); + } + } + + const auto &appId() const { return appId_; } + bool active() const { return active_; } + const auto &key() { return key_; } + + void setup(wayland::ZcosmicToplevelInfoV1 *info) { + if (setup_) { + return; + } + cosmicWindow_.reset(info->getCosmicToplevel(window_.get())); + conns_.emplace_back( + cosmicWindow_->state().connect([this](wl_array *array) { + pendingActive_ = false; + size_t size = array->size / sizeof(uint32_t); + for (size_t i = 0; i < size; ++i) { + auto entry = static_cast(array->data)[i]; + if (entry == ZCOSMIC_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED) { + pendingActive_ = true; + } + } + })); + conns_.emplace_back(window_->done().connect([this]() { + if (active_ != pendingActive_) { + active_ = pendingActive_; + parent_->refresh(); + } + })); + conns_.emplace_back(window_->appId().connect([this](const char *appId) { + if (appId_ != appId) { + appId_ = appId; + parent_->refresh(); + } + })); + setup_ = true; + } + +private: + bool setup_ = false; + CosmicAppMonitor *parent_; + bool pendingActive_ = false; + bool active_ = false; + std::string appId_; + std::unique_ptr window_; + std::unique_ptr cosmicWindow_; + std::string key_; + std::list conns_; +}; + +CosmicAppMonitor::CosmicAppMonitor(wayland::Display *display) { + display->requestGlobals(); + display->requestGlobalsWithMinimalVersion( + 2); + + globalConn_ = display->globalCreated().connect( + [this](const std::string &name, const std::shared_ptr &global) { + if (name == wayland::ExtForeignToplevelListV1::interface) { + setExtForeignToplevelList( + static_cast( + global.get())); + } else if (name == wayland::ZcosmicToplevelInfoV1::interface) { + setCosmicToplevelInfo( + static_cast( + global.get())); + } + }); + + if (auto list = display->getGlobal()) { + setExtForeignToplevelList(list.get()); + } + if (auto info = display->getGlobal()) { + setCosmicToplevelInfo(info.get()); + } +} + +CosmicAppMonitor::~CosmicAppMonitor() = default; + +bool CosmicAppMonitor::isAvailable() const { + return toplevelConn_.connected() && info_; +} + +void CosmicAppMonitor::setExtForeignToplevelList( + wayland::ExtForeignToplevelListV1 *list) { + toplevelConn_ = list->toplevel().connect( + [this](wayland::ExtForeignToplevelHandleV1 *handle) { + windows_[handle] = std::make_unique(this, handle); + handle->closed().connect([this, handle]() { remove(handle); }); + }); +} + +void CosmicAppMonitor::setCosmicToplevelInfo( + wayland::ZcosmicToplevelInfoV1 *info) { + info_ = info; + for (auto &[_, window] : windows_) { + window->setup(info_); + } +} + +void CosmicAppMonitor::remove(wayland::ExtForeignToplevelHandleV1 *handle) { + windows_.erase(handle); + refresh(); +} + +void CosmicAppMonitor::refresh() { + std::unordered_map state; + std::optional focus; + for (const auto &[_, wlrWindow] : windows_) { + if (!wlrWindow->appId().empty()) { + auto iter = state.emplace(wlrWindow->key(), wlrWindow->appId()); + if (wlrWindow->active() && !focus && iter.second) { + focus = iter.first->first; + } + } + } + appUpdated(state, focus); +} + +} // namespace fcitx diff --git a/src/frontend/waylandim/cosmicappmonitor.h b/src/frontend/waylandim/cosmicappmonitor.h new file mode 100644 index 000000000..241d36144 --- /dev/null +++ b/src/frontend/waylandim/cosmicappmonitor.h @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2022~2022 CSSlayer + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + */ +#ifndef _FCITX5_FRONTEND_WAYLANDIM_COSMICAPPMONITOR_H_ +#define _FCITX5_FRONTEND_WAYLANDIM_COSMICAPPMONITOR_H_ + +#include +#include +#include +#include +#include "fcitx-utils/signals.h" +#include "fcitx-wayland/core/display.h" +#include "appmonitor.h" +#include "zcosmic_toplevel_info_v1.h" + +namespace fcitx { +namespace wayland { +class ExtForeignToplevelListV1; +class ExtForeignToplevelHandleV1; +} // namespace wayland +class CosmicWindow; + +class CosmicAppMonitor : public AppMonitor { +public: + CosmicAppMonitor(wayland::Display *display); + ~CosmicAppMonitor() override; + + bool isAvailable() const override; + + void setExtForeignToplevelList(wayland::ExtForeignToplevelListV1 *list); + void setCosmicToplevelInfo(wayland::ZcosmicToplevelInfoV1 *info); + + void remove(wayland::ExtForeignToplevelHandleV1 *handle); + void refresh(); + + auto *info() const { return info_; } + +private: + void setup(); + ScopedConnection globalConn_; + ScopedConnection toplevelConn_; + std::unordered_map> + windows_; + std::unordered_map appState_; + wayland::ZcosmicToplevelInfoV1 *info_ = nullptr; +}; + +} // namespace fcitx + +#endif // _FCITX5_FRONTEND_WAYLANDIM_COSMICAPPMONITOR_H_ diff --git a/src/frontend/waylandim/waylandim.cpp b/src/frontend/waylandim/waylandim.cpp index 67c9ea8fc..3b49a292c 100644 --- a/src/frontend/waylandim/waylandim.cpp +++ b/src/frontend/waylandim/waylandim.cpp @@ -7,7 +7,6 @@ #include "waylandim.h" #include #include -#include #include "fcitx-utils/log.h" #include "fcitx-utils/misc_p.h" #include "fcitx/addonfactory.h" @@ -17,6 +16,7 @@ #include "fcitx/instance.h" #include "fcitx/misc_p.h" #include "appmonitor.h" +#include "cosmicappmonitor.h" #include "display.h" #include "plasmaappmonitor.h" #include "virtualinputcontext.h" @@ -100,16 +100,21 @@ AggregatedAppMonitor *WaylandIMModule::appMonitor(const std::string &display) { auto *display = static_cast( wl_display_get_user_data(displayIter->second)); - auto plasmaMonitor = std::make_unique(display); - auto wlrMonitor = std::make_unique(display); appMonitorPtr = std::make_unique(); if (getDesktopType() == DesktopType::KDE5 || getDesktopType() == DesktopType::KDE6) { - appMonitorPtr->addSubMonitor(std::move(plasmaMonitor)); - appMonitorPtr->addSubMonitor(std::move(wlrMonitor)); + appMonitorPtr->addSubMonitor( + std::make_unique(display)); + appMonitorPtr->addSubMonitor( + std::make_unique(display)); + } else if (getDesktopType() == DesktopType::Cosmic) { + appMonitorPtr->addSubMonitor( + std::make_unique(display)); } else { - appMonitorPtr->addSubMonitor(std::move(wlrMonitor)); - appMonitorPtr->addSubMonitor(std::move(plasmaMonitor)); + appMonitorPtr->addSubMonitor( + std::make_unique(display)); + appMonitorPtr->addSubMonitor( + std::make_unique(display)); } } return appMonitorPtr.get(); diff --git a/src/frontend/waylandim/wlrappmonitor.cpp b/src/frontend/waylandim/wlrappmonitor.cpp index 9cd23b62f..392e0125a 100644 --- a/src/frontend/waylandim/wlrappmonitor.cpp +++ b/src/frontend/waylandim/wlrappmonitor.cpp @@ -37,13 +37,17 @@ class WlrWindow { } } })); - conns_.emplace_back(window->done().connect([this]() { - active_ = pendingActive_; - parent_->refresh(); + conns_.emplace_back(window_->done().connect([this]() { + if (active_ != pendingActive_) { + active_ = pendingActive_; + parent_->refresh(); + } })); - conns_.emplace_back(window->appId().connect([this](const char *appId) { - appId_ = appId; - parent_->refresh(); + conns_.emplace_back(window_->appId().connect([this](const char *appId) { + if (appId_ != appId) { + appId_ = appId; + parent_->refresh(); + } })); } diff --git a/src/lib/fcitx-wayland/CMakeLists.txt b/src/lib/fcitx-wayland/CMakeLists.txt index 75381d0a2..87097fc75 100644 --- a/src/lib/fcitx-wayland/CMakeLists.txt +++ b/src/lib/fcitx-wayland/CMakeLists.txt @@ -12,3 +12,5 @@ add_subdirectory(viewporter) add_subdirectory(tablet-v2) add_subdirectory(cursor-shape) #add_subdirectory(input-method-v3) +add_subdirectory(ext-foreign-toplevel-list) +add_subdirectory(cosmic-toplevel-info-unstable-v1) diff --git a/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/CMakeLists.txt b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/CMakeLists.txt new file mode 100644 index 000000000..e4a42c29b --- /dev/null +++ b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/CMakeLists.txt @@ -0,0 +1,30 @@ +ecm_add_wayland_client_protocol(COSMIC_TOPLEVEL_INFO_PROTOCOL_SRCS + PROTOCOL ${CMAKE_CURRENT_SOURCE_DIR}/cosmic-toplevel-info-unstable-v1.xml + BASENAME cosmic-toplevel-info-unstable-v1) + +# This two are irrelevant, but pulled in as dependency. +ecm_add_wayland_client_protocol(COSMIC_TOPLEVEL_INFO_PROTOCOL_SRCS + PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/staging/ext-workspace/ext-workspace-v1.xml + BASENAME ext-workspace-v1) + +ecm_add_wayland_client_protocol(COSMIC_TOPLEVEL_INFO_PROTOCOL_SRCS + PROTOCOL ${CMAKE_CURRENT_SOURCE_DIR}/cosmic-workspace-unstable-v1.xml + BASENAME cosmic-workspace-unstable-v1) + +set(FCITX_WAYLAND_COSMIC_TOPLEVEL_INFO_PROTOCOL_SOURCES + zcosmic_toplevel_info_v1.cpp + zcosmic_toplevel_handle_v1.cpp +) + +add_library(Fcitx5WaylandCosmicToplevelInfo STATIC ${FCITX_WAYLAND_COSMIC_TOPLEVEL_INFO_PROTOCOL_SOURCES} ${COSMIC_TOPLEVEL_INFO_PROTOCOL_SRCS}) +set_target_properties(Fcitx5WaylandCosmicToplevelInfo PROPERTIES + POSITION_INDEPENDENT_CODE ON + ) +target_include_directories(Fcitx5WaylandCosmicToplevelInfo PUBLIC + "$") +target_link_libraries(Fcitx5WaylandCosmicToplevelInfo +Wayland::Client Fcitx5::Utils Fcitx5::Wayland::Core +Fcitx5::Wayland::ExtForeignToplevelList) + +add_library(Fcitx5::Wayland::CosmicToplevelInfo ALIAS Fcitx5WaylandCosmicToplevelInfo) + diff --git a/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/cosmic-toplevel-info-unstable-v1.xml b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/cosmic-toplevel-info-unstable-v1.xml new file mode 100644 index 000000000..5d3467c24 --- /dev/null +++ b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/cosmic-toplevel-info-unstable-v1.xml @@ -0,0 +1,262 @@ + + + + Copyright © 2018 Ilia Bozhinov + Copyright © 2020 Isaac Freund + Copyright © 2024 Victoria Brekenfeld + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + The purpose of this protocol is to enable clients such as taskbars + or docks to access a list of opened applications and basic properties + thereof. + + It thus extends ext_foreign_toplevel_v1 to provide more information + and actions on foreign toplevels. + + + + + This event is never emitted for clients binding version 2 + of this protocol, they should use `get_cosmic_toplevel` instead. + + This event is emitted for clients binding version 1 whenever a + new toplevel window is created. It is emitted for all toplevels, + regardless of the app that has created them. + + All initial properties of the toplevel (title, app_id, states, etc.) + will be sent immediately after this event via the corresponding + events in zcosmic_toplevel_handle_v1. + + + + + + + This request indicates that the client no longer wishes to receive + events for new toplevels. However, the compositor may emit further + toplevel_created events until the finished event is emitted. + + The client must not send any more requests after this one. + + Note: This request isn't necessary for clients binding version 2 + of this protocol and will be ignored. + + + + + + This event indicates that the compositor is done sending events + to the zcosmic_toplevel_info_v1. The server will destroy the + object immediately after sending this request, so it will become + invalid and the client should free any resources associated with it. + + Note: This event is emitted immediately after calling `stop` for + clients binding version 2 of this protocol for backwards compatibility. + + + + + + Request a zcosmic_toplevel_handle_v1 extension object for an existing + ext_foreign_toplevel_handle_v1. + + All initial properties of the toplevel (states, etc.) + will be sent immediately after this event via the corresponding + events in zcosmic_toplevel_handle_v1. + + + + + + + + This event is sent after all changes for currently active + zcosmic_toplevel_handle_v1 have been sent. + + This allows changes to multiple zcosmic_toplevel_handle_v1 handles + and their properties to be seen as atomic, even if they happen via + multiple events. + + + + + + + A zcosmic_toplevel_handle_v1 object represents an open toplevel + window. A single app may have multiple open toplevels. + + Each toplevel has a list of outputs it is visible on, exposed to the + client via the output_enter and output_leave events. + + + + + This request should be called either when the client will no longer + use the zcosmic_toplevel_handle_v1. + + + + + + The server will emit no further events on the + zcosmic_toplevel_handle_v1 after this event. Any requests received + aside from the destroy request will be ignored. Upon receiving this + event, the client should make the destroy request to allow freeing + of resources. + + Note: This event will not be emitted for clients binding version 2 + of this protocol, as `ext_foreign_toplevel_handle_v1.closed` is + equivalent. + + + + + + This event is sent after all changes in the toplevel state have + been sent. + + This allows changes to the zcosmic_toplevel_handle_v1 properties + to be seen as atomic, even if they happen via multiple events. + + Note: this is is not sent after the closed event. + + Note: This event will not be emitted for clients binding version 2 + of this protocol, as `ext_foreign_toplevel_handle_v1.done` is + equivalent. + + + + + + This event is emitted whenever the title of the toplevel changes. + + Note: This event will not be emitted for clients binding version 2 + of this protocol, as `ext_foreign_toplevel_handle_v1.title` is + equivalent. + + + + + + + This event is emitted whenever the app_id of the toplevel changes. + + Note: This event will not be emitted for clients binding version 2 + of this protocol, as `ext_foreign_toplevel_handle_v1.app_id` is + equivalent. + + + + + + + This event is emitted whenever the toplevel becomes visible on the + given output. A toplevel may be visible on multiple outputs. + + + + + + + This event is emitted whenever the toplevel is no longer visible + on a given output. It is guaranteed that an output_enter event with + the same output has been emitted before this event. + + + + + + + This event is emitted whenever the toplevel becomes visible on the + given workspace. A toplevel may be visible on multiple workspaces. + + + + + + + This event is emitted whenever the toplevel is no longer visible + on a given workspace. It is guaranteed that an workspace_enter event with + the same workspace has been emitted before this event. + + + + + + + The different states that a toplevel may have. These have the same + meaning as the states with the same names defined in xdg-toplevel + + + + + + + + + + + This event is emitted once on creation of the + zcosmic_toplevel_handle_v1 and again whenever the state of the + toplevel changes. + + + + + + + Emitted when the geometry of a toplevel (it's position and/or size) + relative to the provided output has changed. + + This event is emitted once on creation of the + zcosmic_toplevel_handle_v1 for every entered output and again + whenever the geometry of the toplevel changes relative to any output. + + + + + + + + + + + This event is emitted whenever the toplevel becomes visible on the + given workspace. A toplevel may be visible on multiple workspaces. + + + + + + + This event is emitted whenever the toplevel is no longer visible + on a given workspace. It is guaranteed that an workspace_enter event with + the same workspace has been emitted before this event. + + + + + diff --git a/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/cosmic-workspace-unstable-v1.xml b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/cosmic-workspace-unstable-v1.xml new file mode 100644 index 000000000..0bb40180c --- /dev/null +++ b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/cosmic-workspace-unstable-v1.xml @@ -0,0 +1,400 @@ + + + + Copyright © 2019 Christopher Billington + Copyright © 2020 Ilia Bozhinov + Copyright © 2022 Victoria Brekenfeld + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Workspaces, also called virtual desktops, are groups of surfaces. A + compositor with a concept of workspaces may only show some such groups of + surfaces (those of 'active' workspaces) at a time. 'Activating' a + workspace is a request for the compositor to display that workspace's + surfaces as normal, whereas the compositor may hide or otherwise + de-emphasise surfaces that are associated only with 'inactive' workspaces. + Workspaces are grouped by which sets of outputs they correspond to, and + may contain surfaces only from those outputs. In this way, it is possible + for each output to have its own set of workspaces, or for all outputs (or + any other arbitrary grouping) to share workspaces. Compositors may + optionally conceptually arrange each group of workspaces in an + N-dimensional grid. + + The purpose of this protocol is to enable the creation of taskbars and + docks by providing them with a list of workspaces and their properties, + and allowing them to activate and deactivate workspaces. + + After a client binds the zcosmic_workspace_manager_v1, each workspace will be + sent via the workspace event. + + + + + This event is emitted whenever a new workspace group has been created. + + All initial details of the workspace group (workspaces, outputs) will be + sent immediately after this event via the corresponding events in + zcosmic_workspace_group_handle_v1. + + + + + + + The client must send this request after it has finished sending other + requests. The compositor must process a series of requests preceding a + commit request atomically. + + This allows changes to the workspace properties to be seen as atomic, + even if they happen via multiple events, and even if they involve + multiple zcosmic_workspace_handle_v1 objects, for example, deactivating one + workspace and activating another. + + + + + + This event is sent after all changes in all workspace groups have been + sent. + + This allows changes to one or more zcosmic_workspace_group_handle_v1 + properties and zcosmic_workspace_handle_v1 properties to be seen as atomic, + even if they happen via multiple events. + In particular, an output moving from one workspace group to + another sends an output_enter event and an output_leave event to the two + zcosmic_workspace_group_handle_v1 objects in question. The compositor sends + the done event only after updating the output information in both + workspace groups. + + + + + + This event indicates that the compositor is done sending events to the + zcosmic_workspace_manager_v1. The server will destroy the object + immediately after sending this request, so it will become invalid and + the client should free any resources associated with it. + + + + + + Indicates the client no longer wishes to receive events for new + workspace groups. However the compositor may emit further workspace + events, until the finished event is emitted. + + The client must not send any more requests after this one. + + + + + + + A zcosmic_workspace_group_handle_v1 object represents a a workspace group + that is assigned a set of outputs and contains a number of workspaces. + + The set of outputs assigned to the workspace group is conveyed to the client via + output_enter and output_leave events, and its workspaces are conveyed with + workspace events. + + For example, a compositor which has a set of workspaces for each output may + advertise a workspace group (and its workspaces) per output, whereas a compositor + where a workspace spans all outputs may advertise a single workspace group for all + outputs. + + + + + + + + + This event advertises the capabilities supported by the compositor. If + a capability isn't supported, clients should hide or disable the UI + elements that expose this functionality. For instance, if the + compositor doesn't advertise support for creating workspaces, a button + triggering the create_workspace request should not be displayed. + + The compositor will ignore requests it doesn't support. For instance, + a compositor which doesn't advertise support for creating workspaces will ignore + create_workspace requests. + + Compositors must send this event once after creation of an + zcosmic_workspace_group_handle_v1 . When the capabilities change, compositors + must send this event again. + + The capabilities are sent as an array of 32-bit unsigned integers in + native endianness. + + + + + + + This event is emitted whenever an output is assigned to the workspace + group. + + + + + + + This event is emitted whenever an output is removed from the workspace + group. + + + + + + + This event is emitted whenever a new workspace has been created. + A workspace can only be a member of a single workspace group and cannot + be re-assigned. + + All initial details of the workspace (name, coordinates, state) will + be sent immediately after this event via the corresponding events in + zcosmic_workspace_handle_v1. + + + + + + + This event means the zcosmic_workspace_group_handle_v1 has been destroyed. + It is guaranteed there won't be any more events for this + zcosmic_workspace_group_handle_v1. The zext_workspace_group_handle_v1 becomes + inert so any requests will be ignored except the destroy request. + + The compositor must remove all workspaces belonging to a workspace group + before removing the workspace group. + + + + + + Request that the compositor create a new workspace with the given name. + + There is no guarantee that the compositor will create a new workspace, + or that the created workspace will have the provided name. + + + + + + + Destroys the zcosmic_workspace_group_handle_v1 object. + + This request should be called either when the client does not want to + use the workspace object any more or after the remove event to finalize + the destruction of the object. + + + + + + + A zcosmic_workspace_handle_v1 object represents a a workspace that handles a + group of surfaces. + + Each workspace has a name, conveyed to the client with the name event; a + list of states, conveyed to the client with the state event; and + optionally a set of coordinates, conveyed to the client with the + coordinates event. The client may request that the compositor activate or + deactivate the workspace. + + Each workspace can belong to only a single workspace group. + Depepending on the compositor policy, there might be workspaces with + the same name in different workspace groups, but these workspaces are still + separate (e.g. one of them might be active while the other is not). + + + + + This event is emitted immediately after the zcosmic_workspace_handle_v1 is + created and whenever the name of the workspace changes. + + + + + + + This event is used to organize workspaces into an N-dimensional grid + within a workspace group, and if supported, is emitted immediately after + the zcosmic_workspace_handle_v1 is created and whenever the coordinates of + the workspace change. Compositors may not send this event if they do not + conceptually arrange workspaces in this way. If compositors simply + number workspaces, without any geometric interpretation, they may send + 1D coordinates, which clients should not interpret as implying any + geometry. Sending an empty array means that the compositor no longer + orders the workspace geometrically. + + Coordinates have an arbitrary number of dimensions N with an uint32 + position along each dimension. By convention if N > 1, the first + dimension is X, the second Y, the third Z, and so on. The compositor may + chose to utilize these events for a more novel workspace layout + convention, however. No guarantee is made about the grid being filled or + bounded; there may be a workspace at coordinate 1 and another at + coordinate 1000 and none in between. Within a workspace group, however, + workspaces must have unique coordinates of equal dimensionality. + + + + + + + This event is emitted immediately after the zcosmic_workspace_handle_v1 is + created and each time the workspace state changes, either because of a + compositor action or because of a request in this protocol. + + + + + + + The different states that a workspace can have. + + + + + + + The workspace is not visible in its workspace group, and clients + attempting to visualize the compositor workspace state should not + display such workspaces. + + + + + + + + + + + + + + + This event advertises the capabilities supported by the compositor. If + a capability isn't supported, clients should hide or disable the UI + elements that expose this functionality. For instance, if the + compositor doesn't advertise support for removing workspaces, a button + triggering the remove request should not be displayed. + + The compositor will ignore requests it doesn't support. For instance, + a compositor which doesn't advertise support for remove will ignore + remove requests. + + Compositors must send this event once after creation of an + zcosmic_workspace_handle_v1 . When the capabilities change, compositors + must send this event again. + + The capabilities are sent as an array of 32-bit unsigned integers in + native endianness. + + + + + + + This event means the zcosmic_workspace_handle_v1 has been destroyed. It is + guaranteed there won't be any more events for this + zcosmic_workspace_handle_v1. The zext_workspace_handle_v1 becomes inert so + any requests will be ignored except the destroy request. + + + + + + Destroys the zcosmic_workspace_handle_v1 object. + + This request should be called either when the client does not want to + use the workspace object any more or after the remove event to finalize + the destruction of the object. + + + + + + Request that this workspace be activated. + + There is no guarantee the workspace will be actually activated, and + behaviour may be compositor-dependent. For example, activating a + workspace may or may not deactivate all other workspaces in the same + group. + + + + + + Request that this workspace be deactivated. + + There is no guarantee the workspace will be actually deactivated. + + + + + + Request that this workspace be removed. + + There is no guarantee the workspace will be actually removed. + + + + + + This event is emitted immediately after the zcosmic_workspace_handle_v1 is created + and each time the workspace tiling state changes, either because of a + compositor action or because of a request in this protocol. + + + + + + + + + + + + + + Request that this workspace is renamed. + + There is no guarantee the workspace will actually be renamed. + + + + + + + Request that this workspace's tiling state is changed. + + There is no guarantee the workspace will actually change it's tiling state. + + + + + diff --git a/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_handle_v1.cpp b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_handle_v1.cpp new file mode 100644 index 000000000..d03204ba4 --- /dev/null +++ b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_handle_v1.cpp @@ -0,0 +1,196 @@ +#include "zcosmic_toplevel_handle_v1.h" +#include +#include +#include "wayland-cosmic-toplevel-info-unstable-v1-client-protocol.h" + +namespace fcitx::wayland { +const struct zcosmic_toplevel_handle_v1_listener + ZcosmicToplevelHandleV1::listener = { +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_CLOSED_SINCE_VERSION) + .closed = + [](void *data, zcosmic_toplevel_handle_v1 *wldata) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->closed()(); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_DONE_SINCE_VERSION) + .done = + [](void *data, zcosmic_toplevel_handle_v1 *wldata) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->done()(); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_TITLE_SINCE_VERSION) + .title = + [](void *data, zcosmic_toplevel_handle_v1 *wldata, + const char *title) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->title()(title); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_APP_ID_SINCE_VERSION) + .app_id = + [](void *data, zcosmic_toplevel_handle_v1 *wldata, + const char *appId) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->appId()(appId); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_OUTPUT_ENTER_SINCE_VERSION) + .output_enter = + [](void *data, zcosmic_toplevel_handle_v1 *wldata, + wl_output *output) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + if (!output) { + return; + } + auto *output_ = + static_cast(wl_proxy_get_user_data( + reinterpret_cast(output))); + obj->outputEnter()(output_); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_OUTPUT_LEAVE_SINCE_VERSION) + .output_leave = + [](void *data, zcosmic_toplevel_handle_v1 *wldata, + wl_output *output) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + if (!output) { + return; + } + auto *output_ = + static_cast(wl_proxy_get_user_data( + reinterpret_cast(output))); + obj->outputLeave()(output_); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_WORKSPACE_ENTER_SINCE_VERSION) + .workspace_enter = + [](void *data, zcosmic_toplevel_handle_v1 *wldata, + zcosmic_workspace_handle_v1 *workspace) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + if (!workspace) { + return; + } + auto *workspace_ = static_cast( + wl_proxy_get_user_data( + reinterpret_cast(workspace))); + obj->workspaceEnter()(workspace_); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_WORKSPACE_LEAVE_SINCE_VERSION) + .workspace_leave = + [](void *data, zcosmic_toplevel_handle_v1 *wldata, + zcosmic_workspace_handle_v1 *workspace) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + if (!workspace) { + return; + } + auto *workspace_ = static_cast( + wl_proxy_get_user_data( + reinterpret_cast(workspace))); + obj->workspaceLeave()(workspace_); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_STATE_SINCE_VERSION) + .state = + [](void *data, zcosmic_toplevel_handle_v1 *wldata, + wl_array *state) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->state()(state); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_GEOMETRY_SINCE_VERSION) + .geometry = + [](void *data, zcosmic_toplevel_handle_v1 *wldata, + wl_output *output, int32_t x, int32_t y, int32_t width, + int32_t height) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + if (!output) { + return; + } + auto *output_ = + static_cast(wl_proxy_get_user_data( + reinterpret_cast(output))); + obj->geometry()(output_, x, y, width, height); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_EXT_WORKSPACE_ENTER_SINCE_VERSION) + .ext_workspace_enter = + [](void *data, zcosmic_toplevel_handle_v1 *wldata, + ext_workspace_handle_v1 *workspace) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + if (!workspace) { + return; + } + auto *workspace_ = static_cast( + wl_proxy_get_user_data( + reinterpret_cast(workspace))); + obj->extWorkspaceEnter()(workspace_); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_HANDLE_V1_EXT_WORKSPACE_LEAVE_SINCE_VERSION) + .ext_workspace_leave = + [](void *data, zcosmic_toplevel_handle_v1 *wldata, + ext_workspace_handle_v1 *workspace) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + if (!workspace) { + return; + } + auto *workspace_ = static_cast( + wl_proxy_get_user_data( + reinterpret_cast(workspace))); + obj->extWorkspaceLeave()(workspace_); + } + }, +#endif +}; + +ZcosmicToplevelHandleV1::ZcosmicToplevelHandleV1( + zcosmic_toplevel_handle_v1 *data) + : version_(zcosmic_toplevel_handle_v1_get_version(data)), data_(data) { + zcosmic_toplevel_handle_v1_set_user_data(*this, this); + zcosmic_toplevel_handle_v1_add_listener( + *this, &ZcosmicToplevelHandleV1::listener, this); +} + +void ZcosmicToplevelHandleV1::destructor(zcosmic_toplevel_handle_v1 *data) { + zcosmic_toplevel_handle_v1_destroy(data); +} + +} // namespace fcitx::wayland diff --git a/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_handle_v1.h b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_handle_v1.h new file mode 100644 index 000000000..860b33087 --- /dev/null +++ b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_handle_v1.h @@ -0,0 +1,72 @@ +#ifndef ZCOSMIC_TOPLEVEL_HANDLE_V1_H_ +#define ZCOSMIC_TOPLEVEL_HANDLE_V1_H_ +#include +#include +#include +#include "fcitx-utils/misc.h" +#include "fcitx-utils/signals.h" +#include "wayland-cosmic-toplevel-info-unstable-v1-client-protocol.h" // IWYU pragma: export +namespace fcitx::wayland { + +class ExtWorkspaceHandleV1; +class WlOutput; +class ZcosmicWorkspaceHandleV1; + +class ZcosmicToplevelHandleV1 final { +public: + static constexpr const char *interface = "zcosmic_toplevel_handle_v1"; + static constexpr const wl_interface *const wlInterface = + &zcosmic_toplevel_handle_v1_interface; + static constexpr const uint32_t version = 3; + using wlType = zcosmic_toplevel_handle_v1; + operator zcosmic_toplevel_handle_v1 *() { return data_.get(); } + ZcosmicToplevelHandleV1(wlType *data); + ZcosmicToplevelHandleV1(ZcosmicToplevelHandleV1 &&other) noexcept = delete; + ZcosmicToplevelHandleV1 & + operator=(ZcosmicToplevelHandleV1 &&other) noexcept = delete; + auto actualVersion() const { return version_; } + void *userData() const { return userData_; } + void setUserData(void *userData) { userData_ = userData; } + + auto &closed() { return closedSignal_; } + auto &done() { return doneSignal_; } + auto &title() { return titleSignal_; } + auto &appId() { return appIdSignal_; } + auto &outputEnter() { return outputEnterSignal_; } + auto &outputLeave() { return outputLeaveSignal_; } + auto &workspaceEnter() { return workspaceEnterSignal_; } + auto &workspaceLeave() { return workspaceLeaveSignal_; } + auto &state() { return stateSignal_; } + auto &geometry() { return geometrySignal_; } + auto &extWorkspaceEnter() { return extWorkspaceEnterSignal_; } + auto &extWorkspaceLeave() { return extWorkspaceLeaveSignal_; } + +private: + static void destructor(zcosmic_toplevel_handle_v1 *); + static const struct zcosmic_toplevel_handle_v1_listener listener; + fcitx::Signal closedSignal_; + fcitx::Signal doneSignal_; + fcitx::Signal titleSignal_; + fcitx::Signal appIdSignal_; + fcitx::Signal outputEnterSignal_; + fcitx::Signal outputLeaveSignal_; + fcitx::Signal workspaceEnterSignal_; + fcitx::Signal workspaceLeaveSignal_; + fcitx::Signal stateSignal_; + fcitx::Signal + geometrySignal_; + fcitx::Signal extWorkspaceEnterSignal_; + fcitx::Signal extWorkspaceLeaveSignal_; + + uint32_t version_; + void *userData_ = nullptr; + UniqueCPtr data_; +}; +static inline zcosmic_toplevel_handle_v1 * +rawPointer(ZcosmicToplevelHandleV1 *p) { + return p ? static_cast(*p) : nullptr; +} + +} // namespace fcitx::wayland + +#endif // ZCOSMIC_TOPLEVEL_HANDLE_V1_H_ diff --git a/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_info_v1.cpp b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_info_v1.cpp new file mode 100644 index 000000000..fb6322a81 --- /dev/null +++ b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_info_v1.cpp @@ -0,0 +1,67 @@ +#include "zcosmic_toplevel_info_v1.h" +#include +#include +#include "ext_foreign_toplevel_handle_v1.h" +#include "wayland-cosmic-toplevel-info-unstable-v1-client-protocol.h" +#include "zcosmic_toplevel_handle_v1.h" + +namespace fcitx::wayland { +const struct zcosmic_toplevel_info_v1_listener ZcosmicToplevelInfoV1::listener = + { +#if defined(ZCOSMIC_TOPLEVEL_INFO_V1_TOPLEVEL_SINCE_VERSION) + .toplevel = + [](void *data, zcosmic_toplevel_info_v1 *wldata, + zcosmic_toplevel_handle_v1 *toplevel) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + auto *toplevel_ = new ZcosmicToplevelHandleV1(toplevel); + obj->toplevel()(toplevel_); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_INFO_V1_FINISHED_SINCE_VERSION) + .finished = + [](void *data, zcosmic_toplevel_info_v1 *wldata) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->finished()(); + } + }, +#endif +#if defined(ZCOSMIC_TOPLEVEL_INFO_V1_DONE_SINCE_VERSION) + .done = + [](void *data, zcosmic_toplevel_info_v1 *wldata) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->done()(); + } + }, +#endif +}; + +ZcosmicToplevelInfoV1::ZcosmicToplevelInfoV1(zcosmic_toplevel_info_v1 *data) + : version_(zcosmic_toplevel_info_v1_get_version(data)), data_(data) { + zcosmic_toplevel_info_v1_set_user_data(*this, this); + zcosmic_toplevel_info_v1_add_listener( + *this, &ZcosmicToplevelInfoV1::listener, this); +} + +void ZcosmicToplevelInfoV1::destructor(zcosmic_toplevel_info_v1 *data) { + zcosmic_toplevel_info_v1_destroy(data); +} +#if defined(ZCOSMIC_TOPLEVEL_INFO_V1_STOP_SINCE_VERSION) +void ZcosmicToplevelInfoV1::stop() { zcosmic_toplevel_info_v1_stop(*this); } +#endif +#if defined(ZCOSMIC_TOPLEVEL_INFO_V1_GET_COSMIC_TOPLEVEL_SINCE_VERSION) +ZcosmicToplevelHandleV1 *ZcosmicToplevelInfoV1::getCosmicToplevel( + ExtForeignToplevelHandleV1 *foreignToplevel) { + return new ZcosmicToplevelHandleV1( + zcosmic_toplevel_info_v1_get_cosmic_toplevel( + *this, rawPointer(foreignToplevel))); +} +#endif + +} // namespace fcitx::wayland diff --git a/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_info_v1.h b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_info_v1.h new file mode 100644 index 000000000..0584a5c0b --- /dev/null +++ b/src/lib/fcitx-wayland/cosmic-toplevel-info-unstable-v1/zcosmic_toplevel_info_v1.h @@ -0,0 +1,58 @@ +#ifndef ZCOSMIC_TOPLEVEL_INFO_V1_H_ +#define ZCOSMIC_TOPLEVEL_INFO_V1_H_ +#include +#include +#include +#include "fcitx-utils/misc.h" +#include "fcitx-utils/signals.h" +#include "wayland-cosmic-toplevel-info-unstable-v1-client-protocol.h" // IWYU pragma: export +namespace fcitx::wayland { + +class ExtForeignToplevelHandleV1; +class ZcosmicToplevelHandleV1; + +class ZcosmicToplevelInfoV1 final { +public: + static constexpr const char *interface = "zcosmic_toplevel_info_v1"; + static constexpr const wl_interface *const wlInterface = + &zcosmic_toplevel_info_v1_interface; + static constexpr const uint32_t version = 3; + using wlType = zcosmic_toplevel_info_v1; + operator zcosmic_toplevel_info_v1 *() { return data_.get(); } + ZcosmicToplevelInfoV1(wlType *data); + ZcosmicToplevelInfoV1(ZcosmicToplevelInfoV1 &&other) noexcept = delete; + ZcosmicToplevelInfoV1 & + operator=(ZcosmicToplevelInfoV1 &&other) noexcept = delete; + auto actualVersion() const { return version_; } + void *userData() const { return userData_; } + void setUserData(void *userData) { userData_ = userData; } +#if defined(ZCOSMIC_TOPLEVEL_INFO_V1_STOP_SINCE_VERSION) + void stop(); +#endif +#if defined(ZCOSMIC_TOPLEVEL_INFO_V1_GET_COSMIC_TOPLEVEL_SINCE_VERSION) + ZcosmicToplevelHandleV1 * + getCosmicToplevel(ExtForeignToplevelHandleV1 *foreignToplevel); +#endif + + auto &toplevel() { return toplevelSignal_; } + auto &finished() { return finishedSignal_; } + auto &done() { return doneSignal_; } + +private: + static void destructor(zcosmic_toplevel_info_v1 *); + static const struct zcosmic_toplevel_info_v1_listener listener; + fcitx::Signal toplevelSignal_; + fcitx::Signal finishedSignal_; + fcitx::Signal doneSignal_; + + uint32_t version_; + void *userData_ = nullptr; + UniqueCPtr data_; +}; +static inline zcosmic_toplevel_info_v1 *rawPointer(ZcosmicToplevelInfoV1 *p) { + return p ? static_cast(*p) : nullptr; +} + +} // namespace fcitx::wayland + +#endif // ZCOSMIC_TOPLEVEL_INFO_V1_H_ diff --git a/src/lib/fcitx-wayland/ext-foreign-toplevel-list/CMakeLists.txt b/src/lib/fcitx-wayland/ext-foreign-toplevel-list/CMakeLists.txt new file mode 100644 index 000000000..f42426e61 --- /dev/null +++ b/src/lib/fcitx-wayland/ext-foreign-toplevel-list/CMakeLists.txt @@ -0,0 +1,19 @@ +ecm_add_wayland_client_protocol(EXT_FOREIGN_TOPLEVEL_LIST_PROTOCOL_SRCS + PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml + BASENAME ext-foreign-toplevel-list-v1) + +set(FCITX_WAYLAND_EXT_FOREIGN_TOPLEVEL_LIST_PROTOCOL_SOURCES + ext_foreign_toplevel_list_v1.cpp + ext_foreign_toplevel_handle_v1.cpp +) + +add_library(Fcitx5WaylandExtForeignToplevelList STATIC ${FCITX_WAYLAND_EXT_FOREIGN_TOPLEVEL_LIST_PROTOCOL_SOURCES} ${EXT_FOREIGN_TOPLEVEL_LIST_PROTOCOL_SRCS}) +set_target_properties(Fcitx5WaylandExtForeignToplevelList PROPERTIES + POSITION_INDEPENDENT_CODE ON + ) +target_include_directories(Fcitx5WaylandExtForeignToplevelList PUBLIC + "$") +target_link_libraries(Fcitx5WaylandExtForeignToplevelList Wayland::Client Fcitx5::Utils Fcitx5::Wayland::Core) + +add_library(Fcitx5::Wayland::ExtForeignToplevelList ALIAS Fcitx5WaylandExtForeignToplevelList) + diff --git a/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_handle_v1.cpp b/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_handle_v1.cpp new file mode 100644 index 000000000..2cd2f86b5 --- /dev/null +++ b/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_handle_v1.cpp @@ -0,0 +1,76 @@ +#include "ext_foreign_toplevel_handle_v1.h" +#include +#include "wayland-ext-foreign-toplevel-list-v1-client-protocol.h" + +namespace fcitx::wayland { +const struct ext_foreign_toplevel_handle_v1_listener + ExtForeignToplevelHandleV1::listener = { +#if defined(EXT_FOREIGN_TOPLEVEL_HANDLE_V1_CLOSED_SINCE_VERSION) + .closed = + [](void *data, ext_foreign_toplevel_handle_v1 *wldata) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->closed()(); + } + }, +#endif +#if defined(EXT_FOREIGN_TOPLEVEL_HANDLE_V1_DONE_SINCE_VERSION) + .done = + [](void *data, ext_foreign_toplevel_handle_v1 *wldata) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->done()(); + } + }, +#endif +#if defined(EXT_FOREIGN_TOPLEVEL_HANDLE_V1_TITLE_SINCE_VERSION) + .title = + [](void *data, ext_foreign_toplevel_handle_v1 *wldata, + const char *title) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->title()(title); + } + }, +#endif +#if defined(EXT_FOREIGN_TOPLEVEL_HANDLE_V1_APP_ID_SINCE_VERSION) + .app_id = + [](void *data, ext_foreign_toplevel_handle_v1 *wldata, + const char *appId) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->appId()(appId); + } + }, +#endif +#if defined(EXT_FOREIGN_TOPLEVEL_HANDLE_V1_IDENTIFIER_SINCE_VERSION) + .identifier = + [](void *data, ext_foreign_toplevel_handle_v1 *wldata, + const char *identifier) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->identifier()(identifier); + } + }, +#endif +}; + +ExtForeignToplevelHandleV1::ExtForeignToplevelHandleV1( + ext_foreign_toplevel_handle_v1 *data) + : version_(ext_foreign_toplevel_handle_v1_get_version(data)), data_(data) { + ext_foreign_toplevel_handle_v1_set_user_data(*this, this); + ext_foreign_toplevel_handle_v1_add_listener( + *this, &ExtForeignToplevelHandleV1::listener, this); +} + +void ExtForeignToplevelHandleV1::destructor( + ext_foreign_toplevel_handle_v1 *data) { + ext_foreign_toplevel_handle_v1_destroy(data); +} + +} // namespace fcitx::wayland diff --git a/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_handle_v1.h b/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_handle_v1.h new file mode 100644 index 000000000..e0067f54d --- /dev/null +++ b/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_handle_v1.h @@ -0,0 +1,54 @@ +#ifndef EXT_FOREIGN_TOPLEVEL_HANDLE_V1_H_ +#define EXT_FOREIGN_TOPLEVEL_HANDLE_V1_H_ +#include +#include +#include +#include "fcitx-utils/misc.h" +#include "fcitx-utils/signals.h" +#include "wayland-ext-foreign-toplevel-list-v1-client-protocol.h" // IWYU pragma: export +namespace fcitx::wayland { + +class ExtForeignToplevelHandleV1 final { +public: + static constexpr const char *interface = "ext_foreign_toplevel_handle_v1"; + static constexpr const wl_interface *const wlInterface = + &ext_foreign_toplevel_handle_v1_interface; + static constexpr const uint32_t version = 1; + using wlType = ext_foreign_toplevel_handle_v1; + operator ext_foreign_toplevel_handle_v1 *() { return data_.get(); } + ExtForeignToplevelHandleV1(wlType *data); + ExtForeignToplevelHandleV1(ExtForeignToplevelHandleV1 &&other) noexcept = + delete; + ExtForeignToplevelHandleV1 & + operator=(ExtForeignToplevelHandleV1 &&other) noexcept = delete; + auto actualVersion() const { return version_; } + void *userData() const { return userData_; } + void setUserData(void *userData) { userData_ = userData; } + + auto &closed() { return closedSignal_; } + auto &done() { return doneSignal_; } + auto &title() { return titleSignal_; } + auto &appId() { return appIdSignal_; } + auto &identifier() { return identifierSignal_; } + +private: + static void destructor(ext_foreign_toplevel_handle_v1 *); + static const struct ext_foreign_toplevel_handle_v1_listener listener; + fcitx::Signal closedSignal_; + fcitx::Signal doneSignal_; + fcitx::Signal titleSignal_; + fcitx::Signal appIdSignal_; + fcitx::Signal identifierSignal_; + + uint32_t version_; + void *userData_ = nullptr; + UniqueCPtr data_; +}; +static inline ext_foreign_toplevel_handle_v1 * +rawPointer(ExtForeignToplevelHandleV1 *p) { + return p ? static_cast(*p) : nullptr; +} + +} // namespace fcitx::wayland + +#endif // EXT_FOREIGN_TOPLEVEL_HANDLE_V1_H_ diff --git a/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_list_v1.cpp b/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_list_v1.cpp new file mode 100644 index 000000000..a5d93bad3 --- /dev/null +++ b/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_list_v1.cpp @@ -0,0 +1,50 @@ +#include "ext_foreign_toplevel_list_v1.h" +#include +#include "ext_foreign_toplevel_handle_v1.h" +#include "wayland-ext-foreign-toplevel-list-v1-client-protocol.h" + +namespace fcitx::wayland { +const struct ext_foreign_toplevel_list_v1_listener + ExtForeignToplevelListV1::listener = { +#if defined(EXT_FOREIGN_TOPLEVEL_LIST_V1_TOPLEVEL_SINCE_VERSION) + .toplevel = + [](void *data, ext_foreign_toplevel_list_v1 *wldata, + ext_foreign_toplevel_handle_v1 *toplevel) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + auto *toplevel_ = new ExtForeignToplevelHandleV1(toplevel); + obj->toplevel()(toplevel_); + } + }, +#endif +#if defined(EXT_FOREIGN_TOPLEVEL_LIST_V1_FINISHED_SINCE_VERSION) + .finished = + [](void *data, ext_foreign_toplevel_list_v1 *wldata) { + auto *obj = static_cast(data); + assert(*obj == wldata); + { + obj->finished()(); + } + }, +#endif +}; + +ExtForeignToplevelListV1::ExtForeignToplevelListV1( + ext_foreign_toplevel_list_v1 *data) + : version_(ext_foreign_toplevel_list_v1_get_version(data)), data_(data) { + ext_foreign_toplevel_list_v1_set_user_data(*this, this); + ext_foreign_toplevel_list_v1_add_listener( + *this, &ExtForeignToplevelListV1::listener, this); +} + +void ExtForeignToplevelListV1::destructor(ext_foreign_toplevel_list_v1 *data) { + ext_foreign_toplevel_list_v1_destroy(data); +} +#if defined(EXT_FOREIGN_TOPLEVEL_LIST_V1_STOP_SINCE_VERSION) +void ExtForeignToplevelListV1::stop() { + ext_foreign_toplevel_list_v1_stop(*this); +} +#endif + +} // namespace fcitx::wayland diff --git a/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_list_v1.h b/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_list_v1.h new file mode 100644 index 000000000..ebce59db7 --- /dev/null +++ b/src/lib/fcitx-wayland/ext-foreign-toplevel-list/ext_foreign_toplevel_list_v1.h @@ -0,0 +1,53 @@ +#ifndef EXT_FOREIGN_TOPLEVEL_LIST_V1_H_ +#define EXT_FOREIGN_TOPLEVEL_LIST_V1_H_ +#include +#include +#include +#include "fcitx-utils/misc.h" +#include "fcitx-utils/signals.h" +#include "wayland-ext-foreign-toplevel-list-v1-client-protocol.h" // IWYU pragma: export +namespace fcitx::wayland { + +class ExtForeignToplevelHandleV1; + +class ExtForeignToplevelListV1 final { +public: + static constexpr const char *interface = "ext_foreign_toplevel_list_v1"; + static constexpr const wl_interface *const wlInterface = + &ext_foreign_toplevel_list_v1_interface; + static constexpr const uint32_t version = 1; + using wlType = ext_foreign_toplevel_list_v1; + operator ext_foreign_toplevel_list_v1 *() { return data_.get(); } + ExtForeignToplevelListV1(wlType *data); + ExtForeignToplevelListV1(ExtForeignToplevelListV1 &&other) noexcept = + delete; + ExtForeignToplevelListV1 & + operator=(ExtForeignToplevelListV1 &&other) noexcept = delete; + auto actualVersion() const { return version_; } + void *userData() const { return userData_; } + void setUserData(void *userData) { userData_ = userData; } +#if defined(EXT_FOREIGN_TOPLEVEL_LIST_V1_STOP_SINCE_VERSION) + void stop(); +#endif + + auto &toplevel() { return toplevelSignal_; } + auto &finished() { return finishedSignal_; } + +private: + static void destructor(ext_foreign_toplevel_list_v1 *); + static const struct ext_foreign_toplevel_list_v1_listener listener; + fcitx::Signal toplevelSignal_; + fcitx::Signal finishedSignal_; + + uint32_t version_; + void *userData_ = nullptr; + UniqueCPtr data_; +}; +static inline ext_foreign_toplevel_list_v1 * +rawPointer(ExtForeignToplevelListV1 *p) { + return p ? static_cast(*p) : nullptr; +} + +} // namespace fcitx::wayland + +#endif // EXT_FOREIGN_TOPLEVEL_LIST_V1_H_ diff --git a/src/lib/fcitx/misc_p.h b/src/lib/fcitx/misc_p.h index b3bc8afc6..9b9612700 100644 --- a/src/lib/fcitx/misc_p.h +++ b/src/lib/fcitx/misc_p.h @@ -127,6 +127,7 @@ enum class DesktopType { DEEPIN, UKUI, Sway, + Cosmic, Unknown }; @@ -190,6 +191,9 @@ static inline DesktopType getDesktopType() { if (desktop == "sway") { return DesktopType::Sway; } + if (desktop == "cosmic") { + return DesktopType::Cosmic; + } } return DesktopType::Unknown; }