From 7cfec341999ae0cdf988d0a662e6f18f6d57bf8a Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Mon, 22 Jul 2024 17:32:07 -0600 Subject: [PATCH] Add ghost plugin Allows windows to become click-through. --- metadata/ghost.xml | 17 +++++ metadata/meson.build | 1 + src/ghost.cpp | 151 +++++++++++++++++++++++++++++++++++++++++++ src/meson.build | 4 ++ 4 files changed, 173 insertions(+) create mode 100644 metadata/ghost.xml create mode 100644 src/ghost.cpp diff --git a/metadata/ghost.xml b/metadata/ghost.xml new file mode 100644 index 0000000..4fc39cb --- /dev/null +++ b/metadata/ghost.xml @@ -0,0 +1,17 @@ + + + + <_short>Ghost Windows + Window Management + + + + diff --git a/metadata/meson.build b/metadata/meson.build index 081949b..17bea4b 100644 --- a/metadata/meson.build +++ b/metadata/meson.build @@ -7,6 +7,7 @@ install_data('focus-change.xml', install_dir: wayfire.get_variable(pkgconfig: 'm install_data('focus-steal-prevent.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) install_data('follow-focus.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) install_data('force-fullscreen.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) +install_data('ghost.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) install_data('hide-cursor.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) install_data('join-views.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) install_data('keycolor.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir')) diff --git a/src/ghost.cpp b/src/ghost.cpp new file mode 100644 index 0000000..2517eae --- /dev/null +++ b/src/ghost.cpp @@ -0,0 +1,151 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Scott Moreau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +const std::string ghost_transformer_name = "ghost_transformer"; + +namespace wf +{ +namespace ghost +{ +using namespace wf::scene; +class ghost_view : public wf::scene::view_2d_transformer_t +{ + wayfire_view view; + + public: + + ghost_view(wayfire_view view) : wf::scene::view_2d_transformer_t(view) + { + this->view = view; + } + + std::optional find_node_at(const wf::pointf_t& at) override + { + return {}; + } + + virtual ~ghost_view() + {} +}; + +class ghost_plugin : public wf::plugin_interface_t +{ + wf::ipc_activator_t ghost_toggle{"ghost/ghost_toggle"}; + wf::view_matcher_t ghost_match{"ghost/ghost_match"}; + + void pop_transformer(wayfire_view view) + { + if (view->get_transformed_node()->get_transformer(ghost_transformer_name)) + { + view->get_transformed_node()->rem_transformer(ghost_transformer_name); + } + } + + void remove_shade_transformers() + { + for (auto& view : wf::get_core().get_all_views()) + { + pop_transformer(view); + } + } + + std::shared_ptr ensure_transformer(wayfire_view view) + { + auto tmgr = view->get_transformed_node(); + if (auto tr = tmgr->get_transformer(ghost_transformer_name)) + { + return tr; + } + + auto node = std::make_shared(view); + tmgr->add_transformer(node, wf::TRANSFORMER_2D, ghost_transformer_name); + auto tr = tmgr->get_transformer(ghost_transformer_name); + + return tr; + } + + public: + + void init() override + { + for (auto& view : wf::get_core().get_all_views()) + { + if (ghost_match.matches(view)) + { + ensure_transformer(view); + } + } + + ghost_toggle.set_handler(ghost_view_toggle_cb); + wf::get_core().connect(&on_view_map); + } + + wf::ipc_activator_t::handler_t ghost_view_toggle_cb = [=] (wf::output_t *output, wayfire_view view) + { + auto top_view = wf::get_core().seat->get_active_view(); + if (top_view && top_view->get_transformed_node()->get_transformer(ghost_transformer_name)) + { + pop_transformer(top_view); + return true; + } + + if (!view) + { + return false; + } + + if (view->get_transformed_node()->get_transformer(ghost_transformer_name)) + { + pop_transformer(view); + return true; + } + + ensure_transformer(view); + return true; + }; + + wf::signal::connection_t on_view_map = [=] (wf::view_mapped_signal *ev) + { + if (ghost_match.matches(ev->view)) + { + ensure_transformer(ev->view); + } + }; + + void fini() override + { + remove_shade_transformers(); + on_view_map.disconnect(); + } +}; +} +} + +DECLARE_WAYFIRE_PLUGIN(wf::ghost::ghost_plugin); diff --git a/src/meson.build b/src/meson.build index 952b678..e02c334 100644 --- a/src/meson.build +++ b/src/meson.build @@ -36,6 +36,10 @@ force_fullscreen = shared_module('force-fullscreen', 'force-fullscreen.cpp', dependencies: [wayfire], install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) +ghost = shared_module('ghost', 'ghost.cpp', + dependencies: [wayfire], + install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) + if giomm.found() glib_main_loop = shared_module('glib-main-loop', 'glib-main-loop.cpp', dependencies: [wayfire, giomm],