From e9236e1744472dac2b8895ac1f74eeeedfded9c3 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Sat, 6 Jul 2024 16:37:42 +0200 Subject: [PATCH 01/12] [DONOTMERGE] add -ftime-trace --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 6f07212ae..5a676b333 100644 --- a/meson.build +++ b/meson.build @@ -145,7 +145,7 @@ cpp = meson.get_compiler('cpp') # -E is for RTTI/dynamic_cast across plugins add_project_link_arguments(['-rdynamic', '-Wl,-E'], language: 'cpp') -project_args = ['-DWLR_USE_UNSTABLE'] +project_args = ['-DWLR_USE_UNSTABLE', '-ftime-trace'] # Needed for dlclose to actually free plugin memory on gcc+glibc if cpp.has_argument('-fno-gnu-unique') project_args += '-fno-gnu-unique' From c5d9c3057291faab093be3ae413d1d7ffe2c12ec Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 3 Jul 2024 12:18:22 +0200 Subject: [PATCH 02/12] shuffle around header files --- meson.build | 2 +- plugins/blur/blur.cpp | 1 + .../plugins/common/simple-text-node.hpp | 1 + .../common/wayfire/plugins/common/util.hpp | 2 +- plugins/protocols/foreign-toplevel.cpp | 1 + plugins/protocols/shortcuts-inhibit.cpp | 2 +- plugins/single_plugins/command.cpp | 1 + plugins/single_plugins/oswitch.cpp | 1 - plugins/single_plugins/preserve-output.cpp | 1 + plugins/single_plugins/wsets.cpp | 1 + plugins/single_plugins/xkb-bindings.cpp | 1 + .../window-rules/view-action-interface.cpp | 1 + .../window-rules/view-action-interface.hpp | 2 +- plugins/wm-actions/wm-actions.cpp | 1 + .../wayfire/plugins/wobbly/wobbly-signal.hpp | 12 +-- plugins/wobbly/wobbly.cpp | 6 ++ src/api/wayfire/core.hpp | 4 +- src/api/wayfire/geometry.hpp | 8 +- src/api/wayfire/nonstd/safe-list.hpp | 5 - src/api/wayfire/option-wrapper.hpp | 1 + src/api/wayfire/output-layout.hpp | 79 +++++++++++++++ src/api/wayfire/per-output-plugin.hpp | 2 - src/api/wayfire/plugin.hpp | 2 +- src/api/wayfire/render-manager.hpp | 1 + src/api/wayfire/scene.hpp | 7 +- src/api/wayfire/seat.hpp | 17 ++++ src/api/wayfire/signal-definitions.hpp | 96 ------------------- src/api/wayfire/signal-provider.hpp | 1 - src/api/wayfire/txn/transaction-object.hpp | 2 + src/api/wayfire/unstable/wlr-surface-node.hpp | 1 + src/api/wayfire/view.hpp | 4 +- src/core/core.cpp | 1 + src/core/output-layout.cpp | 1 + src/core/seat/input-manager.cpp | 5 +- src/core/seat/input-manager.hpp | 5 +- src/core/seat/input-method-relay.hpp | 2 +- src/output/output-impl.hpp | 4 +- src/view/xdg-shell.hpp | 2 +- 38 files changed, 146 insertions(+), 140 deletions(-) diff --git a/meson.build b/meson.build index 5a676b333..0bb9680d9 100644 --- a/meson.build +++ b/meson.build @@ -196,7 +196,7 @@ else print_trace = false endif -add_project_arguments(['-DWF_USE_CONFIG_H'], language: ['cpp', 'c']) +add_project_arguments(['-DWF_USE_CONFIG_H', '-ftime-trace'], language: ['cpp', 'c']) configure_file(input: 'config.h.in', output: 'config.h', install: true, diff --git a/plugins/blur/blur.cpp b/plugins/blur/blur.cpp index b5f5686b3..a0837c978 100644 --- a/plugins/blur/blur.cpp +++ b/plugins/blur/blur.cpp @@ -20,6 +20,7 @@ #include "wayfire/scene-render.hpp" #include "wayfire/scene.hpp" #include "wayfire/signal-provider.hpp" +#include using blur_algorithm_provider = std::function()>; diff --git a/plugins/common/wayfire/plugins/common/simple-text-node.hpp b/plugins/common/wayfire/plugins/common/simple-text-node.hpp index f0d801c1c..1a8c7465c 100644 --- a/plugins/common/wayfire/plugins/common/simple-text-node.hpp +++ b/plugins/common/wayfire/plugins/common/simple-text-node.hpp @@ -2,6 +2,7 @@ #include "wayfire/output.hpp" #include "wayfire/scene.hpp" #include +#include class simple_text_node_t : public wf::scene::node_t { diff --git a/plugins/common/wayfire/plugins/common/util.hpp b/plugins/common/wayfire/plugins/common/util.hpp index 4aa81e456..6cef06329 100644 --- a/plugins/common/wayfire/plugins/common/util.hpp +++ b/plugins/common/wayfire/plugins/common/util.hpp @@ -8,7 +8,7 @@ #include "wayfire/view.hpp" #include "wayfire/output.hpp" #include "wayfire/toplevel-view.hpp" -#include "wayfire/workspace-set.hpp" +#include "wayfire/view-transform.hpp" #include namespace wf { diff --git a/plugins/protocols/foreign-toplevel.cpp b/plugins/protocols/foreign-toplevel.cpp index d0a912363..9cb201783 100644 --- a/plugins/protocols/foreign-toplevel.cpp +++ b/plugins/protocols/foreign-toplevel.cpp @@ -1,4 +1,5 @@ #include "wayfire/core.hpp" +#include "wayfire/debug.hpp" #include "wayfire/signal-definitions.hpp" #include #include "wayfire/view.hpp" diff --git a/plugins/protocols/shortcuts-inhibit.cpp b/plugins/protocols/shortcuts-inhibit.cpp index a4df40095..a5352e9a4 100644 --- a/plugins/protocols/shortcuts-inhibit.cpp +++ b/plugins/protocols/shortcuts-inhibit.cpp @@ -1,6 +1,5 @@ #include "wayfire/core.hpp" #include "wayfire/option-wrapper.hpp" -#include "wayfire/plugins/common/shared-core-data.hpp" #include "wayfire/signal-definitions.hpp" #include "wayfire/signal-provider.hpp" #include "wayfire/util.hpp" @@ -11,6 +10,7 @@ #include #include #include +#include class wayfire_shortcuts_inhibit : public wf::plugin_interface_t { diff --git a/plugins/single_plugins/command.cpp b/plugins/single_plugins/command.cpp index 99cdf7715..8fc86d962 100644 --- a/plugins/single_plugins/command.cpp +++ b/plugins/single_plugins/command.cpp @@ -15,6 +15,7 @@ #include #include #include +#include /* Initial repeat delay passed */ static int repeat_delay_timeout_handler(void *callback) diff --git a/plugins/single_plugins/oswitch.cpp b/plugins/single_plugins/oswitch.cpp index e0dfa682f..1e79ef6e2 100644 --- a/plugins/single_plugins/oswitch.cpp +++ b/plugins/single_plugins/oswitch.cpp @@ -49,7 +49,6 @@ class wayfire_oswitch : public wf::plugin_interface_t auto current_output = wf::get_core().seat->get_active_output(); auto view = wf::find_topmost_parent(wf::toplevel_cast(wf::get_active_view_for_output(current_output))); - if (view) { move_view_to_output(view, target_output, true); diff --git a/plugins/single_plugins/preserve-output.cpp b/plugins/single_plugins/preserve-output.cpp index b716007f2..d1f3dac27 100644 --- a/plugins/single_plugins/preserve-output.cpp +++ b/plugins/single_plugins/preserve-output.cpp @@ -1,4 +1,5 @@ #include "wayfire/core.hpp" +#include "wayfire/debug.hpp" #include "wayfire/plugin.hpp" #include #include diff --git a/plugins/single_plugins/wsets.cpp b/plugins/single_plugins/wsets.cpp index b330cc5a4..aa17cba91 100644 --- a/plugins/single_plugins/wsets.cpp +++ b/plugins/single_plugins/wsets.cpp @@ -22,6 +22,7 @@ #include #include #include +#include class wayfire_wsets_plugin_t : public wf::plugin_interface_t diff --git a/plugins/single_plugins/xkb-bindings.cpp b/plugins/single_plugins/xkb-bindings.cpp index 2fa279b5f..0ba063f86 100644 --- a/plugins/single_plugins/xkb-bindings.cpp +++ b/plugins/single_plugins/xkb-bindings.cpp @@ -4,6 +4,7 @@ #include #include "wayfire/core.hpp" #include "wayfire/seat.hpp" +#include namespace wf { diff --git a/plugins/window-rules/view-action-interface.cpp b/plugins/window-rules/view-action-interface.cpp index a5b8f8e12..2672f627d 100644 --- a/plugins/window-rules/view-action-interface.cpp +++ b/plugins/window-rules/view-action-interface.cpp @@ -11,6 +11,7 @@ #include "../wm-actions/wm-actions-signals.hpp" #include #include +#include #include #include diff --git a/plugins/window-rules/view-action-interface.hpp b/plugins/window-rules/view-action-interface.hpp index e2c17cd43..32e525dd0 100644 --- a/plugins/window-rules/view-action-interface.hpp +++ b/plugins/window-rules/view-action-interface.hpp @@ -2,7 +2,7 @@ #define VIEW_ACTION_INTERFACE_HPP #include "wayfire/action/action_interface.hpp" -#include "wayfire/view.hpp" +#include "wayfire/toplevel-view.hpp" #include #include #include diff --git a/plugins/wm-actions/wm-actions.cpp b/plugins/wm-actions/wm-actions.cpp index 8ff784281..2e09dd147 100644 --- a/plugins/wm-actions/wm-actions.cpp +++ b/plugins/wm-actions/wm-actions.cpp @@ -17,6 +17,7 @@ #include "wayfire/window-manager.hpp" #include "wayfire/seat.hpp" #include "wm-actions-signals.hpp" +#include "wayfire/nonstd/reverse.hpp" class always_on_top_root_node_t : public wf::scene::output_node_t { diff --git a/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp b/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp index e7ef538de..540264f7f 100644 --- a/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp +++ b/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include enum wobbly_event { @@ -97,13 +98,10 @@ inline void move_wobbly(wayfire_toplevel_view view, int grab_x, int grab_y) */ inline void activate_wobbly(wayfire_toplevel_view view) { - if (!view->get_transformed_node()->get_transformer("wobbly")) - { - wobbly_signal sig; - sig.view = view; - sig.events = WOBBLY_EVENT_ACTIVATE; - wf::get_core().emit(&sig); - } + wobbly_signal sig; + sig.view = view; + sig.events = WOBBLY_EVENT_ACTIVATE; + wf::get_core().emit(&sig); } /** diff --git a/plugins/wobbly/wobbly.cpp b/plugins/wobbly/wobbly.cpp index f0d8ec877..a0706c62d 100644 --- a/plugins/wobbly/wobbly.cpp +++ b/plugins/wobbly/wobbly.cpp @@ -932,6 +932,12 @@ class wayfire_wobbly : public wf::plugin_interface_t void adjust_wobbly(wobbly_signal *data) { auto tr_manager = data->view->get_transformed_node(); + + if ((data->events == WOBBLY_EVENT_ACTIVATE) && tr_manager->get_transformer("wobbly")) + { + return; + } + if ((data->events & (WOBBLY_EVENT_GRAB | WOBBLY_EVENT_ACTIVATE)) && !tr_manager->get_transformer("wobbly")) { diff --git a/src/api/wayfire/core.hpp b/src/api/wayfire/core.hpp index 7f6c9c5b5..d2ebb60bc 100644 --- a/src/api/wayfire/core.hpp +++ b/src/api/wayfire/core.hpp @@ -2,10 +2,7 @@ #define CORE_HPP #include "wayfire/object.hpp" -#include "wayfire/scene-input.hpp" -#include #include -#include #include #include @@ -24,6 +21,7 @@ class view_interface_t; class toplevel_view_interface_t; class window_manager_t; class workspace_set_t; +class config_backend_t; namespace scene { diff --git a/src/api/wayfire/geometry.hpp b/src/api/wayfire/geometry.hpp index 80fb64611..576142a62 100644 --- a/src/api/wayfire/geometry.hpp +++ b/src/api/wayfire/geometry.hpp @@ -1,8 +1,12 @@ #ifndef WF_GEOMETRY_HPP #define WF_GEOMETRY_HPP -#include -#include +#include +#include + +extern "C" { +#include +} namespace wf { diff --git a/src/api/wayfire/nonstd/safe-list.hpp b/src/api/wayfire/nonstd/safe-list.hpp index 2abe0f483..295322860 100644 --- a/src/api/wayfire/nonstd/safe-list.hpp +++ b/src/api/wayfire/nonstd/safe-list.hpp @@ -1,17 +1,12 @@ #ifndef WF_SAFE_LIST_HPP #define WF_SAFE_LIST_HPP -#include -#include #include #include #include #include #include #include -#include - -#include "reverse.hpp" namespace wf { diff --git a/src/api/wayfire/option-wrapper.hpp b/src/api/wayfire/option-wrapper.hpp index d61702115..c1765e346 100644 --- a/src/api/wayfire/option-wrapper.hpp +++ b/src/api/wayfire/option-wrapper.hpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace wf { diff --git a/src/api/wayfire/output-layout.hpp b/src/api/wayfire/output-layout.hpp index 985496a10..abc47c318 100644 --- a/src/api/wayfire/output-layout.hpp +++ b/src/api/wayfire/output-layout.hpp @@ -18,6 +18,85 @@ namespace wf { class output_t; + +/* ----------------------------------------------------------------------------/ + * Output signals + * -------------------------------------------------------------------------- */ + +/** Base class for all output signals. */ + +/** + * on: output-layout + * when: Each time a new output is added. + */ +struct output_added_signal +{ + wf::output_t *output; +}; + +/** + * on: output, output-layout(output-) + * when: Emitted just before starting the destruction procedure for an output. + */ +struct output_pre_remove_signal +{ + wf::output_t *output; +}; + +/** + * on: output-layout + * when: Each time a new output is added. + */ +struct output_removed_signal +{ + wf::output_t *output; +}; + +enum output_config_field_t +{ + /** Output source changed */ + OUTPUT_SOURCE_CHANGE = (1 << 0), + /** Output mode changed */ + OUTPUT_MODE_CHANGE = (1 << 1), + /** Output scale changed */ + OUTPUT_SCALE_CHANGE = (1 << 2), + /** Output transform changed */ + OUTPUT_TRANSFORM_CHANGE = (1 << 3), + /** Output position changed */ + OUTPUT_POSITION_CHANGE = (1 << 4), +}; + +struct output_state_t; + +/** + * on: output-layout + * when: Each time the configuration of the output layout changes. + */ +struct output_layout_configuration_changed_signal +{}; + +/** + * on: output + * when: Each time the output's source, mode, scale, transform and/or position changes. + */ +struct output_configuration_changed_signal +{ + wf::output_t *output; + output_configuration_changed_signal(const wf::output_state_t& st) : state(st) + {} + + /** + * Which output attributes actually changed. + * A bitwise OR of output_config_field_t. + */ + uint32_t changed_fields; + + /** + * The new state of the output. + */ + const wf::output_state_t& state; +}; + /** Represents the source of pixels for this output */ enum output_image_source_t { diff --git a/src/api/wayfire/per-output-plugin.hpp b/src/api/wayfire/per-output-plugin.hpp index a6192ac6e..288c40ff6 100644 --- a/src/api/wayfire/per-output-plugin.hpp +++ b/src/api/wayfire/per-output-plugin.hpp @@ -1,5 +1,3 @@ -#include "wayfire/object.hpp" -#include "wayfire/signal-definitions.hpp" #include "wayfire/signal-provider.hpp" #include #include diff --git a/src/api/wayfire/plugin.hpp b/src/api/wayfire/plugin.hpp index 3929b5512..db4da8eaf 100644 --- a/src/api/wayfire/plugin.hpp +++ b/src/api/wayfire/plugin.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include class wayfire_config; namespace wf diff --git a/src/api/wayfire/render-manager.hpp b/src/api/wayfire/render-manager.hpp index f4f4c7ab9..17da9d235 100644 --- a/src/api/wayfire/render-manager.hpp +++ b/src/api/wayfire/render-manager.hpp @@ -1,5 +1,6 @@ #pragma once +#include "wayfire/opengl.hpp" #include #include #include diff --git a/src/api/wayfire/scene.hpp b/src/api/wayfire/scene.hpp index 9f8158858..06438d183 100644 --- a/src/api/wayfire/scene.hpp +++ b/src/api/wayfire/scene.hpp @@ -1,15 +1,12 @@ #pragma once -#include "wayfire/opengl.hpp" #include #include #include -#include #include #include #include #include -#include #include namespace wf @@ -71,6 +68,10 @@ class node_t; using node_ptr = std::shared_ptr; using node_weak_ptr = std::weak_ptr; +class render_instance_t; +using render_instance_uptr = std::unique_ptr; +using damage_callback = std::function; + /** * Describes the current state of a node. */ diff --git a/src/api/wayfire/seat.hpp b/src/api/wayfire/seat.hpp index d29f2a639..ad095cd08 100644 --- a/src/api/wayfire/seat.hpp +++ b/src/api/wayfire/seat.hpp @@ -16,6 +16,23 @@ enum class keyboard_focus_reason UNKNOWN, }; +/** + * on: core + * when: Keyboard focus is changed (may change to nullptr). + */ +struct keyboard_focus_changed_signal +{ + wf::scene::node_ptr new_focus; + keyboard_focus_reason reason = keyboard_focus_reason::UNKNOWN; +}; + +/** + * on: core + * when: Seat activity has happened after being idle. + */ +struct seat_activity_signal +{}; + /** * A seat represents a group of input devices (mouse, keyboard, etc.) which logically belong together. * Each seat has its own keyboard, touch, pointer and tablet focus. diff --git a/src/api/wayfire/signal-definitions.hpp b/src/api/wayfire/signal-definitions.hpp index 46070397c..933304ae8 100644 --- a/src/api/wayfire/signal-definitions.hpp +++ b/src/api/wayfire/signal-definitions.hpp @@ -3,7 +3,6 @@ #include "wayfire/view.hpp" #include "wayfire/output.hpp" -#include "wayfire/seat.hpp" /** * Documentation of signals emitted from core components. @@ -195,23 +194,6 @@ struct touch_focus_changed_signal struct reload_config_signal {}; -/** - * on: core - * when: Keyboard focus is changed (may change to nullptr). - */ -struct keyboard_focus_changed_signal -{ - wf::scene::node_ptr new_focus; - keyboard_focus_reason reason = keyboard_focus_reason::UNKNOWN; -}; - -/** - * on: core - * when: Seat activity has happened after being idle. - */ -struct seat_activity_signal -{}; - /** * on: core * when: idle inhibit changed. @@ -221,84 +203,6 @@ struct idle_inhibit_changed_signal bool inhibit; }; -/* ----------------------------------------------------------------------------/ - * Output signals - * -------------------------------------------------------------------------- */ - -/** Base class for all output signals. */ - -/** - * on: output-layout - * when: Each time a new output is added. - */ -struct output_added_signal -{ - wf::output_t *output; -}; - -/** - * on: output, output-layout(output-) - * when: Emitted just before starting the destruction procedure for an output. - */ -struct output_pre_remove_signal -{ - wf::output_t *output; -}; - -/** - * on: output-layout - * when: Each time a new output is added. - */ -struct output_removed_signal -{ - wf::output_t *output; -}; - -enum output_config_field_t -{ - /** Output source changed */ - OUTPUT_SOURCE_CHANGE = (1 << 0), - /** Output mode changed */ - OUTPUT_MODE_CHANGE = (1 << 1), - /** Output scale changed */ - OUTPUT_SCALE_CHANGE = (1 << 2), - /** Output transform changed */ - OUTPUT_TRANSFORM_CHANGE = (1 << 3), - /** Output position changed */ - OUTPUT_POSITION_CHANGE = (1 << 4), -}; - -struct output_state_t; - -/** - * on: output-layout - * when: Each time the configuration of the output layout changes. - */ -struct output_layout_configuration_changed_signal -{}; - -/** - * on: output - * when: Each time the output's source, mode, scale, transform and/or position changes. - */ -struct output_configuration_changed_signal -{ - wf::output_t *output; - output_configuration_changed_signal(const wf::output_state_t& st) : state(st) - {} - - /** - * Which output attributes actually changed. - * A bitwise OR of output_config_field_t. - */ - uint32_t changed_fields; - - /** - * The new state of the output. - */ - const wf::output_state_t& state; -}; - /** * on: output, core(output-) * when: Immediately after the output becomes focused. diff --git a/src/api/wayfire/signal-provider.hpp b/src/api/wayfire/signal-provider.hpp index 64e28518e..133c89137 100644 --- a/src/api/wayfire/signal-provider.hpp +++ b/src/api/wayfire/signal-provider.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include diff --git a/src/api/wayfire/txn/transaction-object.hpp b/src/api/wayfire/txn/transaction-object.hpp index 1da48557f..3f4375f85 100644 --- a/src/api/wayfire/txn/transaction-object.hpp +++ b/src/api/wayfire/txn/transaction-object.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include namespace wf { diff --git a/src/api/wayfire/unstable/wlr-surface-node.hpp b/src/api/wayfire/unstable/wlr-surface-node.hpp index af65f9424..770238527 100644 --- a/src/api/wayfire/unstable/wlr-surface-node.hpp +++ b/src/api/wayfire/unstable/wlr-surface-node.hpp @@ -6,6 +6,7 @@ #include "wayfire/view-transform.hpp" #include #include +#include namespace wf { diff --git a/src/api/wayfire/view.hpp b/src/api/wayfire/view.hpp index 8f9ad5726..8c8ac1356 100644 --- a/src/api/wayfire/view.hpp +++ b/src/api/wayfire/view.hpp @@ -3,13 +3,10 @@ #include #include -#include #include #include "wayfire/nonstd/tracking-allocator.hpp" #include "wayfire/object.hpp" -#include "wayfire/geometry.hpp" -#include "wayfire/view-transform.hpp" #include #include #include @@ -29,6 +26,7 @@ class output_t; namespace scene { class view_node_t; +class transform_manager_node_t; } /* abstraction for desktop-apis, no real need for plugins diff --git a/src/core/core.cpp b/src/core/core.cpp index c60365343..64ee3341f 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -12,6 +12,7 @@ #include "wayfire/bindings-repository.hpp" #include "wayfire/util.hpp" #include +#include "wayfire/config-backend.hpp" // IWYU pragma: keep #include "plugin-loader.hpp" #include "seat/tablet.hpp" diff --git a/src/core/output-layout.cpp b/src/core/output-layout.cpp index 4b2148288..8c5adaea9 100644 --- a/src/core/output-layout.cpp +++ b/src/core/output-layout.cpp @@ -6,6 +6,7 @@ #include "wayfire/render-manager.hpp" #include "wayfire/signal-definitions.hpp" #include "wayfire/util.hpp" +#include "wayfire/config-backend.hpp" #include "../output/output-impl.hpp" #include diff --git a/src/core/seat/input-manager.cpp b/src/core/seat/input-manager.cpp index a91153259..c74e7aef0 100644 --- a/src/core/seat/input-manager.cpp +++ b/src/core/seat/input-manager.cpp @@ -1,17 +1,14 @@ #include -#include #include "pointer.hpp" #include "wayfire/core.hpp" #include "wayfire/signal-definitions.hpp" #include "../core-impl.hpp" -#include "../../output/output-impl.hpp" -#include "touch.hpp" #include "keyboard.hpp" #include "cursor.hpp" #include "input-manager.hpp" #include "wayfire/output-layout.hpp" #include "wayfire/view.hpp" -#include "wayfire/workspace-set.hpp" +#include "wayfire/config-backend.hpp" #include #include diff --git a/src/core/seat/input-manager.hpp b/src/core/seat/input-manager.hpp index 54392396e..14a0eb386 100644 --- a/src/core/seat/input-manager.hpp +++ b/src/core/seat/input-manager.hpp @@ -1,14 +1,11 @@ #ifndef INPUT_MANAGER_HPP #define INPUT_MANAGER_HPP -#include +#include #include -#include #include "seat-impl.hpp" -#include "wayfire/plugin.hpp" #include "wayfire/signal-provider.hpp" -#include "wayfire/view.hpp" #include "wayfire/core.hpp" #include "wayfire/signal-definitions.hpp" #include diff --git a/src/core/seat/input-method-relay.hpp b/src/core/seat/input-method-relay.hpp index 7a5b81a19..c85c34a2f 100644 --- a/src/core/seat/input-method-relay.hpp +++ b/src/core/seat/input-method-relay.hpp @@ -1,9 +1,9 @@ #pragma once #include "wayfire/util.hpp" -#include "wayfire/signal-definitions.hpp" #include "wayfire/view.hpp" #include #include +#include #include #include diff --git a/src/output/output-impl.hpp b/src/output/output-impl.hpp index d7e0086fa..a73fbbf03 100644 --- a/src/output/output-impl.hpp +++ b/src/output/output-impl.hpp @@ -5,13 +5,13 @@ #include "wayfire/plugin.hpp" #include "wayfire/scene-render.hpp" #include "wayfire/scene.hpp" -#include "wayfire/signal-definitions.hpp" -#include "wayfire/signal-provider.hpp" #include #include #include #include +#include +#include namespace wf { diff --git a/src/view/xdg-shell.hpp b/src/view/xdg-shell.hpp index 832f9c976..91140f0ad 100644 --- a/src/view/xdg-shell.hpp +++ b/src/view/xdg-shell.hpp @@ -3,7 +3,7 @@ #include "view-impl.hpp" #include "wayfire/geometry.hpp" -#include "wayfire/signal-definitions.hpp" +#include "wayfire/seat.hpp" #include "wayfire/signal-provider.hpp" #include "wayfire/view.hpp" From d0f7fc32c7e9adbf81dca1e9202ac2ed46882c42 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Sat, 6 Jul 2024 17:44:37 +0200 Subject: [PATCH 03/12] signal-provider: hide implementation details --- src/api/wayfire/nonstd/tracking-allocator.hpp | 1 + src/api/wayfire/signal-provider.hpp | 44 +++++--------- src/api/wayfire/txn/transaction-object.hpp | 8 +-- src/core/object.cpp | 58 ++++++++++++++++++- src/core/txn/transaction.cpp | 8 +++ test/misc/tracking-allocator.cpp | 1 + 6 files changed, 79 insertions(+), 41 deletions(-) diff --git a/src/api/wayfire/nonstd/tracking-allocator.hpp b/src/api/wayfire/nonstd/tracking-allocator.hpp index 61e8c2a12..b1d88ecbc 100644 --- a/src/api/wayfire/nonstd/tracking-allocator.hpp +++ b/src/api/wayfire/nonstd/tracking-allocator.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include #include diff --git a/src/api/wayfire/signal-provider.hpp b/src/api/wayfire/signal-provider.hpp index 133c89137..c80252659 100644 --- a/src/api/wayfire/signal-provider.hpp +++ b/src/api/wayfire/signal-provider.hpp @@ -1,9 +1,7 @@ #pragma once #include -#include -#include -#include +#include #include #include @@ -47,7 +45,7 @@ class connection_base_t // Allow provider to deregister itself friend class provider_t; - std::unordered_set connected_to; + std::vector connected_to; }; /** @@ -136,26 +134,17 @@ class provider_t template void connect(connection_t *callback) { - typed_connections[index()].push_back(callback); - callback->connected_to.insert(this); + connect_base(index(), callback); } /** Unregister a connection. */ - void disconnect(connection_base_t *callback) - { - callback->connected_to.erase(this); - for (auto& [id, connected] : typed_connections) - { - connected.remove_all(callback); - } - } + void disconnect(connection_base_t *callback); /** Emit the given signal. */ template void emit(SignalType *data) { - auto& conns = typed_connections[std::type_index(typeid(SignalType))]; - conns.for_each([&] (connection_base_t *tc) + this->for_each_connection(index(), [&] (connection_base_t *tc) { auto real_type = dynamic_cast*>(tc); assert(real_type); @@ -163,19 +152,8 @@ class provider_t }); } - provider_t() - {} - - ~provider_t() - { - for (auto& [id, connected] : typed_connections) - { - connected.for_each([&] (connection_base_t *base) - { - base->connected_to.erase(this); - }); - } - } + provider_t(); + ~provider_t(); // Non-movable, non-copyable: connection_t keeps reference to this object. // Unclear what happens if this object is duplicated, and plugins usually @@ -192,8 +170,12 @@ class provider_t return std::type_index(typeid(SignalType)); } - std::unordered_map> - typed_connections; + void connect_base(std::type_index type, connection_base_t *callback); + void for_each_connection(std::type_index type, std::function func); + void disconnect_other_side(connection_base_t *callback); + + struct impl; + std::unique_ptr priv; }; } } diff --git a/src/api/wayfire/txn/transaction-object.hpp b/src/api/wayfire/txn/transaction-object.hpp index 3f4375f85..2b959e9ce 100644 --- a/src/api/wayfire/txn/transaction-object.hpp +++ b/src/api/wayfire/txn/transaction-object.hpp @@ -61,12 +61,6 @@ struct object_ready_signal /** * Emit the object-ready signal on the given object. */ -inline void emit_object_ready(wf::txn::transaction_object_t *obj) -{ - wf::txn::object_ready_signal data_ready; - data_ready.self = obj; - obj->emit(&data_ready); - return; -} +void emit_object_ready(wf::txn::transaction_object_t *obj); } } diff --git a/src/core/object.cpp b/src/core/object.cpp index 744b9b279..2f17cbd78 100644 --- a/src/core/object.cpp +++ b/src/core/object.cpp @@ -1,9 +1,52 @@ #include "wayfire/object.hpp" -#include "wayfire/nonstd/safe-list.hpp" #include -#include - #include +#include + +struct wf::signal::provider_t::impl +{ + std::unordered_map> typed_connections; +}; + +wf::signal::provider_t::provider_t() +{ + this->priv = std::make_unique(); +} + +wf::signal::provider_t::~provider_t() +{ + for (auto& [id, connected] : priv->typed_connections) + { + connected.for_each([&] (connection_base_t *base) { disconnect_other_side(base); }); + } +} + +void wf::signal::provider_t::disconnect_other_side(connection_base_t *callback) +{ + auto it = std::find(callback->connected_to.begin(), callback->connected_to.end(), this); + if (it != callback->connected_to.end()) + { + auto last = std::prev(callback->connected_to.end()); + if (it != last) + { + std::iter_swap(it, last); + } + + callback->connected_to.pop_back(); + } +} + +void wf::signal::provider_t::connect_base(std::type_index idx, connection_base_t *callback) +{ + priv->typed_connections[idx].push_back(callback); + callback->connected_to.push_back(this); +} + +void wf::signal::provider_t::for_each_connection( + std::type_index type, std::function func) +{ + priv->typed_connections[type].for_each(func); +} void wf::signal::connection_base_t::disconnect() { @@ -14,6 +57,15 @@ void wf::signal::connection_base_t::disconnect() } } +void wf::signal::provider_t::disconnect(connection_base_t *callback) +{ + disconnect_other_side(callback); + for (auto& [id, connected] : priv->typed_connections) + { + connected.remove_all(callback); + } +} + class wf::object_base_t::obase_impl { public: diff --git a/src/core/txn/transaction.cpp b/src/core/txn/transaction.cpp index fe8f8dc62..ba466baac 100644 --- a/src/core/txn/transaction.cpp +++ b/src/core/txn/transaction.cpp @@ -118,3 +118,11 @@ std::unique_ptr wf::txn::transaction_t::create(int64_t t return std::make_unique(timeout); } + +void wf::txn::emit_object_ready(wf::txn::transaction_object_t *obj) +{ + wf::txn::object_ready_signal data_ready; + data_ready.self = obj; + obj->emit(&data_ready); + return; +} diff --git a/test/misc/tracking-allocator.cpp b/test/misc/tracking-allocator.cpp index 034c29d81..7aebf0cbb 100644 --- a/test/misc/tracking-allocator.cpp +++ b/test/misc/tracking-allocator.cpp @@ -6,6 +6,7 @@ class base_t : public wf::signal::provider_t { public: + using wf::signal::provider_t::provider_t; static int destroyed; virtual ~base_t() { From eb57e8c12dd54d10b23d1decf14bafae8d4c0e08 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Sun, 14 Jul 2024 09:19:55 +0200 Subject: [PATCH 04/12] core: forward declare option wrapper templates --- src/api/wayfire/option-wrapper.hpp | 16 ++++++++++++++++ src/core/core.cpp | 14 ++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/api/wayfire/option-wrapper.hpp b/src/api/wayfire/option-wrapper.hpp index c1765e346..986ead7a0 100644 --- a/src/api/wayfire/option-wrapper.hpp +++ b/src/api/wayfire/option-wrapper.hpp @@ -54,4 +54,20 @@ class option_wrapper_t : public base_option_wrapper_t return wf::get_core().config.get_option(name); } }; + +extern template class option_wrapper_t; + +extern template class option_wrapper_t; + +extern template class option_wrapper_t; + +extern template class option_wrapper_t; + +extern template class option_wrapper_t; } + +extern template class std::shared_ptr>; +extern template class std::shared_ptr>; +extern template class std::shared_ptr>; +extern template class std::shared_ptr>; +extern template class std::shared_ptr>; diff --git a/src/core/core.cpp b/src/core/core.cpp index 64ee3341f..28d7c06d4 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -632,3 +632,17 @@ std::unique_ptr wf::compositor_core_impl_t::static_c // TODO: move this to a better location wf_runtime_config runtime_config; + +#include + +template class wf::option_wrapper_t; +template class wf::option_wrapper_t; +template class wf::option_wrapper_t; +template class wf::option_wrapper_t; +template class wf::option_wrapper_t; + +template class std::shared_ptr>; +template class std::shared_ptr>; +template class std::shared_ptr>; +template class std::shared_ptr>; +template class std::shared_ptr>; From 22ac0f113113e69ddf6e9158e48c93f3ef4eade2 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 24 Jul 2024 10:35:30 +0200 Subject: [PATCH 05/12] core.hpp: do not include config manager --- plugins/ipc-rules/ipc-utility-methods.hpp | 5 +++-- plugins/single_plugins/autostart.cpp | 3 ++- src/api/wayfire/core.hpp | 8 ++++++-- src/api/wayfire/option-wrapper.hpp | 5 +++-- src/core/core.cpp | 10 +++++++++- src/core/plugin.cpp | 21 +++++++++------------ src/main.cpp | 2 +- 7 files changed, 33 insertions(+), 21 deletions(-) diff --git a/plugins/ipc-rules/ipc-utility-methods.hpp b/plugins/ipc-rules/ipc-utility-methods.hpp index 1c206e8c3..bd61ca849 100644 --- a/plugins/ipc-rules/ipc-utility-methods.hpp +++ b/plugins/ipc-rules/ipc-utility-methods.hpp @@ -8,6 +8,7 @@ #include #include #include +#include extern "C" { #include @@ -115,7 +116,7 @@ class ipc_rules_utility_methods_t { WFJSON_EXPECT_FIELD(data, "option", string); - auto option = wf::get_core().config.get_option(data["option"]); + auto option = wf::get_core().config->get_option(data["option"]); if (!option) { return wf::ipc::json_error("Option not found!"); @@ -245,7 +246,7 @@ class ipc_rules_utility_methods_t for (auto& [option, value] : data.items()) { - auto opt = wf::get_core().config.get_option(option); + auto opt = wf::get_core().config->get_option(option); if (!opt) { return wf::ipc::json_error(option + ": Option not found!"); diff --git a/plugins/single_plugins/autostart.cpp b/plugins/single_plugins/autostart.cpp index 78d54ab87..92dd52a04 100644 --- a/plugins/single_plugins/autostart.cpp +++ b/plugins/single_plugins/autostart.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include class wayfire_autostart : public wf::plugin_interface_t @@ -14,7 +15,7 @@ class wayfire_autostart : public wf::plugin_interface_t void init() override { /* Run only once, at startup */ - auto section = wf::get_core().config.get_section("autostart"); + auto section = wf::get_core().config->get_section("autostart"); bool panel_manually_started = false; bool background_manually_started = false; diff --git a/src/api/wayfire/core.hpp b/src/api/wayfire/core.hpp index d2ebb60bc..ddd0105ed 100644 --- a/src/api/wayfire/core.hpp +++ b/src/api/wayfire/core.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -38,6 +37,11 @@ namespace touch class gesture_t; struct gesture_state_t; } + +namespace config +{ +class config_manager_t; +} } using wayfire_view = nonstd::observer_ptr; @@ -80,7 +84,7 @@ class compositor_core_t : public wf::object_base_t, public signal::provider_t /** * The current configuration used by Wayfire */ - wf::config::config_manager_t config; + std::unique_ptr config; /** * Command line arguments. diff --git a/src/api/wayfire/option-wrapper.hpp b/src/api/wayfire/option-wrapper.hpp index 986ead7a0..f1e726d97 100644 --- a/src/api/wayfire/option-wrapper.hpp +++ b/src/api/wayfire/option-wrapper.hpp @@ -14,6 +14,7 @@ namespace detail void option_wrapper_debug_message(const std::string& option_name, const std::runtime_error& err); [[noreturn]] void option_wrapper_debug_message(const std::string& option_name, const std::logic_error& err); +std::shared_ptr load_raw_option(const std::string& name); } /** @@ -49,9 +50,9 @@ class option_wrapper_t : public base_option_wrapper_t {} protected: - std::shared_ptr load_raw_option(const std::string& name) + std::shared_ptr load_raw_option(const std::string& name) override { - return wf::get_core().config.get_option(name); + return detail::load_raw_option(name); } }; diff --git a/src/core/core.cpp b/src/core/core.cpp index 28d7c06d4..7b4742a86 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -583,7 +583,10 @@ const std::shared_ptr& wf::compositor_core_impl_t::scene } wf::compositor_core_t::compositor_core_t() -{} +{ + this->config = std::make_unique(); +} + wf::compositor_core_t::~compositor_core_t() {} @@ -633,6 +636,11 @@ std::unique_ptr wf::compositor_core_impl_t::static_c // TODO: move this to a better location wf_runtime_config runtime_config; +std::shared_ptr wf::detail::load_raw_option(const std::string& name) +{ + return wf::get_core().config->get_option(name); +} + #include template class wf::option_wrapper_t; diff --git a/src/core/plugin.cpp b/src/core/plugin.cpp index 6d7d8917d..24caa0413 100644 --- a/src/core/plugin.cpp +++ b/src/core/plugin.cpp @@ -1,10 +1,7 @@ -#include "core-impl.hpp" #include "wayfire/debug.hpp" -#include "wayfire/output.hpp" -#include "seat/input-manager.hpp" -#include "wayfire/signal-definitions.hpp" #include #include +#include void wf::plugin_interface_t::fini() {} @@ -18,13 +15,13 @@ std::shared_ptr wf::config_backend_t::get_output_section( std::string name = output->name; name = "output:" + name; auto& config = wf::get_core().config; - if (!config.get_section(name)) + if (!config->get_section(name)) { - config.merge_section( - config.get_section("output")->clone_with_name(name)); + config->merge_section( + config->get_section("output")->clone_with_name(name)); } - return config.get_section(name); + return config->get_section(name); } std::shared_ptr wf::config_backend_t::get_input_device_section( @@ -33,13 +30,13 @@ std::shared_ptr wf::config_backend_t::get_input_device_sectio std::string name = nonull(device->name); name = "input-device:" + name; auto& config = wf::get_core().config; - if (!config.get_section(name)) + if (!config->get_section(name)) { - config.merge_section( - config.get_section("input-device")->clone_with_name(name)); + config->merge_section( + config->get_section("input-device")->clone_with_name(name)); } - return config.get_section(name); + return config->get_section(name); } std::vector wf::config_backend_t::get_xml_dirs() const diff --git a/src/main.cpp b/src/main.cpp index 498bb8e56..ec8a8eb8b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -420,7 +420,7 @@ int main(int argc, char *argv[]) LOGD("Using configuration backend: ", config_backend); core.config_backend = std::unique_ptr(backend); - core.config_backend->init(display, core.config, config_file); + core.config_backend->init(display, *core.config, config_file); core.init(); auto socket = choose_socket(core.display); From 2be92c8bb81a5b8d31548132f352665728823e21 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 24 Jul 2024 10:42:39 +0200 Subject: [PATCH 06/12] seat.hpp: do not include wlroots-full.hpp There is no need for this header at all. --- src/api/wayfire/seat.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/wayfire/seat.hpp b/src/api/wayfire/seat.hpp index ad095cd08..066bce884 100644 --- a/src/api/wayfire/seat.hpp +++ b/src/api/wayfire/seat.hpp @@ -3,7 +3,6 @@ #include #include #include -#include #include namespace wf From 1683d3f1c500865614baa8a456771ead7d47662b Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Sun, 14 Jul 2024 09:55:00 +0200 Subject: [PATCH 07/12] add .cache to gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9e0f7ab01..85376ffdd 100644 --- a/.gitignore +++ b/.gitignore @@ -62,4 +62,6 @@ build/** -# End of https://www.toptal.com/developers/gitignore/api/c++,meson,ninja,linux \ No newline at end of file +.cache/** + +# End of https://www.toptal.com/developers/gitignore/api/c++,meson,ninja,linux From 2d70f2d329129361ab01e9c342959c6a3619a92b Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Mon, 15 Jul 2024 22:48:44 +0200 Subject: [PATCH 08/12] [DONOTMERGE] A tentative implementation for custom plugin PCH --- meson_options.txt | 1 + plugins/animate/meson.build | 8 ++++- plugins/blur/meson.build | 6 ++-- plugins/cube/meson.build | 3 +- plugins/decor/meson.build | 3 +- plugins/grid/meson.build | 3 +- plugins/ipc-rules/ipc-events.hpp | 1 - plugins/ipc-rules/ipc-rules-common.hpp | 1 - plugins/ipc-rules/meson.build | 3 +- plugins/ipc/ipc-helpers.hpp | 2 +- plugins/ipc/ipc-method-repository.hpp | 2 +- plugins/ipc/ipc.hpp | 2 +- plugins/ipc/meson.build | 9 +++-- plugins/meson.build | 36 +++++++++++++++++++ plugins/pch/pch.hpp | 13 +++++++ plugins/protocols/meson.build | 3 +- plugins/scale/meson.build | 4 ++- plugins/single_plugins/meson.build | 3 +- plugins/tile/meson.build | 3 +- plugins/tile/tile-ipc.hpp | 1 - plugins/vswitch/meson.build | 3 +- plugins/window-rules/meson.build | 6 ++-- plugins/wm-actions/meson.build | 3 +- plugins/wobbly/meson.build | 8 +++-- .../wayfire/plugins/wobbly/wobbly-signal.hpp | 1 + src/api/wayfire/nonstd/wlroots.hpp | 2 +- src/api/wayfire/per-output-plugin.hpp | 2 ++ 27 files changed, 104 insertions(+), 28 deletions(-) create mode 100644 plugins/pch/pch.hpp diff --git a/meson_options.txt b/meson_options.txt index c827933b0..1e5148b44 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,3 +6,4 @@ option('xwayland', type: 'feature', value: 'auto', description: 'Build with xway option('default_config_backend', type: 'string', value: 'default', description: 'Default configuration backend to use') option('print_trace', type: 'boolean', value: true, description: 'Print stack trace in debug logs (disables coredump)') option('tests', type: 'feature', value: 'auto', description: 'Enable unit tests') +option('custom_pch', type: 'boolean', value: false, description: 'Use custom PCH for plugins. May not work with all compilers and setups.') diff --git a/plugins/animate/meson.build b/plugins/animate/meson.build index eef601bb1..dcca2f226 100644 --- a/plugins/animate/meson.build +++ b/plugins/animate/meson.build @@ -1,7 +1,12 @@ dependencies = [wlroots, pixman, wfconfig] +animate_pch_deps = [plugin_pch_dep] +animate_pch_flags = plugin_pch_args if get_option('enable_openmp') dependencies += [dependency('openmp')] + # PCH does not have openmp enabled + animate_pch_deps = [] + animate_pch_args = [] endif animiate = shared_module('animate', @@ -9,6 +14,7 @@ animiate = shared_module('animate', 'fire/particle.cpp', 'fire/fire.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc], - dependencies: dependencies, + dependencies: dependencies + animate_pch_deps, + cpp_args: animate_pch_args, install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/plugins/blur/meson.build b/plugins/blur/meson.build index 609fa3178..71f923aea 100644 --- a/plugins/blur/meson.build +++ b/plugins/blur/meson.build @@ -1,7 +1,8 @@ blur_base = shared_library('wayfire-blur-base', ['blur-base.cpp', 'box.cpp', 'gaussian.cpp', 'kawase.cpp', 'bokeh.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc], - dependencies: [wlroots, pixman, wfconfig], + dependencies: [wlroots, pixman, wfconfig, plugin_pch_dep], + cpp_args: plugin_pch_args, override_options: ['b_lundef=false'], install: true) install_headers(['blur.hpp'], subdir: 'wayfire/plugins/blur') @@ -9,5 +10,6 @@ install_headers(['blur.hpp'], subdir: 'wayfire/plugins/blur') blur = shared_module('blur', ['blur.cpp'], link_with: blur_base, include_directories: [wayfire_api_inc, wayfire_conf_inc], - dependencies: [wlroots, pixman, wfconfig], + dependencies: [wlroots, pixman, wfconfig, plugin_pch_dep], + cpp_args: plugin_pch_args, install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/plugins/cube/meson.build b/plugins/cube/meson.build index 3d7abcbb8..9c7ecf5b9 100644 --- a/plugins/cube/meson.build +++ b/plugins/cube/meson.build @@ -1,6 +1,7 @@ animiate = shared_module('cube', ['cube.cpp', 'cubemap.cpp', 'skydome.cpp', 'simple-background.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, ipc_include_dirs], - dependencies: [wlroots, pixman, wfconfig, json], + dependencies: [wlroots, pixman, wfconfig, json, plugin_pch_dep], + cpp_args: plugin_pch_args, install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/plugins/decor/meson.build b/plugins/decor/meson.build index f7e71d6a4..1f879359f 100644 --- a/plugins/decor/meson.build +++ b/plugins/decor/meson.build @@ -2,6 +2,7 @@ decoration = shared_module('decoration', ['decoration.cpp', 'deco-subsurface.cpp', 'deco-button.cpp', 'deco-layout.cpp', 'deco-theme.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc], - dependencies: [wlroots, pixman, wf_protos, wfconfig, cairo, pango, pangocairo], + dependencies: [wlroots, pixman, wf_protos, wfconfig, cairo, pango, pangocairo, plugin_pch_dep], + cpp_args: plugin_pch_args, install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/plugins/grid/meson.build b/plugins/grid/meson.build index b91770410..52879af38 100644 --- a/plugins/grid/meson.build +++ b/plugins/grid/meson.build @@ -1,10 +1,11 @@ grid_inc = include_directories('.') all_include_dirs = [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, wobbly_inc, grid_inc] -all_deps = [wlroots, pixman, wfconfig, wftouch, cairo, json] +all_deps = [wlroots, pixman, wfconfig, wftouch, cairo, json, plugin_pch_dep] shared_module('grid', ['grid.cpp'], include_directories: all_include_dirs, dependencies: all_deps, + cpp_args: plugin_pch_args, install: true, install_dir: conf_data.get('PLUGIN_PATH')) diff --git a/plugins/ipc-rules/ipc-events.hpp b/plugins/ipc-rules/ipc-events.hpp index f3822272b..639d862b3 100644 --- a/plugins/ipc-rules/ipc-events.hpp +++ b/plugins/ipc-rules/ipc-events.hpp @@ -4,7 +4,6 @@ #include #include "plugins/ipc/ipc-method-repository.hpp" #include -#include namespace wf { diff --git a/plugins/ipc-rules/ipc-rules-common.hpp b/plugins/ipc-rules/ipc-rules-common.hpp index afb36d288..4cecf7f66 100644 --- a/plugins/ipc-rules/ipc-rules-common.hpp +++ b/plugins/ipc-rules/ipc-rules-common.hpp @@ -2,7 +2,6 @@ #include "plugins/ipc/ipc-helpers.hpp" #include #include -#include #include #include "config.h" #include "wayfire/plugins/common/util.hpp" diff --git a/plugins/ipc-rules/meson.build b/plugins/ipc-rules/meson.build index d475b700d..32ec3944e 100644 --- a/plugins/ipc-rules/meson.build +++ b/plugins/ipc-rules/meson.build @@ -1,8 +1,9 @@ all_include_dirs = [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc] -all_deps = [wlroots, pixman, wfconfig, wftouch, json] +all_deps = [wlroots, pixman, wfconfig, wftouch, json, plugin_pch_dep] shared_module('ipc-rules', ['ipc-rules.cpp'], include_directories: all_include_dirs, + cpp_args: plugin_pch_args, dependencies: all_deps, install: true, install_dir: conf_data.get('PLUGIN_PATH')) diff --git a/plugins/ipc/ipc-helpers.hpp b/plugins/ipc/ipc-helpers.hpp index c6cd4814f..ea3437fbb 100644 --- a/plugins/ipc/ipc-helpers.hpp +++ b/plugins/ipc/ipc-helpers.hpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include // IWYU pragma: keep namespace wf { diff --git a/plugins/ipc/ipc-method-repository.hpp b/plugins/ipc/ipc-method-repository.hpp index 0b4233310..1105c6f1c 100644 --- a/plugins/ipc/ipc-method-repository.hpp +++ b/plugins/ipc/ipc-method-repository.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include // IWYU pragma: keep #include #include #include "wayfire/signal-provider.hpp" diff --git a/plugins/ipc/ipc.hpp b/plugins/ipc/ipc.hpp index 2f4666061..69009de75 100644 --- a/plugins/ipc/ipc.hpp +++ b/plugins/ipc/ipc.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include // IWYU pragma: keep #include #include #include diff --git a/plugins/ipc/meson.build b/plugins/ipc/meson.build index a33f56b2c..bfa785bac 100644 --- a/plugins/ipc/meson.build +++ b/plugins/ipc/meson.build @@ -5,21 +5,24 @@ ipc_include_dirs = include_directories('.') ipc = shared_module('ipc', ['ipc.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc], - dependencies: [wlroots, pixman, wfconfig, wftouch, json, evdev], + dependencies: [wlroots, pixman, wfconfig, wftouch, json, evdev, plugin_pch_dep], + cpp_args: plugin_pch_args, install: true, install_dir: conf_data.get('PLUGIN_PATH')) stipc = shared_module('stipc', ['stipc.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc], - dependencies: [wlroots, pixman, wfconfig, wftouch, json, evdev], + dependencies: [wlroots, pixman, wfconfig, wftouch, json, evdev, plugin_pch_dep], + cpp_args: plugin_pch_args, install: true, install_dir: conf_data.get('PLUGIN_PATH')) demoipc = shared_module('demo-ipc', ['demo-ipc.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc], - dependencies: [wlroots, pixman, wfconfig, wftouch, json, evdev], + dependencies: [wlroots, pixman, wfconfig, wftouch, json, evdev, plugin_pch_dep], + cpp_args: plugin_pch_args, install: true, install_dir: conf_data.get('PLUGIN_PATH')) diff --git a/plugins/meson.build b/plugins/meson.build index 7fd9855bb..927646106 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,4 +1,40 @@ subdir('common') + +if get_option('custom_pch') + cc = meson.get_compiler('cpp') + + pch_file = meson.current_source_dir() / 'pch/pch.hpp' + api_headers = meson.project_source_root() / 'src/api' + ipc_headers = meson.project_source_root() / 'plugins/ipc' + proto_headers = meson.project_build_root() / 'proto/libwl_protos.a.p/' + common_headers = meson.project_source_root() / 'plugins/common' + wobbly_headers = meson.project_source_root() / 'plugins/wobbly' + + if cc.get_id() == 'clang' + pch = custom_target('plugin_pch', + input: pch_file, + output: 'plugin_pch.hpp.pch', + command: cc.cmd_array() + ['@INPUT@', '-c', '-o', '@OUTPUT@', + '-std=c++17', '-pthread', '-fPIC', + '-I' + api_headers, + '-I' + ipc_headers, + '-I/usr/include/pixman-1', + '-I' + proto_headers, + '-I' + common_headers, + '-I' + wobbly_headers]) + + plugin_pch_args = ['-include-pch', pch.full_path(), '-pthread'] + plugin_pch_dep = declare_dependency(sources: pch) + elif cc.get_id() == 'gcc' + error('TODO: CUSTOM PCH FOR GCC') + else + error('Unsupported compiler for custom pch: ' + cc.get_id()) + endif +else + plugin_pch_args = [] + plugin_pch_dep = declare_dependency() +endif + subdir('ipc') subdir('protocols') subdir('vswitch') diff --git a/plugins/pch/pch.hpp b/plugins/pch/pch.hpp new file mode 100644 index 000000000..0af01ca84 --- /dev/null +++ b/plugins/pch/pch.hpp @@ -0,0 +1,13 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/plugins/protocols/meson.build b/plugins/protocols/meson.build index 544779536..ecf9d55bf 100644 --- a/plugins/protocols/meson.build +++ b/plugins/protocols/meson.build @@ -4,12 +4,13 @@ protocol_plugins = [ ] all_include_dirs = [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc] -all_deps = [wlroots, pixman, wfconfig, wf_protos, json, cairo, pango, pangocairo] +all_deps = [wlroots, pixman, wfconfig, wf_protos, json, cairo, pango, pangocairo, plugin_pch_dep] foreach plugin : protocol_plugins shared_module(plugin, plugin + '.cpp', include_directories: all_include_dirs, dependencies: all_deps, + cpp_args: plugin_pch_args, install: true, install_dir: conf_data.get('PLUGIN_PATH')) endforeach diff --git a/plugins/scale/meson.build b/plugins/scale/meson.build index 1aea4661d..86ad39dc7 100644 --- a/plugins/scale/meson.build +++ b/plugins/scale/meson.build @@ -1,15 +1,17 @@ all_include_dirs = [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, vswitch_inc, wobbly_inc, include_directories('.')] -all_deps = [wlroots, pixman, wfconfig, wftouch, cairo, pango, pangocairo, json] +all_deps = [wlroots, pixman, wfconfig, wftouch, cairo, pango, pangocairo, json, plugin_pch_dep] shared_module('scale', ['scale.cpp', 'scale-title-overlay.cpp'], include_directories: all_include_dirs, dependencies: all_deps, + cpp_args: plugin_pch_args, install: true, install_dir: conf_data.get('PLUGIN_PATH')) shared_module('scale-title-filter', 'scale-title-filter.cpp', include_directories: all_include_dirs, dependencies: all_deps, + cpp_args: plugin_pch_args, install: true, install_dir: conf_data.get('PLUGIN_PATH')) diff --git a/plugins/single_plugins/meson.build b/plugins/single_plugins/meson.build index 966a102fd..dc6ca8a46 100644 --- a/plugins/single_plugins/meson.build +++ b/plugins/single_plugins/meson.build @@ -6,12 +6,13 @@ plugins = [ ] all_include_dirs = [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, vswitch_inc, wobbly_inc, grid_inc] -all_deps = [wlroots, pixman, wfconfig, wftouch, cairo, pango, pangocairo, json] +all_deps = [wlroots, pixman, wfconfig, wftouch, cairo, pango, pangocairo, json, plugin_pch_dep] foreach plugin : plugins shared_module(plugin, plugin + '.cpp', include_directories: all_include_dirs, dependencies: all_deps, + cpp_args: plugin_pch_args, install: true, install_dir: conf_data.get('PLUGIN_PATH')) endforeach diff --git a/plugins/tile/meson.build b/plugins/tile/meson.build index fa6a8a873..d87e231a3 100644 --- a/plugins/tile/meson.build +++ b/plugins/tile/meson.build @@ -1,7 +1,8 @@ tile = shared_module('simple-tile', ['tile-plugin.cpp', 'tree.cpp', 'tree-controller.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, grid_inc, wobbly_inc, ipc_include_dirs], - dependencies: [wlroots, pixman, wfconfig, json], + dependencies: [wlroots, pixman, wfconfig, json, plugin_pch_dep], + cpp_args: plugin_pch_args, install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/plugins/tile/tile-ipc.hpp b/plugins/tile/tile-ipc.hpp index 667578543..8aedef739 100644 --- a/plugins/tile/tile-ipc.hpp +++ b/plugins/tile/tile-ipc.hpp @@ -4,7 +4,6 @@ #include #include #include "tree.hpp" -#include #include "plugins/ipc/ipc-helpers.hpp" #include "plugins/ipc/ipc-method-repository.hpp" #include "tile-wset.hpp" diff --git a/plugins/vswitch/meson.build b/plugins/vswitch/meson.build index ca76340cc..68da00f5f 100644 --- a/plugins/vswitch/meson.build +++ b/plugins/vswitch/meson.build @@ -3,7 +3,8 @@ vswitch_inc = include_directories('.') vswitch = shared_module('vswitch', ['vswitch.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, vswitch_inc, ipc_include_dirs], - dependencies: [wlroots, pixman, wfconfig, json], + dependencies: [wlroots, pixman, wfconfig, json, plugin_pch_dep], + cpp_args: plugin_pch_args, install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/plugins/window-rules/meson.build b/plugins/window-rules/meson.build index 91c95bee9..e296bc53f 100644 --- a/plugins/window-rules/meson.build +++ b/plugins/window-rules/meson.build @@ -1,7 +1,7 @@ window_rules = shared_module('window-rules', ['window-rules.cpp', 'view-action-interface.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, grid_inc, plugins_common_inc], - dependencies: [wlroots, pixman, wfconfig, wfutils], + dependencies: [wlroots, pixman, wfconfig, wfutils, plugin_pch_dep], + cpp_args: plugin_pch_args, install: true, - install_dir: join_paths(get_option('libdir'), 'wayfire') - ) + install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/plugins/wm-actions/meson.build b/plugins/wm-actions/meson.build index 693fbc4a7..aab953658 100644 --- a/plugins/wm-actions/meson.build +++ b/plugins/wm-actions/meson.build @@ -1,7 +1,8 @@ wm_actions = shared_module('wm-actions', ['wm-actions.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc], - dependencies: [wlroots, pixman, wfconfig, json], + dependencies: [wlroots, pixman, wfconfig, json, plugin_pch_dep], + cpp_args: plugin_pch_args, install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/plugins/wobbly/meson.build b/plugins/wobbly/meson.build index b7faa7ef9..8ef7cbb48 100644 --- a/plugins/wobbly/meson.build +++ b/plugins/wobbly/meson.build @@ -1,7 +1,11 @@ +wobbly_c_model = static_library('wobbly-c-model', ['wobbly.c'], install: false) + wobbly = shared_module('wobbly', - ['wobbly.cpp', 'wobbly.c'], + ['wobbly.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc], - dependencies: [wlroots, pixman, wfconfig], + dependencies: [wlroots, pixman, wfconfig, plugin_pch_dep], + cpp_args: plugin_pch_args, + link_with: wobbly_c_model, install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp b/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp index 540264f7f..34470d61e 100644 --- a/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp +++ b/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp @@ -1,4 +1,5 @@ #pragma once + #include #include #include diff --git a/src/api/wayfire/nonstd/wlroots.hpp b/src/api/wayfire/nonstd/wlroots.hpp index 03a8f5a65..5dbcb2bc7 100644 --- a/src/api/wayfire/nonstd/wlroots.hpp +++ b/src/api/wayfire/nonstd/wlroots.hpp @@ -1,7 +1,7 @@ #pragma once #ifndef WLR_USE_UNSTABLE - #define WLR_USE_UNSTABLE + #define WLR_USE_UNSTABLE 1 #endif /** diff --git a/src/api/wayfire/per-output-plugin.hpp b/src/api/wayfire/per-output-plugin.hpp index 288c40ff6..9fc20bc55 100644 --- a/src/api/wayfire/per-output-plugin.hpp +++ b/src/api/wayfire/per-output-plugin.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "wayfire/signal-provider.hpp" #include #include From a91e136581b7cb5e0badd24026a5b1589037c28a Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 24 Jul 2024 11:28:16 +0200 Subject: [PATCH 09/12] plugins: split workspace-wall into a separate helper library --- plugins/common/meson.build | 9 + .../wayfire/plugins/common/workspace-wall.hpp | 455 +----------------- plugins/common/workspace-wall.cpp | 453 +++++++++++++++++ plugins/meson.build | 13 +- plugins/single_plugins/meson.build | 6 + plugins/vswitch/meson.build | 1 + src/api/wayfire/plugin.hpp | 2 +- src/api/wayfire/toplevel.hpp | 1 + src/core/seat/hotspot-manager.hpp | 1 + src/core/seat/touch.cpp | 1 + src/output/render-manager.cpp | 1 + src/output/workarea.cpp | 1 + 12 files changed, 494 insertions(+), 450 deletions(-) create mode 100644 plugins/common/workspace-wall.cpp diff --git a/plugins/common/meson.build b/plugins/common/meson.build index d401eed7c..ca65f0cf8 100644 --- a/plugins/common/meson.build +++ b/plugins/common/meson.build @@ -1,2 +1,11 @@ plugins_common_inc = include_directories('.') install_subdir('wayfire', install_dir: get_option('includedir')) + +workspace_wall = static_library('wayfire-workspace-wall', + ['workspace-wall.cpp'], + include_directories: [wayfire_api_inc, wayfire_conf_inc], + dependencies: [wlroots, pixman, wfconfig, plugin_pch_dep], + cpp_args: plugin_pch_args, + override_options: ['b_lundef=false'], + install: true) + diff --git a/plugins/common/wayfire/plugins/common/workspace-wall.hpp b/plugins/common/wayfire/plugins/common/workspace-wall.hpp index ceee1cf7a..6a4330da6 100644 --- a/plugins/common/wayfire/plugins/common/workspace-wall.hpp +++ b/plugins/common/wayfire/plugins/common/workspace-wall.hpp @@ -1,19 +1,16 @@ #pragma once - #include "wayfire/workspace-set.hpp" // IWYU pragma: keep #include #include +#include #include "wayfire/core.hpp" #include "wayfire/geometry.hpp" #include "wayfire/opengl.hpp" #include "wayfire/region.hpp" -#include "wayfire/scene-input.hpp" -#include "wayfire/scene-operations.hpp" #include "wayfire/scene-render.hpp" #include "wayfire/scene.hpp" #include "wayfire/signal-provider.hpp" -#include "wayfire/workspace-stream.hpp" #include "wayfire/output.hpp" namespace wf @@ -40,25 +37,16 @@ class workspace_wall_t : public wf::signal::provider_t /** * Create a new workspace wall on the given output. */ - workspace_wall_t(wf::output_t *_output) : output(_output) - { - this->viewport = get_wall_rectangle(); - } + workspace_wall_t(wf::output_t *_output); - ~workspace_wall_t() - { - stop_output_renderer(false); - } + ~workspace_wall_t(); /** * Set the color of the background outside of workspaces. * * @param color The new background color. */ - void set_background_color(const wf::color_t& color) - { - this->background_color = color; - } + void set_background_color(const wf::color_t& color); /** * Set the size of the gap between adjacent workspaces, both horizontally @@ -66,10 +54,7 @@ class workspace_wall_t : public wf::signal::provider_t * * @param size The new gap size, in pixels. */ - void set_gap_size(int size) - { - this->gap_size = size; - } + void set_gap_size(int size); /** * Set which part of the workspace wall to render. @@ -82,20 +67,9 @@ class workspace_wall_t : public wf::signal::provider_t * * @param viewport_geometry The part of the workspace wall to render. */ - void set_viewport(const wf::geometry_t& viewport_geometry) - { - this->viewport = viewport_geometry; - if (render_node) - { - scene::damage_node(this->render_node, - this->render_node->get_bounding_box()); - } - } + void set_viewport(const wf::geometry_t& viewport_geometry); - wf::geometry_t get_viewport() const - { - return viewport; - } + wf::geometry_t get_viewport() const; /** * Render the selected viewport on the framebuffer. @@ -104,22 +78,13 @@ class workspace_wall_t : public wf::signal::provider_t * @param geometry The rectangle in fb to draw to, in the same coordinate * system as the framebuffer's geometry. */ - void render_wall(const wf::render_target_t& fb, const wf::region_t& damage) - { - wall_frame_event_t data{fb}; - this->emit(&data); - } + void render_wall(const wf::render_target_t& fb, const wf::region_t& damage); /** * Register a render hook and paint the whole output as a desktop wall * with the set parameters. */ - void start_output_renderer() - { - wf::dassert(render_node == nullptr, "Starting workspace-wall twice?"); - render_node = std::make_shared(this); - scene::add_front(wf::get_core().scene(), render_node); - } + void start_output_renderer(); /** * Stop repainting the whole output. @@ -127,21 +92,7 @@ class workspace_wall_t : public wf::signal::provider_t * @param reset_viewport If true, the viewport will be reset to {0, 0, 0, 0} * and thus all workspace streams will be stopped. */ - void stop_output_renderer(bool reset_viewport) - { - if (!render_node) - { - return; - } - - scene::remove_child(render_node); - render_node = nullptr; - - if (reset_viewport) - { - set_viewport({0, 0, 0, 0}); - } - } + void stop_output_renderer(bool reset_viewport); /** * Calculate the geometry of a particular workspace, as described in @@ -149,45 +100,17 @@ class workspace_wall_t : public wf::signal::provider_t * * @param ws The workspace whose geometry is to be computed. */ - wf::geometry_t get_workspace_rectangle(const wf::point_t& ws) const - { - auto size = this->output->get_screen_size(); - - return { - ws.x * (size.width + gap_size), - ws.y * (size.height + gap_size), - size.width, - size.height - }; - } + wf::geometry_t get_workspace_rectangle(const wf::point_t& ws) const; /** * Calculate the whole workspace wall region, including gaps around it. */ - wf::geometry_t get_wall_rectangle() const - { - auto size = this->output->get_screen_size(); - auto workspace_size = this->output->wset()->get_workspace_grid_size(); - - return { - -gap_size, - -gap_size, - workspace_size.width * (size.width + gap_size) + gap_size, - workspace_size.height * (size.height + gap_size) + gap_size - }; - } + wf::geometry_t get_wall_rectangle() const; /** * Get/set the dimming factor for a given workspace. */ - void set_ws_dim(const wf::point_t& ws, float value) - { - render_colors[{ws.x, ws.y}] = value; - if (render_node) - { - scene::damage_node(render_node, render_node->get_bounding_box()); - } - } + void set_ws_dim(const wf::point_t& ws, float value); protected: wf::output_t *output; @@ -195,362 +118,16 @@ class workspace_wall_t : public wf::signal::provider_t wf::color_t background_color = {0, 0, 0, 0}; int gap_size = 0; wf::geometry_t viewport = {0, 0, 0, 0}; - std::map, float> render_colors; - - float get_color_for_workspace(wf::point_t ws) - { - auto it = render_colors.find({ws.x, ws.y}); - if (it == render_colors.end()) - { - return 1.0; - } - - return it->second; - } + float get_color_for_workspace(wf::point_t ws); /** * Get a list of workspaces visible in the viewport. */ - std::vector get_visible_workspaces(wf::geometry_t viewport) const - { - std::vector visible; - auto wsize = output->wset()->get_workspace_grid_size(); - for (int i = 0; i < wsize.width; i++) - { - for (int j = 0; j < wsize.height; j++) - { - if (viewport & get_workspace_rectangle({i, j})) - { - visible.push_back({i, j}); - } - } - } - - return visible; - } + std::vector get_visible_workspaces(wf::geometry_t viewport) const; protected: - template using per_workspace_map_t = std::map>; - - class workspace_wall_node_t : public scene::node_t - { - class wwall_render_instance_t : public scene::render_instance_t - { - std::shared_ptr self; - per_workspace_map_t> instances; - - scene::damage_callback push_damage; - wf::signal::connection_t on_wall_damage = - [=] (scene::node_damage_signal *ev) - { - push_damage(ev->region); - }; - - wf::geometry_t get_workspace_rect(wf::point_t ws) - { - auto output_size = self->wall->output->get_screen_size(); - return { - .x = ws.x * (output_size.width + self->wall->gap_size), - .y = ws.y * (output_size.height + self->wall->gap_size), - .width = output_size.width, - .height = output_size.height, - }; - } - - public: - wwall_render_instance_t(workspace_wall_node_t *self, - scene::damage_callback push_damage) - { - this->self = std::dynamic_pointer_cast(self->shared_from_this()); - this->push_damage = push_damage; - self->connect(&on_wall_damage); - - for (int i = 0; i < (int)self->workspaces.size(); i++) - { - for (int j = 0; j < (int)self->workspaces[i].size(); j++) - { - auto push_damage_child = [=] (const wf::region_t& damage) - { - // Store the damage because we'll have to update the buffers - self->aux_buffer_damage[i][j] |= damage; - - wf::region_t our_damage; - for (auto& rect : damage) - { - wf::geometry_t box = wlr_box_from_pixman_box(rect); - box = box + wf::origin(get_workspace_rect({i, j})); - auto A = self->wall->viewport; - auto B = self->get_bounding_box(); - our_damage |= scale_box(A, B, box); - } - - // Also damage the 'screen' after transforming damage - push_damage(our_damage); - }; - - self->workspaces[i][j]->gen_render_instances(instances[i][j], - push_damage_child, self->wall->output); - } - } - } - - static int damage_sum_area(const wf::region_t& damage) - { - int sum = 0; - for (const auto& rect : damage) - { - sum += (rect.y2 - rect.y1) * (rect.x2 - rect.x1); - } - - return sum; - } - - bool consider_rescale_workspace_buffer(int i, int j, wf::region_t& visible_damage) - { - // In general, when rendering the auxilliary buffers for each workspace, we can render the - // workspace thumbnails in a lower resolution, because at the end they are shown scaled. - // This helps with performance and uses less GPU power. - // - // However, the situation is tricky because during the Expo animation the optimal render - // scale constantly changes. Thus, in some cases it is actually far from optimal to rescale - // on every frame - it is often better to just keep the buffers from the old scale. - // - // Nonetheless, we need to make sure to rescale when this makes sense, and to avoid visual - // artifacts. - auto bbox = self->workspaces[i][j]->get_bounding_box(); - const float render_scale = std::max( - 1.0 * bbox.width / self->wall->viewport.width, - 1.0 * bbox.height / self->wall->viewport.height); - const float current_scale = self->aux_buffer_current_scale[i][j]; - - // Avoid keeping a low resolution if we are going up in the scale (for example, expo exit - // animation) and we're close to the 1.0 scale. Otherwise, we risk popping artifacts as we - // suddenly switch from low to high resolution. - const bool rescale_magnification = (render_scale > 0.5) && - (render_scale > current_scale * 1.1); - - // In general, it is worth changing the buffer scale if we have a lot of damage to the old - // buffer, so that for ex. a full re-scale is actually cheaper than repaiting the old buffer. - // This could easily happen for example if we have a video player during Expo start animation. - const int repaint_cost_current_scale = - damage_sum_area(visible_damage) * (current_scale * current_scale); - const int repaint_rescale_cost = (bbox.width * bbox.height) * (render_scale * render_scale); - - if ((repaint_cost_current_scale > repaint_rescale_cost) || rescale_magnification) - { - self->aux_buffer_current_scale[i][j] = render_scale; - self->aux_buffers[i][j].subbuffer = wf::geometry_t{ - 0, 0, - int(std::ceil(render_scale * self->aux_buffers[i][j].viewport_width)), - int(std::ceil(render_scale * self->aux_buffers[i][j].viewport_height)), - }; - - self->aux_buffer_damage[i][j] |= self->workspaces[i][j]->get_bounding_box(); - return true; - } - - return false; - } - - void schedule_instructions( - std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override - { - // Update workspaces in a render pass - for (int i = 0; i < (int)self->workspaces.size(); i++) - { - for (int j = 0; j < (int)self->workspaces[i].size(); j++) - { - const auto ws_bbox = self->wall->get_workspace_rectangle({i, j}); - const auto visible_box = - geometry_intersection(self->wall->viewport, ws_bbox) - wf::origin(ws_bbox); - wf::region_t visible_damage = self->aux_buffer_damage[i][j] & visible_box; - if (consider_rescale_workspace_buffer(i, j, visible_damage)) - { - visible_damage |= visible_box; - } - - if (!visible_damage.empty()) - { - scene::render_pass_params_t params; - params.instances = &instances[i][j]; - params.damage = std::move(visible_damage); - params.reference_output = self->wall->output; - params.target = self->aux_buffers[i][j]; - scene::run_render_pass(params, scene::RPASS_EMIT_SIGNALS); - self->aux_buffer_damage[i][j] ^= visible_damage; - } - } - } - - // Render the wall - instructions.push_back(scene::render_instruction_t{ - .instance = this, - .target = target, - .damage = damage & self->get_bounding_box(), - }); - - damage ^= self->get_bounding_box(); - } - - static gl_geometry scale_fbox(wf::geometry_t A, wf::geometry_t B, wf::geometry_t box) - { - const float px = 1.0 * (box.x - A.x) / A.width; - const float py = 1.0 * (box.y - A.y) / A.height; - const float px2 = 1.0 * (box.x + box.width - A.x) / A.width; - const float py2 = 1.0 * (box.y + box.height - A.y) / A.height; - return gl_geometry{ - B.x + B.width * px, - B.y + B.height * py, - B.x + B.width * px2, - B.y + B.height * py2, - }; - } - - void render(const wf::render_target_t& target, const wf::region_t& region) override - { - OpenGL::render_begin(target); - for (auto& box : region) - { - target.logic_scissor(wlr_box_from_pixman_box(box)); - OpenGL::clear(self->wall->background_color); - for (int i = 0; i < (int)self->workspaces.size(); i++) - { - for (int j = 0; j < (int)self->workspaces[i].size(); j++) - { - auto box = get_workspace_rect({i, j}); - auto A = self->wall->viewport; - auto B = self->get_bounding_box(); - gl_geometry render_geometry = scale_fbox(A, B, box); - auto& buffer = self->aux_buffers[i][j]; - - float dim = self->wall->get_color_for_workspace({i, j}); - const glm::vec4 color = glm::vec4(dim, dim, dim, 1.0); - - if (!buffer.subbuffer.has_value()) - { - OpenGL::render_transformed_texture({buffer.tex}, - render_geometry, {}, target.get_orthographic_projection(), color); - } else - { - // The 0.999f come from trying to avoid floating-point artifacts - const gl_geometry tex_geometry = { - 0.0f, - 1.0f - 0.999f * buffer.subbuffer->height / buffer.viewport_height, - 0.999f * buffer.subbuffer->width / buffer.viewport_width, - 1.0f, - }; - - OpenGL::render_transformed_texture({buffer.tex}, - render_geometry, tex_geometry, - target.get_orthographic_projection(), - color, OpenGL::TEXTURE_USE_TEX_GEOMETRY); - } - } - } - } - - OpenGL::render_end(); - self->wall->render_wall(target, region); - } - - void compute_visibility(wf::output_t *output, wf::region_t& visible) override - { - for (int i = 0; i < (int)self->workspaces.size(); i++) - { - for (int j = 0; j < (int)self->workspaces[i].size(); j++) - { - wf::region_t ws_region = self->workspaces[i][j]->get_bounding_box(); - for (auto& ch : this->instances[i][j]) - { - ch->compute_visibility(output, ws_region); - } - } - } - } - }; - - public: - workspace_wall_node_t(workspace_wall_t *wall) : node_t(false) - { - this->wall = wall; - auto [w, h] = wall->output->wset()->get_workspace_grid_size(); - workspaces.resize(w); - for (int i = 0; i < w; i++) - { - for (int j = 0; j < h; j++) - { - auto node = std::make_shared( - wall->output, wf::point_t{i, j}); - workspaces[i].push_back(node); - - aux_buffers[i][j].geometry = workspaces[i][j]->get_bounding_box(); - aux_buffers[i][j].scale = wall->output->handle->scale; - aux_buffers[i][j].wl_transform = WL_OUTPUT_TRANSFORM_NORMAL; - aux_buffers[i][j].transform = get_output_matrix_from_transform( - aux_buffers[i][j].wl_transform); - - auto size = - aux_buffers[i][j].framebuffer_box_from_geometry_box(aux_buffers[i][j].geometry); - OpenGL::render_begin(); - aux_buffers[i][j].allocate(size.width, size.height); - OpenGL::render_end(); - - aux_buffer_damage[i][j] |= aux_buffers[i][j].geometry; - aux_buffer_current_scale[i][j] = 1.0; - } - } - } - - ~workspace_wall_node_t() - { - OpenGL::render_begin(); - for (auto& [_, buffers] : aux_buffers) - { - for (auto& [_, buffer] : buffers) - { - buffer.release(); - } - } - - OpenGL::render_end(); - } - - virtual void gen_render_instances( - std::vector& instances, - scene::damage_callback push_damage, wf::output_t *shown_on) override - { - if (shown_on != this->wall->output) - { - return; - } - - instances.push_back(std::make_unique( - this, push_damage)); - } - - std::string stringify() const override - { - return "workspace-wall " + stringify_flags(); - } - - wf::geometry_t get_bounding_box() override - { - return wall->output->get_layout_geometry(); - } - - private: - workspace_wall_t *wall; - std::vector>> workspaces; - - // Buffers keeping the contents of almost-static workspaces - per_workspace_map_t aux_buffers; - // Damage accumulated for those buffers - per_workspace_map_t aux_buffer_damage; - // Current rendering scale for the workspace - per_workspace_map_t aux_buffer_current_scale; - }; + class workspace_wall_node_t; std::shared_ptr render_node; }; } diff --git a/plugins/common/workspace-wall.cpp b/plugins/common/workspace-wall.cpp new file mode 100644 index 000000000..082f041fa --- /dev/null +++ b/plugins/common/workspace-wall.cpp @@ -0,0 +1,453 @@ +#include "wayfire/plugins/common/workspace-wall.hpp" +#include "wayfire/scene-input.hpp" +#include "wayfire/scene-operations.hpp" +#include "wayfire/workspace-stream.hpp" + +namespace wf +{ +template using per_workspace_map_t = std::map>; + +class workspace_wall_t::workspace_wall_node_t : public scene::node_t +{ + class wwall_render_instance_t : public scene::render_instance_t + { + std::shared_ptr self; + per_workspace_map_t> instances; + + scene::damage_callback push_damage; + wf::signal::connection_t on_wall_damage = + [=] (scene::node_damage_signal *ev) + { + push_damage(ev->region); + }; + + wf::geometry_t get_workspace_rect(wf::point_t ws) + { + auto output_size = self->wall->output->get_screen_size(); + return { + .x = ws.x * (output_size.width + self->wall->gap_size), + .y = ws.y * (output_size.height + self->wall->gap_size), + .width = output_size.width, + .height = output_size.height, + }; + } + + public: + wwall_render_instance_t(workspace_wall_node_t *self, + scene::damage_callback push_damage) + { + this->self = std::dynamic_pointer_cast(self->shared_from_this()); + this->push_damage = push_damage; + self->connect(&on_wall_damage); + + for (int i = 0; i < (int)self->workspaces.size(); i++) + { + for (int j = 0; j < (int)self->workspaces[i].size(); j++) + { + auto push_damage_child = [=] (const wf::region_t& damage) + { + // Store the damage because we'll have to update the buffers + self->aux_buffer_damage[i][j] |= damage; + + wf::region_t our_damage; + for (auto& rect : damage) + { + wf::geometry_t box = wlr_box_from_pixman_box(rect); + box = box + wf::origin(get_workspace_rect({i, j})); + auto A = self->wall->viewport; + auto B = self->get_bounding_box(); + our_damage |= scale_box(A, B, box); + } + + // Also damage the 'screen' after transforming damage + push_damage(our_damage); + }; + + self->workspaces[i][j]->gen_render_instances(instances[i][j], + push_damage_child, self->wall->output); + } + } + } + + static int damage_sum_area(const wf::region_t& damage) + { + int sum = 0; + for (const auto& rect : damage) + { + sum += (rect.y2 - rect.y1) * (rect.x2 - rect.x1); + } + + return sum; + } + + bool consider_rescale_workspace_buffer(int i, int j, wf::region_t& visible_damage) + { + // In general, when rendering the auxilliary buffers for each workspace, we can render the + // workspace thumbnails in a lower resolution, because at the end they are shown scaled. + // This helps with performance and uses less GPU power. + // + // However, the situation is tricky because during the Expo animation the optimal render + // scale constantly changes. Thus, in some cases it is actually far from optimal to rescale + // on every frame - it is often better to just keep the buffers from the old scale. + // + // Nonetheless, we need to make sure to rescale when this makes sense, and to avoid visual + // artifacts. + auto bbox = self->workspaces[i][j]->get_bounding_box(); + const float render_scale = std::max( + 1.0 * bbox.width / self->wall->viewport.width, + 1.0 * bbox.height / self->wall->viewport.height); + const float current_scale = self->aux_buffer_current_scale[i][j]; + + // Avoid keeping a low resolution if we are going up in the scale (for example, expo exit + // animation) and we're close to the 1.0 scale. Otherwise, we risk popping artifacts as we + // suddenly switch from low to high resolution. + const bool rescale_magnification = (render_scale > 0.5) && + (render_scale > current_scale * 1.1); + + // In general, it is worth changing the buffer scale if we have a lot of damage to the old + // buffer, so that for ex. a full re-scale is actually cheaper than repaiting the old buffer. + // This could easily happen for example if we have a video player during Expo start animation. + const int repaint_cost_current_scale = + damage_sum_area(visible_damage) * (current_scale * current_scale); + const int repaint_rescale_cost = (bbox.width * bbox.height) * (render_scale * render_scale); + + if ((repaint_cost_current_scale > repaint_rescale_cost) || rescale_magnification) + { + self->aux_buffer_current_scale[i][j] = render_scale; + self->aux_buffers[i][j].subbuffer = wf::geometry_t{ + 0, 0, + int(std::ceil(render_scale * self->aux_buffers[i][j].viewport_width)), + int(std::ceil(render_scale * self->aux_buffers[i][j].viewport_height)), + }; + + self->aux_buffer_damage[i][j] |= self->workspaces[i][j]->get_bounding_box(); + return true; + } + + return false; + } + + void schedule_instructions( + std::vector& instructions, + const wf::render_target_t& target, wf::region_t& damage) override + { + // Update workspaces in a render pass + for (int i = 0; i < (int)self->workspaces.size(); i++) + { + for (int j = 0; j < (int)self->workspaces[i].size(); j++) + { + const auto ws_bbox = self->wall->get_workspace_rectangle({i, j}); + const auto visible_box = + geometry_intersection(self->wall->viewport, ws_bbox) - wf::origin(ws_bbox); + wf::region_t visible_damage = self->aux_buffer_damage[i][j] & visible_box; + if (consider_rescale_workspace_buffer(i, j, visible_damage)) + { + visible_damage |= visible_box; + } + + if (!visible_damage.empty()) + { + scene::render_pass_params_t params; + params.instances = &instances[i][j]; + params.damage = std::move(visible_damage); + params.reference_output = self->wall->output; + params.target = self->aux_buffers[i][j]; + scene::run_render_pass(params, scene::RPASS_EMIT_SIGNALS); + self->aux_buffer_damage[i][j] ^= visible_damage; + } + } + } + + // Render the wall + instructions.push_back(scene::render_instruction_t{ + .instance = this, + .target = target, + .damage = damage & self->get_bounding_box(), + }); + + damage ^= self->get_bounding_box(); + } + + static gl_geometry scale_fbox(wf::geometry_t A, wf::geometry_t B, wf::geometry_t box) + { + const float px = 1.0 * (box.x - A.x) / A.width; + const float py = 1.0 * (box.y - A.y) / A.height; + const float px2 = 1.0 * (box.x + box.width - A.x) / A.width; + const float py2 = 1.0 * (box.y + box.height - A.y) / A.height; + return gl_geometry{ + B.x + B.width * px, + B.y + B.height * py, + B.x + B.width * px2, + B.y + B.height * py2, + }; + } + + void render(const wf::render_target_t& target, const wf::region_t& region) override + { + OpenGL::render_begin(target); + for (auto& box : region) + { + target.logic_scissor(wlr_box_from_pixman_box(box)); + OpenGL::clear(self->wall->background_color); + for (int i = 0; i < (int)self->workspaces.size(); i++) + { + for (int j = 0; j < (int)self->workspaces[i].size(); j++) + { + auto box = get_workspace_rect({i, j}); + auto A = self->wall->viewport; + auto B = self->get_bounding_box(); + gl_geometry render_geometry = scale_fbox(A, B, box); + auto& buffer = self->aux_buffers[i][j]; + + float dim = self->wall->get_color_for_workspace({i, j}); + const glm::vec4 color = glm::vec4(dim, dim, dim, 1.0); + + if (!buffer.subbuffer.has_value()) + { + OpenGL::render_transformed_texture({buffer.tex}, + render_geometry, {}, target.get_orthographic_projection(), color); + } else + { + // The 0.999f come from trying to avoid floating-point artifacts + const gl_geometry tex_geometry = { + 0.0f, + 1.0f - 0.999f * buffer.subbuffer->height / buffer.viewport_height, + 0.999f * buffer.subbuffer->width / buffer.viewport_width, + 1.0f, + }; + + OpenGL::render_transformed_texture({buffer.tex}, + render_geometry, tex_geometry, + target.get_orthographic_projection(), + color, OpenGL::TEXTURE_USE_TEX_GEOMETRY); + } + } + } + } + + OpenGL::render_end(); + self->wall->render_wall(target, region); + } + + void compute_visibility(wf::output_t *output, wf::region_t& visible) override + { + for (int i = 0; i < (int)self->workspaces.size(); i++) + { + for (int j = 0; j < (int)self->workspaces[i].size(); j++) + { + wf::region_t ws_region = self->workspaces[i][j]->get_bounding_box(); + for (auto& ch : this->instances[i][j]) + { + ch->compute_visibility(output, ws_region); + } + } + } + } + }; + + public: + std::map, float> render_colors; + + workspace_wall_node_t(workspace_wall_t *wall) : node_t(false) + { + this->wall = wall; + auto [w, h] = wall->output->wset()->get_workspace_grid_size(); + workspaces.resize(w); + for (int i = 0; i < w; i++) + { + for (int j = 0; j < h; j++) + { + auto node = std::make_shared( + wall->output, wf::point_t{i, j}); + workspaces[i].push_back(node); + + aux_buffers[i][j].geometry = workspaces[i][j]->get_bounding_box(); + aux_buffers[i][j].scale = wall->output->handle->scale; + aux_buffers[i][j].wl_transform = WL_OUTPUT_TRANSFORM_NORMAL; + aux_buffers[i][j].transform = get_output_matrix_from_transform( + aux_buffers[i][j].wl_transform); + + auto size = + aux_buffers[i][j].framebuffer_box_from_geometry_box(aux_buffers[i][j].geometry); + OpenGL::render_begin(); + aux_buffers[i][j].allocate(size.width, size.height); + OpenGL::render_end(); + + aux_buffer_damage[i][j] |= aux_buffers[i][j].geometry; + aux_buffer_current_scale[i][j] = 1.0; + } + } + } + + ~workspace_wall_node_t() + { + OpenGL::render_begin(); + for (auto& [_, buffers] : aux_buffers) + { + for (auto& [_, buffer] : buffers) + { + buffer.release(); + } + } + + OpenGL::render_end(); + } + + virtual void gen_render_instances( + std::vector& instances, + scene::damage_callback push_damage, wf::output_t *shown_on) override + { + if (shown_on != this->wall->output) + { + return; + } + + instances.push_back(std::make_unique( + this, push_damage)); + } + + std::string stringify() const override + { + return "workspace-wall " + stringify_flags(); + } + + wf::geometry_t get_bounding_box() override + { + return wall->output->get_layout_geometry(); + } + + private: + workspace_wall_t *wall; + std::vector>> workspaces; + + // Buffers keeping the contents of almost-static workspaces + per_workspace_map_t aux_buffers; + // Damage accumulated for those buffers + per_workspace_map_t aux_buffer_damage; + // Current rendering scale for the workspace + per_workspace_map_t aux_buffer_current_scale; +}; + +workspace_wall_t::workspace_wall_t(wf::output_t *_output) : output(_output) +{ + this->viewport = get_wall_rectangle(); +} + +workspace_wall_t::~workspace_wall_t() +{ + stop_output_renderer(false); +} + +void workspace_wall_t::set_background_color(const wf::color_t& color) +{ + this->background_color = color; +} + +void workspace_wall_t::set_gap_size(int size) +{ + this->gap_size = size; +} + +void workspace_wall_t::set_viewport(const wf::geometry_t& viewport_geometry) +{ + this->viewport = viewport_geometry; + if (render_node) + { + scene::damage_node( + this->render_node, this->render_node->get_bounding_box()); + } +} + +wf::geometry_t workspace_wall_t::get_viewport() const +{ + return viewport; +} + +void workspace_wall_t::render_wall( + const wf::render_target_t& fb, const wf::region_t& damage) +{ + wall_frame_event_t data{fb}; + this->emit(&data); +} + +void workspace_wall_t::start_output_renderer() +{ + wf::dassert(render_node == nullptr, "Starting workspace-wall twice?"); + render_node = std::make_shared(this); + scene::add_front(wf::get_core().scene(), render_node); +} + +void workspace_wall_t::stop_output_renderer(bool reset_viewport) +{ + if (!render_node) + { + return; + } + + scene::remove_child(render_node); + render_node = nullptr; + + if (reset_viewport) + { + set_viewport({0, 0, 0, 0}); + } +} + +wf::geometry_t workspace_wall_t::get_workspace_rectangle( + const wf::point_t& ws) const +{ + auto size = this->output->get_screen_size(); + + return {ws.x * (size.width + gap_size), ws.y * (size.height + gap_size), + size.width, size.height}; +} + +wf::geometry_t workspace_wall_t::get_wall_rectangle() const +{ + auto size = this->output->get_screen_size(); + auto workspace_size = this->output->wset()->get_workspace_grid_size(); + + return {-gap_size, -gap_size, + workspace_size.width * (size.width + gap_size) + gap_size, + workspace_size.height * (size.height + gap_size) + gap_size}; +} + +void workspace_wall_t::set_ws_dim(const wf::point_t& ws, float value) +{ + render_colors[{ws.x, ws.y}] = value; + if (render_node) + { + scene::damage_node(render_node, render_node->get_bounding_box()); + } +} + +float workspace_wall_t::get_color_for_workspace(wf::point_t ws) +{ + auto it = render_colors.find({ws.x, ws.y}); + if (it == render_colors.end()) + { + return 1.0; + } + + return it->second; +} + +std::vector workspace_wall_t::get_visible_workspaces( + wf::geometry_t viewport) const +{ + std::vector visible; + auto wsize = output->wset()->get_workspace_grid_size(); + for (int i = 0; i < wsize.width; i++) + { + for (int j = 0; j < wsize.height; j++) + { + if (viewport & get_workspace_rectangle({i, j})) + { + visible.push_back({i, j}); + } + } + } + + return visible; +} +} // namespace wf diff --git a/plugins/meson.build b/plugins/meson.build index 927646106..8b412ba49 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,14 +1,8 @@ -subdir('common') - if get_option('custom_pch') cc = meson.get_compiler('cpp') - pch_file = meson.current_source_dir() / 'pch/pch.hpp' api_headers = meson.project_source_root() / 'src/api' - ipc_headers = meson.project_source_root() / 'plugins/ipc' proto_headers = meson.project_build_root() / 'proto/libwl_protos.a.p/' - common_headers = meson.project_source_root() / 'plugins/common' - wobbly_headers = meson.project_source_root() / 'plugins/wobbly' if cc.get_id() == 'clang' pch = custom_target('plugin_pch', @@ -17,11 +11,8 @@ if get_option('custom_pch') command: cc.cmd_array() + ['@INPUT@', '-c', '-o', '@OUTPUT@', '-std=c++17', '-pthread', '-fPIC', '-I' + api_headers, - '-I' + ipc_headers, '-I/usr/include/pixman-1', - '-I' + proto_headers, - '-I' + common_headers, - '-I' + wobbly_headers]) + '-I' + proto_headers]) plugin_pch_args = ['-include-pch', pch.full_path(), '-pthread'] plugin_pch_dep = declare_dependency(sources: pch) @@ -35,6 +26,8 @@ else plugin_pch_dep = declare_dependency() endif +subdir('common') + subdir('ipc') subdir('protocols') subdir('vswitch') diff --git a/plugins/single_plugins/meson.build b/plugins/single_plugins/meson.build index dc6ca8a46..877c80e9f 100644 --- a/plugins/single_plugins/meson.build +++ b/plugins/single_plugins/meson.build @@ -8,10 +8,16 @@ plugins = [ all_include_dirs = [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, vswitch_inc, wobbly_inc, grid_inc] all_deps = [wlroots, pixman, wfconfig, wftouch, cairo, pango, pangocairo, json, plugin_pch_dep] +extra_libs = { + 'expo': [workspace_wall], + 'vswipe': [workspace_wall], +} + foreach plugin : plugins shared_module(plugin, plugin + '.cpp', include_directories: all_include_dirs, dependencies: all_deps, + link_with: extra_libs.get(plugin, []), cpp_args: plugin_pch_args, install: true, install_dir: conf_data.get('PLUGIN_PATH')) diff --git a/plugins/vswitch/meson.build b/plugins/vswitch/meson.build index 68da00f5f..d02252748 100644 --- a/plugins/vswitch/meson.build +++ b/plugins/vswitch/meson.build @@ -5,6 +5,7 @@ vswitch = shared_module('vswitch', include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, vswitch_inc, ipc_include_dirs], dependencies: [wlroots, pixman, wfconfig, json, plugin_pch_dep], cpp_args: plugin_pch_args, + link_with: [workspace_wall], install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) diff --git a/src/api/wayfire/plugin.hpp b/src/api/wayfire/plugin.hpp index db4da8eaf..b3bf5adac 100644 --- a/src/api/wayfire/plugin.hpp +++ b/src/api/wayfire/plugin.hpp @@ -105,7 +105,7 @@ class plugin_interface_t using wayfire_plugin_load_func = wf::plugin_interface_t * (*)(); /** The version of Wayfire's API/ABI */ -constexpr uint32_t WAYFIRE_API_ABI_VERSION = 2024'06'19; +constexpr uint32_t WAYFIRE_API_ABI_VERSION = 2024'07'24; /** * Each plugin must also provide a function which returns the Wayfire API/ABI diff --git a/src/api/wayfire/toplevel.hpp b/src/api/wayfire/toplevel.hpp index cf2aa303a..e4bcd8a92 100644 --- a/src/api/wayfire/toplevel.hpp +++ b/src/api/wayfire/toplevel.hpp @@ -4,6 +4,7 @@ #include "wayfire/geometry.hpp" #include "wayfire/object.hpp" #include +#include "wayfire/nonstd/wlroots.hpp" // IWYU pragma: keep namespace wf { diff --git a/src/core/seat/hotspot-manager.hpp b/src/core/seat/hotspot-manager.hpp index b8b0d5541..437852c29 100644 --- a/src/core/seat/hotspot-manager.hpp +++ b/src/core/seat/hotspot-manager.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include "wayfire/util.hpp" #include #include diff --git a/src/core/seat/touch.cpp b/src/core/seat/touch.cpp index 247bf7f16..1ebf0084b 100644 --- a/src/core/seat/touch.cpp +++ b/src/core/seat/touch.cpp @@ -9,6 +9,7 @@ #include "wayfire/output.hpp" #include "wayfire/util.hpp" #include "wayfire/output-layout.hpp" +#include wf::touch_interface_t::touch_interface_t(wlr_cursor *cursor, wlr_seat *seat, input_surface_selector_t surface_at) diff --git a/src/output/render-manager.cpp b/src/output/render-manager.cpp index 6a8288c8c..e986c5862 100644 --- a/src/output/render-manager.cpp +++ b/src/output/render-manager.cpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace wf { diff --git a/src/output/workarea.cpp b/src/output/workarea.cpp index 7c4edef04..9692b2d75 100644 --- a/src/output/workarea.cpp +++ b/src/output/workarea.cpp @@ -3,6 +3,7 @@ #include "wayfire/signal-provider.hpp" #include #include +#include struct wf::output_workarea_manager_t::impl { From f92f9724c365394abc79cdbc6c9e4e70f98619f6 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 24 Jul 2024 12:02:33 +0200 Subject: [PATCH 10/12] plugins: move move-drag-interface into a shared library --- plugins/common/meson.build | 7 + plugins/common/move-drag-interface.cpp | 673 ++++++++++++++++++ .../plugins/common/move-drag-interface.hpp | 662 +---------------- plugins/common/workspace-wall.cpp | 7 + plugins/scale/meson.build | 1 + plugins/scale/scale.cpp | 1 + plugins/single_plugins/expo.cpp | 1 + plugins/single_plugins/meson.build | 3 +- plugins/tile/meson.build | 1 + 9 files changed, 712 insertions(+), 644 deletions(-) create mode 100644 plugins/common/move-drag-interface.cpp diff --git a/plugins/common/meson.build b/plugins/common/meson.build index ca65f0cf8..646a35caf 100644 --- a/plugins/common/meson.build +++ b/plugins/common/meson.build @@ -9,3 +9,10 @@ workspace_wall = static_library('wayfire-workspace-wall', override_options: ['b_lundef=false'], install: true) +move_drag_interface = static_library('wayfire-move-drag-interface', + ['move-drag-interface.cpp'], + include_directories: [wayfire_api_inc, wayfire_conf_inc], + dependencies: [wlroots, pixman, wfconfig, plugin_pch_dep], + cpp_args: plugin_pch_args, + override_options: ['b_lundef=false'], + install: true) diff --git a/plugins/common/move-drag-interface.cpp b/plugins/common/move-drag-interface.cpp new file mode 100644 index 000000000..7085d642c --- /dev/null +++ b/plugins/common/move-drag-interface.cpp @@ -0,0 +1,673 @@ +#include "wayfire/plugins/common/move-drag-interface.hpp" +#include "wayfire/debug.hpp" +#include "wayfire/opengl.hpp" +#include "wayfire/region.hpp" +#include "wayfire/scene-input.hpp" +#include "wayfire/scene-operations.hpp" +#include "wayfire/seat.hpp" +#include "wayfire/signal-definitions.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wayfire/scene-render.hpp" +#include "wayfire/scene.hpp" +#include "wayfire/view-helpers.hpp" + +namespace wf +{ +namespace move_drag +{ +static wf::geometry_t find_geometry_around(wf::dimensions_t size, wf::point_t grab, wf::pointf_t relative) +{ + return wf::geometry_t{ + grab.x - (int)std::floor(relative.x * size.width), + grab.y - (int)std::floor(relative.y * size.height), + size.width, + size.height, + }; +} + +/** + * A transformer used while dragging. + * + * It is primarily used to scale the view is a plugin needs it, and also to keep it + * centered around the `grab_position`. + */ +class scale_around_grab_t : public wf::scene::transformer_base_node_t +{ + public: + /** + * Factor for scaling down the view. + * A factor 2.0 means that the view will have half of its width and height. + */ + wf::animation::simple_animation_t scale_factor{wf::create_option(300)}; + + wf::animation::simple_animation_t alpha_factor{wf::create_option(300)}; + + /** + * A place relative to the view, where it is grabbed. + * + * Coordinates are [0, 1]. A grab at (0.5, 0.5) means that the view is grabbed + * at its center. + */ + wf::pointf_t relative_grab; + + /** + * The position where the grab appears on the outputs, in output-layout + * coordinates. + */ + wf::point_t grab_position; + + scale_around_grab_t() : transformer_base_node_t(false) + {} + + std::string stringify() const override + { + return "move-drag"; + } + + wf::pointf_t scale_around_grab(wf::pointf_t point, double factor) + { + auto bbox = get_children_bounding_box(); + auto gx = bbox.x + bbox.width * relative_grab.x; + auto gy = bbox.y + bbox.height * relative_grab.y; + + return { + (point.x - gx) * factor + gx, + (point.y - gy) * factor + gy, + }; + } + + wf::pointf_t to_local(const wf::pointf_t& point) override + { + return scale_around_grab(point, scale_factor); + } + + wf::pointf_t to_global(const wf::pointf_t& point) override + { + return scale_around_grab(point, 1.0 / scale_factor); + } + + wf::geometry_t get_bounding_box() override + { + auto bbox = get_children_bounding_box(); + int w = std::floor(bbox.width / scale_factor); + int h = std::floor(bbox.height / scale_factor); + return find_geometry_around({w, h}, grab_position, relative_grab); + } + + class render_instance_t : + public scene::transformer_render_instance_t + { + public: + using transformer_render_instance_t::transformer_render_instance_t; + + void transform_damage_region(wf::region_t& region) override + { + region |= self->get_bounding_box(); + } + + void render(const wf::render_target_t& target, + const wf::region_t& region) override + { + auto bbox = self->get_bounding_box(); + auto tex = this->get_texture(target.scale); + + OpenGL::render_begin(target); + for (auto& rect : region) + { + target.logic_scissor(wlr_box_from_pixman_box(rect)); + OpenGL::render_texture(tex, target, bbox, glm::vec4{1, 1, 1, (double)self->alpha_factor}); + } + + OpenGL::render_end(); + } + }; + + void gen_render_instances(std::vector& instances, + scene::damage_callback push_damage, wf::output_t *shown_on) override + { + instances.push_back(std::make_unique(this, + push_damage, shown_on)); + } +}; + +static const std::string move_drag_transformer = "move-drag-transformer"; + +/** + * Represents a view which is being dragged. + * Multiple views exist only if join_views is set to true. + */ +struct dragged_view_t +{ + // The view being dragged + wayfire_toplevel_view view; + + // Its transformer + std::shared_ptr transformer; + + // The last bounding box used for damage. + // This is needed in case the view resizes or something like that, in which + // case we don't have access to the previous bbox. + wf::geometry_t last_bbox; +}; + +// A node to render the dragged views in global coordinates. +// The assumption is that all nodes have a view transformer which transforms them to global (not output-local) +// coordinates and thus we just need to schedule them for rendering. +class dragged_view_node_t : public wf::scene::node_t +{ + public: + std::vector views; + dragged_view_node_t(std::vector views) : node_t(false) + { + this->views = views; + } + + std::string stringify() const override + { + return "move-drag-view " + stringify_flags(); + } + + void gen_render_instances(std::vector& instances, + scene::damage_callback push_damage, wf::output_t *output = nullptr) override + { + instances.push_back(std::make_unique( + std::dynamic_pointer_cast(shared_from_this()), push_damage, output)); + } + + wf::geometry_t get_bounding_box() override + { + wf::region_t bounding; + for (auto& view : views) + { + // Note: bbox will be in output layout coordinates now, since this is + // how the transformer works + auto bbox = view.view->get_transformed_node()->get_bounding_box(); + bounding |= bbox; + } + + return wlr_box_from_pixman_box(bounding.get_extents()); + } + + class dragged_view_render_instance_t : public wf::scene::render_instance_t + { + wf::geometry_t last_bbox = {0, 0, 0, 0}; + wf::scene::damage_callback push_damage; + std::vector children; + wf::signal::connection_t on_node_damage = + [=] (scene::node_damage_signal *data) + { + push_damage(data->region); + }; + + public: + dragged_view_render_instance_t(std::shared_ptr self, + wf::scene::damage_callback push_damage, wf::output_t *shown_on) + { + auto push_damage_child = [=] (wf::region_t child_damage) + { + push_damage(last_bbox); + last_bbox = self->get_bounding_box(); + push_damage(last_bbox); + }; + + for (auto& view : self->views) + { + auto node = view.view->get_transformed_node(); + node->gen_render_instances(children, push_damage_child, shown_on); + } + } + + void schedule_instructions(std::vector& instructions, + const wf::render_target_t& target, wf::region_t& damage) override + { + for (auto& inst : children) + { + inst->schedule_instructions(instructions, target, damage); + } + } + + void presentation_feedback(wf::output_t *output) override + { + for (auto& instance : children) + { + instance->presentation_feedback(output); + } + } + + void compute_visibility(wf::output_t *output, wf::region_t& visible) override + { + for (auto& instance : children) + { + const int BIG_NUMBER = 1e5; + wf::region_t big_region = + wf::geometry_t{-BIG_NUMBER, -BIG_NUMBER, 2 * BIG_NUMBER, 2 * BIG_NUMBER}; + instance->compute_visibility(output, big_region); + } + } + }; +}; + +struct core_drag_t::impl +{ + // All views being dragged, more than one in case of join_views. + std::vector all_views; + + // Current parameters + drag_options_t params; + + // View is held in place, waiting for snap-off + bool view_held_in_place = false; + + std::shared_ptr render_node; + + wf::effect_hook_t on_pre_frame = [=] () + { + for (auto& v : this->all_views) + { + if (v.transformer->scale_factor.running()) + { + v.view->damage(); + } + } + }; + + wf::signal::connection_t on_view_unmap; + wf::signal::connection_t on_output_removed; +}; + +core_drag_t::core_drag_t() +{ + this->priv = std::make_unique(); + + priv->on_view_unmap = [=] (auto *ev) + { + handle_input_released(); + }; + + priv->on_output_removed = [=] (wf::output_removed_signal *ev) + { + if (current_output == ev->output) + { + update_current_output(nullptr); + } + }; + + wf::get_core().output_layout->connect(&priv->on_output_removed); +} + +core_drag_t::~core_drag_t() = default; + +void core_drag_t::rebuild_wobbly(wayfire_toplevel_view view, wf::point_t grab, wf::pointf_t relative) +{ + auto dim = wf::dimensions(wf::view_bounding_box_up_to(view, "wobbly")); + modify_wobbly(view, find_geometry_around(dim, grab, relative)); +} + +bool core_drag_t::should_start_pending_drag(wf::point_t current_position) +{ + if (!tentative_grab_position.has_value()) + { + return false; + } + + return distance_to_grab_origin(current_position) > 5; +} + +void core_drag_t::start_drag(wayfire_toplevel_view grab_view, wf::pointf_t relative, + const drag_options_t& options) +{ + wf::dassert(tentative_grab_position.has_value(), + "First, the drag operation should be set as pending!"); + wf::dassert(grab_view->is_mapped(), "Dragged view should be mapped!"); + wf::dassert(!this->view, "Drag operation already in progress!"); + + auto bbox = wf::view_bounding_box_up_to(grab_view, "wobbly"); + wf::point_t rel_grab_pos = { + int(bbox.x + relative.x * bbox.width), + int(bbox.y + relative.y * bbox.height), + }; + + if (options.join_views) + { + grab_view = wf::find_topmost_parent(grab_view); + } + + this->view = grab_view; + priv->params = options; + wf::get_core().default_wm->set_view_grabbed(view, true); + + auto target_views = get_target_views(grab_view, options.join_views); + for (auto& v : target_views) + { + dragged_view_t dragged; + dragged.view = v; + + // Setup view transform + + auto tr = std::make_shared(); + dragged.transformer = {tr}; + + tr->relative_grab = find_relative_grab( + wf::view_bounding_box_up_to(v, "wobbly"), rel_grab_pos); + tr->grab_position = *tentative_grab_position; + tr->scale_factor.animate(options.initial_scale, options.initial_scale); + tr->alpha_factor.animate(1, 1); + v->get_transformed_node()->add_transformer( + tr, wf::TRANSFORMER_HIGHLEVEL - 1); + + // Hide the view, we will render it as an overlay + wf::scene::set_node_enabled(v->get_transformed_node(), false); + v->damage(); + + // Make sure that wobbly has the correct geometry from the start! + rebuild_wobbly(v, *tentative_grab_position, dragged.transformer->relative_grab); + + // TODO: make this configurable! + start_wobbly_rel(v, dragged.transformer->relative_grab); + + priv->all_views.push_back(dragged); + v->connect(&priv->on_view_unmap); + } + + // Setup overlay hooks + priv->render_node = std::make_shared(priv->all_views); + wf::scene::add_front(wf::get_core().scene(), priv->render_node); + wf::get_core().set_cursor("grabbing"); + + // Set up snap-off + if (priv->params.enable_snap_off) + { + for (auto& v : priv->all_views) + { + set_tiled_wobbly(v.view, true); + } + + priv->view_held_in_place = true; + } +} + +void core_drag_t::start_drag(wayfire_toplevel_view view, const drag_options_t& options) +{ + wf::dassert(tentative_grab_position.has_value(), + "First, the drag operation should be set as pending!"); + + if (options.join_views) + { + view = wf::find_topmost_parent(view); + } + + auto bbox = view->get_transformed_node()->get_bounding_box() + + wf::origin(view->get_output()->get_layout_geometry()); + start_drag(view, find_relative_grab(bbox, *tentative_grab_position), options); +} + +void core_drag_t::handle_motion(wf::point_t to) +{ + if (priv->view_held_in_place) + { + if (distance_to_grab_origin(to) >= (double)priv->params.snap_off_threshold) + { + priv->view_held_in_place = false; + for (auto& v : priv->all_views) + { + set_tiled_wobbly(v.view, false); + } + + snap_off_signal data; + data.focus_output = current_output; + emit(&data); + } + } + + // Update wobbly independently of the grab position. + // This is because while held in place, wobbly is anchored to its edges + // so we can still move the grabbed point without moving the view. + for (auto& v : priv->all_views) + { + move_wobbly(v.view, to.x, to.y); + if (!priv->view_held_in_place) + { + v.view->get_transformed_node()->begin_transform_update(); + v.transformer->grab_position = to; + v.view->get_transformed_node()->end_transform_update(); + } + } + + update_current_output(to); + + drag_motion_signal data; + data.current_position = to; + emit(&data); +} + +double core_drag_t::distance_to_grab_origin(wf::point_t to) const +{ + return abs(to - *tentative_grab_position); +} + +void core_drag_t::handle_input_released() +{ + if (!view || priv->all_views.empty()) + { + this->tentative_grab_position = {}; + // Input already released => don't do anything + return; + } + + // Store data for the drag done signal + drag_done_signal data; + data.grab_position = priv->all_views.front().transformer->grab_position; + for (auto& v : priv->all_views) + { + data.all_views.push_back( + {v.view, v.transformer->relative_grab}); + } + + data.main_view = this->view; + data.focused_output = current_output; + data.join_views = priv->params.join_views; + + // Remove overlay hooks and damage outputs BEFORE popping the transformer + wf::scene::remove_child(priv->render_node); + priv->render_node->views.clear(); + priv->render_node = nullptr; + + for (auto& v : priv->all_views) + { + auto grab_position = v.transformer->grab_position; + auto rel_pos = v.transformer->relative_grab; + + // Restore view to where it was before + wf::scene::set_node_enabled(v.view->get_transformed_node(), true); + v.view->get_transformed_node()->rem_transformer(); + + // Reset wobbly and leave it in output-LOCAL coordinates + end_wobbly(v.view); + + // Important! If the view scale was not 1.0, the wobbly model needs to be + // updated with the new size. Since this is an artificial resize, we need + // to make sure that the resize happens smoothly. + rebuild_wobbly(v.view, grab_position, rel_pos); + + // Put wobbly back in output-local space, the plugins will take it from + // here. + translate_wobbly(v.view, + -wf::origin(v.view->get_output()->get_layout_geometry())); + } + + // Reset our state + wf::get_core().default_wm->set_view_grabbed(view, false); + view = nullptr; + priv->all_views.clear(); + if (current_output) + { + current_output->render->rem_effect(&priv->on_pre_frame); + current_output = nullptr; + } + + wf::get_core().set_cursor("default"); + + // Lastly, let the plugins handle what happens on drag end. + emit(&data); + priv->view_held_in_place = false; + priv->on_view_unmap.disconnect(); + + this->tentative_grab_position = {}; +} + +void core_drag_t::set_scale(double new_scale, double alpha) +{ + for (auto& view : priv->all_views) + { + view.transformer->scale_factor.animate(new_scale); + view.transformer->alpha_factor.animate(alpha); + } +} + +bool core_drag_t::is_view_held_in_place() +{ + return priv->view_held_in_place; +} + +void core_drag_t::update_current_output(wf::point_t grab) +{ + wf::pointf_t origin = {1.0 * grab.x, 1.0 * grab.y}; + auto output = wf::get_core().output_layout->get_output_coords_at(origin, origin); + update_current_output(output); +} + +void core_drag_t::update_current_output(wf::output_t *output) +{ + if (output != current_output) + { + if (current_output) + { + current_output->render->rem_effect(&priv->on_pre_frame); + } + + drag_focus_output_signal data; + data.previous_focus_output = current_output; + current_output = output; + data.focus_output = output; + if (output) + { + wf::get_core().seat->focus_output(output); + output->render->add_effect(&priv->on_pre_frame, OUTPUT_EFFECT_PRE); + } + + emit(&data); + } +} + +/** + * Move the view to the target output and put it at the coordinates of the grab. + * Also take into account view's fullscreen and tiled state. + * + * Unmapped views are ignored. + */ +void adjust_view_on_output(drag_done_signal *ev) +{ + // Any one of the views that are being dragged. + // They are all part of the same view tree. + auto parent = wf::find_topmost_parent(ev->main_view); + if (!parent->is_mapped()) + { + return; + } + + const bool change_output = parent->get_output() != ev->focused_output; + auto old_wset = parent->get_wset(); + if (change_output) + { + start_move_view_to_wset(parent, ev->focused_output->wset()); + } + + // Calculate the position we're leaving the view on + auto output_delta = -wf::origin(ev->focused_output->get_layout_geometry()); + auto grab = ev->grab_position + output_delta; + + auto output_geometry = ev->focused_output->get_relative_geometry(); + auto current_ws = ev->focused_output->wset()->get_current_workspace(); + wf::point_t target_ws{ + (int)std::floor(1.0 * grab.x / output_geometry.width), + (int)std::floor(1.0 * grab.y / output_geometry.height), + }; + target_ws = target_ws + current_ws; + + auto gsize = ev->focused_output->wset()->get_workspace_grid_size(); + target_ws.x = wf::clamp(target_ws.x, 0, gsize.width - 1); + target_ws.y = wf::clamp(target_ws.y, 0, gsize.height - 1); + + // view to focus at the end of drag + auto focus_view = ev->main_view; + + for (auto& v : ev->all_views) + { + if (!v.view->is_mapped()) + { + // Maybe some dialog got unmapped + continue; + } + + auto bbox = wf::view_bounding_box_up_to(v.view, "wobbly"); + auto wm = v.view->get_geometry(); + + wf::point_t wm_offset = wf::origin(wm) + -wf::origin(bbox); + bbox = wf::move_drag::find_geometry_around( + wf::dimensions(bbox), grab, v.relative_grab); + + wf::point_t target = wf::origin(bbox) + wm_offset; + v.view->move(target.x, target.y); + if (v.view->pending_fullscreen()) + { + wf::get_core().default_wm->fullscreen_request(v.view, ev->focused_output, true, target_ws); + } else if (v.view->pending_tiled_edges()) + { + wf::get_core().default_wm->tile_request(v.view, v.view->pending_tiled_edges(), target_ws); + } + + // check focus timestamp and select the last focused view to (re)focus + if (get_focus_timestamp(v.view) > get_focus_timestamp(focus_view)) + { + focus_view = v.view; + } + } + + // Ensure that every view is visible on parent's main workspace + for (auto& v : parent->enumerate_views()) + { + ev->focused_output->wset()->move_to_workspace(v, target_ws); + } + + if (change_output) + { + emit_view_moved_to_wset(parent, old_wset, ev->focused_output->wset()); + } + + wf::get_core().default_wm->focus_raise_view(focus_view); +} + +/** + * Adjust the view's state after snap-off. + */ +void adjust_view_on_snap_off(wayfire_toplevel_view view) +{ + if (view->pending_tiled_edges() && !view->pending_fullscreen()) + { + wf::get_core().default_wm->tile_request(view, 0); + } +} +} +} diff --git a/plugins/common/wayfire/plugins/common/move-drag-interface.hpp b/plugins/common/wayfire/plugins/common/move-drag-interface.hpp index fc187d014..77aab4a22 100644 --- a/plugins/common/wayfire/plugins/common/move-drag-interface.hpp +++ b/plugins/common/wayfire/plugins/common/move-drag-interface.hpp @@ -1,33 +1,10 @@ #pragma once -#include "wayfire/core.hpp" -#include "wayfire/debug.hpp" +#include "wayfire/toplevel-view.hpp" #include "wayfire/geometry.hpp" -#include "wayfire/opengl.hpp" -#include "wayfire/region.hpp" -#include "wayfire/scene-input.hpp" -#include "wayfire/scene-operations.hpp" -#include "wayfire/scene-render.hpp" -#include "wayfire/scene.hpp" -#include "wayfire/seat.hpp" -#include "wayfire/signal-definitions.hpp" -#include "wayfire/view-helpers.hpp" #include -#include -#include -#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include namespace wf @@ -127,21 +104,6 @@ struct drag_done_signal wf::point_t grab_position; }; -/** - * Find the geometry of a view, if it has size @size, it is grabbed at point @grab, - * and the grab is at position @relative relative to the view. - */ -inline static wf::geometry_t find_geometry_around( - wf::dimensions_t size, wf::point_t grab, wf::pointf_t relative) -{ - return wf::geometry_t{ - grab.x - (int)std::floor(relative.x * size.width), - grab.y - (int)std::floor(relative.y * size.height), - size.width, - size.height, - }; -} - /** * Find the position of grab relative to the view. * Example: returns [0.5, 0.5] if the grab is the midpoint of the view. @@ -155,133 +117,7 @@ inline static wf::pointf_t find_relative_grab( }; } -/** - * A transformer used while dragging. - * - * It is primarily used to scale the view is a plugin needs it, and also to keep it - * centered around the `grab_position`. - */ -class scale_around_grab_t : public wf::scene::transformer_base_node_t -{ - public: - /** - * Factor for scaling down the view. - * A factor 2.0 means that the view will have half of its width and height. - */ - wf::animation::simple_animation_t scale_factor{wf::create_option(300)}; - - wf::animation::simple_animation_t alpha_factor{wf::create_option(300)}; - - /** - * A place relative to the view, where it is grabbed. - * - * Coordinates are [0, 1]. A grab at (0.5, 0.5) means that the view is grabbed - * at its center. - */ - wf::pointf_t relative_grab; - - /** - * The position where the grab appears on the outputs, in output-layout - * coordinates. - */ - wf::point_t grab_position; - - scale_around_grab_t() : transformer_base_node_t(false) - {} - - std::string stringify() const override - { - return "move-drag"; - } - - wf::pointf_t scale_around_grab(wf::pointf_t point, double factor) - { - auto bbox = get_children_bounding_box(); - auto gx = bbox.x + bbox.width * relative_grab.x; - auto gy = bbox.y + bbox.height * relative_grab.y; - - return { - (point.x - gx) * factor + gx, - (point.y - gy) * factor + gy, - }; - } - - wf::pointf_t to_local(const wf::pointf_t& point) override - { - return scale_around_grab(point, scale_factor); - } - - wf::pointf_t to_global(const wf::pointf_t& point) override - { - return scale_around_grab(point, 1.0 / scale_factor); - } - - wf::geometry_t get_bounding_box() override - { - auto bbox = get_children_bounding_box(); - int w = std::floor(bbox.width / scale_factor); - int h = std::floor(bbox.height / scale_factor); - return find_geometry_around({w, h}, grab_position, relative_grab); - } - - class render_instance_t : - public scene::transformer_render_instance_t - { - public: - using transformer_render_instance_t::transformer_render_instance_t; - - void transform_damage_region(wf::region_t& region) override - { - region |= self->get_bounding_box(); - } - - void render(const wf::render_target_t& target, - const wf::region_t& region) override - { - auto bbox = self->get_bounding_box(); - auto tex = this->get_texture(target.scale); - - OpenGL::render_begin(target); - for (auto& rect : region) - { - target.logic_scissor(wlr_box_from_pixman_box(rect)); - OpenGL::render_texture(tex, target, bbox, glm::vec4{1, 1, 1, (double)self->alpha_factor}); - } - - OpenGL::render_end(); - } - }; - - void gen_render_instances(std::vector& instances, - scene::damage_callback push_damage, wf::output_t *shown_on) override - { - instances.push_back(std::make_unique(this, - push_damage, shown_on)); - } -}; - -static const std::string move_drag_transformer = "move-drag-transformer"; - -/** - * Represents a view which is being dragged. - * Multiple views exist only if join_views is set to true. - */ -struct dragged_view_t -{ - // The view being dragged - wayfire_toplevel_view view; - - // Its transformer - std::shared_ptr transformer; - - // The last bounding box used for damage. - // This is needed in case the view resizes or something like that, in which - // case we don't have access to the previous bbox. - wf::geometry_t last_bbox; -}; - -inline std::vector get_target_views(wayfire_toplevel_view grabbed, - bool join_views) +inline std::vector get_target_views(wayfire_toplevel_view grabbed, bool join_views) { std::vector r = {grabbed}; if (join_views) @@ -292,103 +128,6 @@ inline std::vector get_target_views(wayfire_toplevel_view return r; } -// A node to render the dragged views in global coordinates. -// The assumption is that all nodes have a view transformer which transforms them to global (not output-local) -// coordinates and thus we just need to schedule them for rendering. -class dragged_view_node_t : public wf::scene::node_t -{ - public: - std::vector views; - dragged_view_node_t(std::vector views) : node_t(false) - { - this->views = views; - } - - std::string stringify() const override - { - return "move-drag-view " + stringify_flags(); - } - - void gen_render_instances(std::vector& instances, - scene::damage_callback push_damage, wf::output_t *output = nullptr) override - { - instances.push_back(std::make_unique( - std::dynamic_pointer_cast(shared_from_this()), push_damage, output)); - } - - wf::geometry_t get_bounding_box() override - { - wf::region_t bounding; - for (auto& view : views) - { - // Note: bbox will be in output layout coordinates now, since this is - // how the transformer works - auto bbox = view.view->get_transformed_node()->get_bounding_box(); - bounding |= bbox; - } - - return wlr_box_from_pixman_box(bounding.get_extents()); - } - - class dragged_view_render_instance_t : public wf::scene::render_instance_t - { - wf::geometry_t last_bbox = {0, 0, 0, 0}; - wf::scene::damage_callback push_damage; - std::vector children; - wf::signal::connection_t on_node_damage = - [=] (scene::node_damage_signal *data) - { - push_damage(data->region); - }; - - public: - dragged_view_render_instance_t(std::shared_ptr self, - wf::scene::damage_callback push_damage, wf::output_t *shown_on) - { - auto push_damage_child = [=] (wf::region_t child_damage) - { - push_damage(last_bbox); - last_bbox = self->get_bounding_box(); - push_damage(last_bbox); - }; - - for (auto& view : self->views) - { - auto node = view.view->get_transformed_node(); - node->gen_render_instances(children, push_damage_child, shown_on); - } - } - - void schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override - { - for (auto& inst : children) - { - inst->schedule_instructions(instructions, target, damage); - } - } - - void presentation_feedback(wf::output_t *output) override - { - for (auto& instance : children) - { - instance->presentation_feedback(output); - } - } - - void compute_visibility(wf::output_t *output, wf::region_t& visible) override - { - for (auto& instance : children) - { - const int BIG_NUMBER = 1e5; - wf::region_t big_region = - wf::geometry_t{-BIG_NUMBER, -BIG_NUMBER, 2 * BIG_NUMBER, 2 * BIG_NUMBER}; - instance->compute_visibility(output, big_region); - } - } - }; -}; - struct drag_options_t { /** @@ -422,19 +161,12 @@ class core_drag_t : public signal::provider_t * Rebuild the wobbly model after a change in the scaling, so that the wobbly * model does not try to animate the scaling change itself. */ - void rebuild_wobbly(wayfire_toplevel_view view, wf::point_t grab, wf::pointf_t relative) - { - auto dim = wf::dimensions(wf::view_bounding_box_up_to(view, "wobbly")); - modify_wobbly(view, find_geometry_around(dim, grab, relative)); - } + void rebuild_wobbly(wayfire_toplevel_view view, wf::point_t grab, wf::pointf_t relative); public: std::optional tentative_grab_position; - - core_drag_t() - { - wf::get_core().output_layout->connect(&on_output_removed); - } + core_drag_t(); + ~core_drag_t(); /** * A button has been pressed which might start a drag action. @@ -451,15 +183,7 @@ class core_drag_t : public signal::provider_t * Note that in some cases this functionality is not used at all, if the action for example was triggered * by a binding. */ - bool should_start_pending_drag(wf::point_t current_position) - { - if (!tentative_grab_position.has_value()) - { - return false; - } - - return distance_to_grab_origin(current_position) > 5; - } + bool should_start_pending_drag(wf::point_t current_position); /** * Start the actual dragging operation. Note: this should be called **after** set_pending_drag(). @@ -468,220 +192,16 @@ class core_drag_t : public signal::provider_t * @param grab_position The position of the input, in output-layout coordinates. * @param relative The position of the grab_position relative to view. */ - void start_drag(wayfire_toplevel_view grab_view, wf::pointf_t relative, const drag_options_t& options) - { - wf::dassert(tentative_grab_position.has_value(), - "First, the drag operation should be set as pending!"); - wf::dassert(grab_view->is_mapped(), "Dragged view should be mapped!"); - wf::dassert(!this->view, "Drag operation already in progress!"); - - auto bbox = wf::view_bounding_box_up_to(grab_view, "wobbly"); - wf::point_t rel_grab_pos = { - int(bbox.x + relative.x * bbox.width), - int(bbox.y + relative.y * bbox.height), - }; - - if (options.join_views) - { - grab_view = find_topmost_parent(grab_view); - } - - this->view = grab_view; - this->params = options; - wf::get_core().default_wm->set_view_grabbed(view, true); - - auto target_views = get_target_views(grab_view, options.join_views); - for (auto& v : target_views) - { - dragged_view_t dragged; - dragged.view = v; - - // Setup view transform - - auto tr = std::make_shared(); - dragged.transformer = {tr}; - - tr->relative_grab = find_relative_grab( - wf::view_bounding_box_up_to(v, "wobbly"), rel_grab_pos); - tr->grab_position = *tentative_grab_position; - tr->scale_factor.animate(options.initial_scale, options.initial_scale); - tr->alpha_factor.animate(1, 1); - v->get_transformed_node()->add_transformer( - tr, wf::TRANSFORMER_HIGHLEVEL - 1); - - // Hide the view, we will render it as an overlay - wf::scene::set_node_enabled(v->get_transformed_node(), false); - v->damage(); - - // Make sure that wobbly has the correct geometry from the start! - rebuild_wobbly(v, *tentative_grab_position, dragged.transformer->relative_grab); - - // TODO: make this configurable! - start_wobbly_rel(v, dragged.transformer->relative_grab); - - this->all_views.push_back(dragged); - v->connect(&on_view_unmap); - } - - // Setup overlay hooks - render_node = std::make_shared(all_views); - wf::scene::add_front(wf::get_core().scene(), render_node); - wf::get_core().set_cursor("grabbing"); - - // Set up snap-off - if (params.enable_snap_off) - { - for (auto& v : all_views) - { - set_tiled_wobbly(v.view, true); - } - - view_held_in_place = true; - } - } - - void start_drag(wayfire_toplevel_view view, const drag_options_t& options) - { - wf::dassert(tentative_grab_position.has_value(), - "First, the drag operation should be set as pending!"); - - if (options.join_views) - { - view = find_topmost_parent(view); - } - - auto bbox = view->get_transformed_node()->get_bounding_box() + - wf::origin(view->get_output()->get_layout_geometry()); - start_drag(view, find_relative_grab(bbox, *tentative_grab_position), options); - } - - void handle_motion(wf::point_t to) - { - if (view_held_in_place) - { - if (distance_to_grab_origin(to) >= (double)params.snap_off_threshold) - { - view_held_in_place = false; - for (auto& v : all_views) - { - set_tiled_wobbly(v.view, false); - } - - snap_off_signal data; - data.focus_output = current_output; - emit(&data); - } - } - - // Update wobbly independently of the grab position. - // This is because while held in place, wobbly is anchored to its edges - // so we can still move the grabbed point without moving the view. - for (auto& v : all_views) - { - move_wobbly(v.view, to.x, to.y); - if (!view_held_in_place) - { - v.view->get_transformed_node()->begin_transform_update(); - v.transformer->grab_position = to; - v.view->get_transformed_node()->end_transform_update(); - } - } - - update_current_output(to); - - drag_motion_signal data; - data.current_position = to; - emit(&data); - } + void start_drag(wayfire_toplevel_view grab_view, wf::pointf_t relative, const drag_options_t& options); + void start_drag(wayfire_toplevel_view view, const drag_options_t& options); - double distance_to_grab_origin(wf::point_t to) const - { - return abs(to - *tentative_grab_position); - } + void handle_motion(wf::point_t to); - void handle_input_released() - { - if (!view || all_views.empty()) - { - this->tentative_grab_position = {}; - // Input already released => don't do anything - return; - } - - // Store data for the drag done signal - drag_done_signal data; - data.grab_position = all_views.front().transformer->grab_position; - for (auto& v : all_views) - { - data.all_views.push_back( - {v.view, v.transformer->relative_grab}); - } - - data.main_view = this->view; - data.focused_output = current_output; - data.join_views = params.join_views; - - // Remove overlay hooks and damage outputs BEFORE popping the transformer - wf::scene::remove_child(render_node); - render_node->views.clear(); - render_node = nullptr; - - for (auto& v : all_views) - { - auto grab_position = v.transformer->grab_position; - auto rel_pos = v.transformer->relative_grab; - - // Restore view to where it was before - wf::scene::set_node_enabled(v.view->get_transformed_node(), true); - v.view->get_transformed_node()->rem_transformer(); - - // Reset wobbly and leave it in output-LOCAL coordinates - end_wobbly(v.view); - - // Important! If the view scale was not 1.0, the wobbly model needs to be - // updated with the new size. Since this is an artificial resize, we need - // to make sure that the resize happens smoothly. - rebuild_wobbly(v.view, grab_position, rel_pos); - - // Put wobbly back in output-local space, the plugins will take it from - // here. - translate_wobbly(v.view, - -wf::origin(v.view->get_output()->get_layout_geometry())); - } - - // Reset our state - wf::get_core().default_wm->set_view_grabbed(view, false); - view = nullptr; - all_views.clear(); - if (current_output) - { - current_output->render->rem_effect(&on_pre_frame); - current_output = nullptr; - } - - wf::get_core().set_cursor("default"); - - // Lastly, let the plugins handle what happens on drag end. - emit(&data); - view_held_in_place = false; - on_view_unmap.disconnect(); - - this->tentative_grab_position = {}; - } - - void set_scale(double new_scale, double alpha = 1.0) - { - for (auto& view : all_views) - { - view.transformer->scale_factor.animate(new_scale); - view.transformer->alpha_factor.animate(alpha); - } - } + double distance_to_grab_origin(wf::point_t to) const; + void handle_input_released(); + void set_scale(double new_scale, double alpha = 1.0); - bool is_view_held_in_place() - { - return view_held_in_place; - } + bool is_view_held_in_place(); // View currently being moved. wayfire_toplevel_view view; @@ -690,70 +210,12 @@ class core_drag_t : public signal::provider_t wf::output_t *current_output = NULL; private: - // All views being dragged, more than one in case of join_views. - std::vector all_views; - - // Current parameters - drag_options_t params; + struct impl; + std::unique_ptr priv; - // View is held in place, waiting for snap-off - bool view_held_in_place = false; - std::shared_ptr render_node; - - void update_current_output(wf::point_t grab) - { - wf::pointf_t origin = {1.0 * grab.x, 1.0 * grab.y}; - auto output = wf::get_core().output_layout->get_output_coords_at(origin, origin); - update_current_output(output); - } - - void update_current_output(wf::output_t *output) - { - if (output != current_output) - { - if (current_output) - { - current_output->render->rem_effect(&on_pre_frame); - } - - drag_focus_output_signal data; - data.previous_focus_output = current_output; - current_output = output; - data.focus_output = output; - if (output) - { - wf::get_core().seat->focus_output(output); - output->render->add_effect(&on_pre_frame, OUTPUT_EFFECT_PRE); - } - - emit(&data); - } - } - - wf::effect_hook_t on_pre_frame = [=] () - { - for (auto& v : this->all_views) - { - if (v.transformer->scale_factor.running()) - { - v.view->damage(); - } - } - }; - - wf::signal::connection_t on_view_unmap = [=] (auto *ev) - { - handle_input_released(); - }; - - wf::signal::connection_t on_output_removed = [=] (wf::output_removed_signal *ev) - { - if (current_output == ev->output) - { - update_current_output(nullptr); - } - }; + void update_current_output(wf::point_t grab); + void update_current_output(wf::output_t *output); }; /** @@ -762,97 +224,11 @@ class core_drag_t : public signal::provider_t * * Unmapped views are ignored. */ -inline void adjust_view_on_output(drag_done_signal *ev) -{ - // Any one of the views that are being dragged. - // They are all part of the same view tree. - auto parent = find_topmost_parent(ev->main_view); - if (!parent->is_mapped()) - { - return; - } - - const bool change_output = parent->get_output() != ev->focused_output; - auto old_wset = parent->get_wset(); - if (change_output) - { - start_move_view_to_wset(parent, ev->focused_output->wset()); - } - - // Calculate the position we're leaving the view on - auto output_delta = -wf::origin(ev->focused_output->get_layout_geometry()); - auto grab = ev->grab_position + output_delta; - - auto output_geometry = ev->focused_output->get_relative_geometry(); - auto current_ws = ev->focused_output->wset()->get_current_workspace(); - wf::point_t target_ws{ - (int)std::floor(1.0 * grab.x / output_geometry.width), - (int)std::floor(1.0 * grab.y / output_geometry.height), - }; - target_ws = target_ws + current_ws; - - auto gsize = ev->focused_output->wset()->get_workspace_grid_size(); - target_ws.x = wf::clamp(target_ws.x, 0, gsize.width - 1); - target_ws.y = wf::clamp(target_ws.y, 0, gsize.height - 1); - - // view to focus at the end of drag - auto focus_view = ev->main_view; - - for (auto& v : ev->all_views) - { - if (!v.view->is_mapped()) - { - // Maybe some dialog got unmapped - continue; - } - - auto bbox = wf::view_bounding_box_up_to(v.view, "wobbly"); - auto wm = v.view->get_geometry(); - - wf::point_t wm_offset = wf::origin(wm) + -wf::origin(bbox); - bbox = wf::move_drag::find_geometry_around( - wf::dimensions(bbox), grab, v.relative_grab); - - wf::point_t target = wf::origin(bbox) + wm_offset; - v.view->move(target.x, target.y); - if (v.view->pending_fullscreen()) - { - wf::get_core().default_wm->fullscreen_request(v.view, ev->focused_output, true, target_ws); - } else if (v.view->pending_tiled_edges()) - { - wf::get_core().default_wm->tile_request(v.view, v.view->pending_tiled_edges(), target_ws); - } - - // check focus timestamp and select the last focused view to (re)focus - if (get_focus_timestamp(v.view) > get_focus_timestamp(focus_view)) - { - focus_view = v.view; - } - } - - // Ensure that every view is visible on parent's main workspace - for (auto& v : parent->enumerate_views()) - { - ev->focused_output->wset()->move_to_workspace(v, target_ws); - } - - if (change_output) - { - emit_view_moved_to_wset(parent, old_wset, ev->focused_output->wset()); - } - - wf::get_core().default_wm->focus_raise_view(focus_view); -} +void adjust_view_on_output(drag_done_signal *ev); /** * Adjust the view's state after snap-off. */ -inline void adjust_view_on_snap_off(wayfire_toplevel_view view) -{ - if (view->pending_tiled_edges() && !view->pending_fullscreen()) - { - wf::get_core().default_wm->tile_request(view, 0); - } -} +void adjust_view_on_snap_off(wayfire_toplevel_view view); } } diff --git a/plugins/common/workspace-wall.cpp b/plugins/common/workspace-wall.cpp index 082f041fa..823d14a0d 100644 --- a/plugins/common/workspace-wall.cpp +++ b/plugins/common/workspace-wall.cpp @@ -2,6 +2,13 @@ #include "wayfire/scene-input.hpp" #include "wayfire/scene-operations.hpp" #include "wayfire/workspace-stream.hpp" +#include "wayfire/opengl.hpp" +#include "wayfire/scene-render.hpp" +#include "wayfire/scene.hpp" +#include "wayfire/region.hpp" +#include "wayfire/core.hpp" + +#include namespace wf { diff --git a/plugins/scale/meson.build b/plugins/scale/meson.build index 86ad39dc7..94d826896 100644 --- a/plugins/scale/meson.build +++ b/plugins/scale/meson.build @@ -5,6 +5,7 @@ shared_module('scale', ['scale.cpp', 'scale-title-overlay.cpp'], include_directories: all_include_dirs, dependencies: all_deps, cpp_args: plugin_pch_args, + link_with: [move_drag_interface], install: true, install_dir: conf_data.get('PLUGIN_PATH')) diff --git a/plugins/scale/scale.cpp b/plugins/scale/scale.cpp index de445d5bc..7c6b8f1f5 100644 --- a/plugins/scale/scale.cpp +++ b/plugins/scale/scale.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/plugins/single_plugins/expo.cpp b/plugins/single_plugins/expo.cpp index 486dfa0f1..e5e54cd38 100644 --- a/plugins/single_plugins/expo.cpp +++ b/plugins/single_plugins/expo.cpp @@ -12,6 +12,7 @@ #include #include #include +#include "wayfire/plugins/wobbly/wobbly-signal.hpp" #include #include diff --git a/plugins/single_plugins/meson.build b/plugins/single_plugins/meson.build index 877c80e9f..e71aff2d2 100644 --- a/plugins/single_plugins/meson.build +++ b/plugins/single_plugins/meson.build @@ -9,7 +9,8 @@ all_include_dirs = [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, vswit all_deps = [wlroots, pixman, wfconfig, wftouch, cairo, pango, pangocairo, json, plugin_pch_dep] extra_libs = { - 'expo': [workspace_wall], + 'move': [move_drag_interface], + 'expo': [workspace_wall, move_drag_interface], 'vswipe': [workspace_wall], } diff --git a/plugins/tile/meson.build b/plugins/tile/meson.build index d87e231a3..b84a7c172 100644 --- a/plugins/tile/meson.build +++ b/plugins/tile/meson.build @@ -3,6 +3,7 @@ tile = shared_module('simple-tile', include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, grid_inc, wobbly_inc, ipc_include_dirs], dependencies: [wlroots, pixman, wfconfig, json, plugin_pch_dep], cpp_args: plugin_pch_args, + link_with: [move_drag_interface], install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) From 3207fc9700c84fb9311fa0f2b4d7a8d7c8505494 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 24 Jul 2024 12:14:23 +0200 Subject: [PATCH 11/12] vswitch: move most of the implementation to the cpp file We don't need most of vswitch in the places where it is included. --- plugins/vswitch/vswitch.cpp | 310 ++++++++++++++++++++ plugins/vswitch/wayfire/plugins/vswitch.hpp | 304 ------------------- 2 files changed, 310 insertions(+), 304 deletions(-) diff --git a/plugins/vswitch/vswitch.cpp b/plugins/vswitch/vswitch.cpp index d6b35178c..adc4906ef 100644 --- a/plugins/vswitch/vswitch.cpp +++ b/plugins/vswitch/vswitch.cpp @@ -7,6 +7,316 @@ #include #include "plugins/ipc/ipc-method-repository.hpp" #include "wayfire/plugins/common/shared-core-data.hpp" +#include "wayfire/unstable/translation-node.hpp" +#include "wayfire/scene-operations.hpp" +#include "wayfire/render-manager.hpp" + +namespace wf +{ +namespace vswitch +{ +using namespace animation; +class workspace_animation_t : public duration_t +{ + public: + using duration_t::duration_t; + timed_transition_t dx{*this}; + timed_transition_t dy{*this}; +}; + +/** + * A simple scenegraph node which draws a view at a fixed position and as an overlay over the workspace wall. + */ +class vswitch_overlay_node_t : public wf::scene::node_t +{ + std::weak_ptr _view; + + public: + vswitch_overlay_node_t(wayfire_toplevel_view view) : node_t(true) + { + _view = view->weak_from_this(); + } + + // Since we do not grab focus via a grab node, route focus to the view being rendered as an overlay + wf::keyboard_focus_node_t keyboard_refocus(wf::output_t *output) + { + if (auto view = _view.lock()) + { + return view->get_transformed_node()->keyboard_refocus(output); + } + + return wf::keyboard_focus_node_t{}; + } + + virtual void gen_render_instances(std::vector& instances, + scene::damage_callback push_damage, wf::output_t *output = nullptr) + { + if (auto view = _view.lock()) + { + view->get_transformed_node()->gen_render_instances(instances, push_damage, output); + } + } + + virtual wf::geometry_t get_bounding_box() + { + if (auto view = _view.lock()) + { + return view->get_transformed_node()->get_bounding_box(); + } + + return {0, 0, 0, 0}; + } +}; + +/** + * Represents the action of switching workspaces with the vswitch algorithm. + * + * The workspace is actually switched at the end of the animation + */ +class workspace_switch_t +{ + public: + /** + * Initialize the workspace switch process. + * + * @param output The output the workspace switch happens on. + */ + workspace_switch_t(output_t *output) + { + this->output = output; + wall = std::make_unique(output); + animation = workspace_animation_t{ + wf::option_wrapper_t{"vswitch/duration"} + }; + } + + /** + * Initialize switching animation. + * At this point, the calling plugin needs to have the custom renderer + * ability set. + */ + virtual void start_switch() + { + /* Setup wall */ + wall->set_gap_size(gap); + wall->set_viewport(wall->get_workspace_rectangle( + output->wset()->get_current_workspace())); + wall->set_background_color(background_color); + wall->start_output_renderer(); + + if (overlay_view_node) + { + wf::scene::readd_front(wf::get_core().scene(), overlay_view_node); + } + + output->render->add_effect(&post_render, OUTPUT_EFFECT_POST); + + running = true; + + /* Setup animation */ + animation.dx.set(0, 0); + animation.dy.set(0, 0); + animation.start(); + } + + /** + * Start workspace switch animation towards the given workspace, + * and set that workspace as current. + * + * @param workspace The new target workspace. + */ + virtual void set_target_workspace(point_t workspace) + { + point_t cws = output->wset()->get_current_workspace(); + + animation.dx.set(animation.dx + cws.x - workspace.x, 0); + animation.dy.set(animation.dy + cws.y - workspace.y, 0); + animation.start(); + + std::vector fixed_views; + if (overlay_view) + { + fixed_views.push_back(overlay_view); + } + + output->wset()->set_workspace(workspace, fixed_views); + } + + /** + * Set the overlay view. It will be hidden from the normal workspace layers + * and shown on top of the workspace wall. The overlay view's position is + * not animated together with the workspace transition, but its alpha is. + * + * Note: if the view disappears, the caller is responsible for resetting the + * overlay view. + * + * @param view The desired overlay view, or NULL if the overlay view needs + * to be unset. + */ + virtual void set_overlay_view(wayfire_toplevel_view view) + { + if (this->overlay_view == view) + { + /* Nothing to do */ + return; + } + + /* Reset old view */ + if (this->overlay_view) + { + wf::scene::set_node_enabled(overlay_view->get_transformed_node(), true); + overlay_view->get_transformed_node()->rem_transformer( + vswitch_view_transformer_name); + + wf::scene::remove_child(overlay_view_node); + overlay_view_node.reset(); + } + + /* Set new view */ + this->overlay_view = view; + if (view) + { + view->get_transformed_node()->add_transformer( + std::make_shared(view), + wf::TRANSFORMER_2D, vswitch_view_transformer_name); + wf::scene::set_node_enabled(view->get_transformed_node(), false); + + // Render as an overlay, but make sure it is translated to the local output + auto vswitch_overlay = std::make_shared(view); + + overlay_view_node = std::make_shared(); + overlay_view_node->set_children_list({vswitch_overlay}); + overlay_view_node->set_offset(origin(output->get_layout_geometry())); + + wf::scene::add_front(wf::get_core().scene(), overlay_view_node); + } + } + + /** @return the current overlay view, might be NULL. */ + virtual wayfire_view get_overlay_view() + { + return this->overlay_view; + } + + /** + * Called automatically when the workspace switch animation is done. + * By default, this stops the animation. + * + * @param normal_exit Whether the operation has ended because of animation + * running out, in which case the workspace and the overlay view are + * adjusted, and otherwise not. + */ + virtual void stop_switch(bool normal_exit) + { + if (normal_exit) + { + auto old_ws = output->wset()->get_current_workspace(); + adjust_overlay_view_switch_done(old_ws); + } + + wall->stop_output_renderer(true); + output->render->rem_effect(&post_render); + running = false; + } + + virtual bool is_running() const + { + return running; + } + + virtual ~workspace_switch_t() + {} + + protected: + option_wrapper_t gap{"vswitch/gap"}; + option_wrapper_t background_color{"vswitch/background"}; + workspace_animation_t animation; + + output_t *output; + std::unique_ptr wall; + + const std::string vswitch_view_transformer_name = "vswitch-transformer"; + wayfire_toplevel_view overlay_view; + std::shared_ptr overlay_view_node; + + bool running = false; + void update_overlay_fb() + { + if (!overlay_view) + { + return; + } + + double progress = animation.progress(); + + auto tmanager = overlay_view->get_transformed_node(); + auto tr = tmanager->get_transformer( + vswitch_view_transformer_name); + + static constexpr double smoothing_in = 0.4; + static constexpr double smoothing_out = 0.2; + static constexpr double smoothing_amount = 0.5; + + tmanager->begin_transform_update(); + if (progress <= smoothing_in) + { + tr->alpha = 1.0 - (smoothing_amount / smoothing_in) * progress; + } else if (progress >= 1.0 - smoothing_out) + { + tr->alpha = 1.0 - (smoothing_amount / smoothing_out) * (1.0 - progress); + } else + { + tr->alpha = smoothing_amount; + } + + tmanager->end_transform_update(); + } + + wf::effect_hook_t post_render = [=] () + { + auto start = wall->get_workspace_rectangle( + output->wset()->get_current_workspace()); + auto size = output->get_screen_size(); + geometry_t viewport = { + (int)std::round(animation.dx * (size.width + gap) + start.x), + (int)std::round(animation.dy * (size.height + gap) + start.y), + start.width, + start.height, + }; + wall->set_viewport(viewport); + update_overlay_fb(); + + output->render->damage_whole(); + output->render->schedule_redraw(); + if (!animation.running()) + { + stop_switch(true); + } + }; + + /** + * Emit the view-change-workspace signal from the old workspace to the current + * workspace and unset the view. + */ + virtual void adjust_overlay_view_switch_done(wf::point_t old_workspace) + { + if (!overlay_view) + { + return; + } + + wf::view_change_workspace_signal data; + data.view = overlay_view; + data.from = old_workspace; + data.to = output->wset()->get_current_workspace(); + output->emit(&data); + + set_overlay_view(nullptr); + wf::get_core().seat->refocus(); + } +}; +} +} class vswitch : public wf::per_output_plugin_instance_t { diff --git a/plugins/vswitch/wayfire/plugins/vswitch.hpp b/plugins/vswitch/wayfire/plugins/vswitch.hpp index 306153f24..69a44ac9e 100644 --- a/plugins/vswitch/wayfire/plugins/vswitch.hpp +++ b/plugins/vswitch/wayfire/plugins/vswitch.hpp @@ -1,14 +1,11 @@ #pragma once #include "wayfire/scene-input.hpp" -#include "wayfire/scene-operations.hpp" #include "wayfire/seat.hpp" #include "wayfire/core.hpp" -#include "wayfire/render-manager.hpp" #include "wayfire/scene-render.hpp" #include "wayfire/scene.hpp" #include "wayfire/toplevel-view.hpp" -#include "wayfire/unstable/translation-node.hpp" #include "wayfire/view-helpers.hpp" #include #include @@ -25,307 +22,6 @@ namespace wf { namespace vswitch { -using namespace animation; -class workspace_animation_t : public duration_t -{ - public: - using duration_t::duration_t; - timed_transition_t dx{*this}; - timed_transition_t dy{*this}; -}; - -/** - * A simple scenegraph node which draws a view at a fixed position and as an overlay over the workspace wall. - */ -class vswitch_overlay_node_t : public wf::scene::node_t -{ - std::weak_ptr _view; - - public: - vswitch_overlay_node_t(wayfire_toplevel_view view) : node_t(true) - { - _view = view->weak_from_this(); - } - - // Since we do not grab focus via a grab node, route focus to the view being rendered as an overlay - wf::keyboard_focus_node_t keyboard_refocus(wf::output_t *output) - { - if (auto view = _view.lock()) - { - return view->get_transformed_node()->keyboard_refocus(output); - } - - return wf::keyboard_focus_node_t{}; - } - - virtual void gen_render_instances(std::vector& instances, - scene::damage_callback push_damage, wf::output_t *output = nullptr) - { - if (auto view = _view.lock()) - { - view->get_transformed_node()->gen_render_instances(instances, push_damage, output); - } - } - - virtual wf::geometry_t get_bounding_box() - { - if (auto view = _view.lock()) - { - return view->get_transformed_node()->get_bounding_box(); - } - - return {0, 0, 0, 0}; - } -}; - -/** - * Represents the action of switching workspaces with the vswitch algorithm. - * - * The workspace is actually switched at the end of the animation - */ -class workspace_switch_t -{ - public: - /** - * Initialize the workspace switch process. - * - * @param output The output the workspace switch happens on. - */ - workspace_switch_t(output_t *output) - { - this->output = output; - wall = std::make_unique(output); - animation = workspace_animation_t{ - wf::option_wrapper_t{"vswitch/duration"} - }; - } - - /** - * Initialize switching animation. - * At this point, the calling plugin needs to have the custom renderer - * ability set. - */ - virtual void start_switch() - { - /* Setup wall */ - wall->set_gap_size(gap); - wall->set_viewport(wall->get_workspace_rectangle( - output->wset()->get_current_workspace())); - wall->set_background_color(background_color); - wall->start_output_renderer(); - - if (overlay_view_node) - { - wf::scene::readd_front(wf::get_core().scene(), overlay_view_node); - } - - output->render->add_effect(&post_render, OUTPUT_EFFECT_POST); - - running = true; - - /* Setup animation */ - animation.dx.set(0, 0); - animation.dy.set(0, 0); - animation.start(); - } - - /** - * Start workspace switch animation towards the given workspace, - * and set that workspace as current. - * - * @param workspace The new target workspace. - */ - virtual void set_target_workspace(point_t workspace) - { - point_t cws = output->wset()->get_current_workspace(); - - animation.dx.set(animation.dx + cws.x - workspace.x, 0); - animation.dy.set(animation.dy + cws.y - workspace.y, 0); - animation.start(); - - std::vector fixed_views; - if (overlay_view) - { - fixed_views.push_back(overlay_view); - } - - output->wset()->set_workspace(workspace, fixed_views); - } - - /** - * Set the overlay view. It will be hidden from the normal workspace layers - * and shown on top of the workspace wall. The overlay view's position is - * not animated together with the workspace transition, but its alpha is. - * - * Note: if the view disappears, the caller is responsible for resetting the - * overlay view. - * - * @param view The desired overlay view, or NULL if the overlay view needs - * to be unset. - */ - virtual void set_overlay_view(wayfire_toplevel_view view) - { - if (this->overlay_view == view) - { - /* Nothing to do */ - return; - } - - /* Reset old view */ - if (this->overlay_view) - { - wf::scene::set_node_enabled(overlay_view->get_transformed_node(), true); - overlay_view->get_transformed_node()->rem_transformer( - vswitch_view_transformer_name); - - wf::scene::remove_child(overlay_view_node); - overlay_view_node.reset(); - } - - /* Set new view */ - this->overlay_view = view; - if (view) - { - view->get_transformed_node()->add_transformer( - std::make_shared(view), - wf::TRANSFORMER_2D, vswitch_view_transformer_name); - wf::scene::set_node_enabled(view->get_transformed_node(), false); - - // Render as an overlay, but make sure it is translated to the local output - auto vswitch_overlay = std::make_shared(view); - - overlay_view_node = std::make_shared(); - overlay_view_node->set_children_list({vswitch_overlay}); - overlay_view_node->set_offset(origin(output->get_layout_geometry())); - - wf::scene::add_front(wf::get_core().scene(), overlay_view_node); - } - } - - /** @return the current overlay view, might be NULL. */ - virtual wayfire_view get_overlay_view() - { - return this->overlay_view; - } - - /** - * Called automatically when the workspace switch animation is done. - * By default, this stops the animation. - * - * @param normal_exit Whether the operation has ended because of animation - * running out, in which case the workspace and the overlay view are - * adjusted, and otherwise not. - */ - virtual void stop_switch(bool normal_exit) - { - if (normal_exit) - { - auto old_ws = output->wset()->get_current_workspace(); - adjust_overlay_view_switch_done(old_ws); - } - - wall->stop_output_renderer(true); - output->render->rem_effect(&post_render); - running = false; - } - - virtual bool is_running() const - { - return running; - } - - virtual ~workspace_switch_t() - {} - - protected: - option_wrapper_t gap{"vswitch/gap"}; - option_wrapper_t background_color{"vswitch/background"}; - workspace_animation_t animation; - - output_t *output; - std::unique_ptr wall; - - const std::string vswitch_view_transformer_name = "vswitch-transformer"; - wayfire_toplevel_view overlay_view; - std::shared_ptr overlay_view_node; - - bool running = false; - void update_overlay_fb() - { - if (!overlay_view) - { - return; - } - - double progress = animation.progress(); - - auto tmanager = overlay_view->get_transformed_node(); - auto tr = tmanager->get_transformer( - vswitch_view_transformer_name); - - static constexpr double smoothing_in = 0.4; - static constexpr double smoothing_out = 0.2; - static constexpr double smoothing_amount = 0.5; - - tmanager->begin_transform_update(); - if (progress <= smoothing_in) - { - tr->alpha = 1.0 - (smoothing_amount / smoothing_in) * progress; - } else if (progress >= 1.0 - smoothing_out) - { - tr->alpha = 1.0 - (smoothing_amount / smoothing_out) * (1.0 - progress); - } else - { - tr->alpha = smoothing_amount; - } - - tmanager->end_transform_update(); - } - - wf::effect_hook_t post_render = [=] () - { - auto start = wall->get_workspace_rectangle( - output->wset()->get_current_workspace()); - auto size = output->get_screen_size(); - geometry_t viewport = { - (int)std::round(animation.dx * (size.width + gap) + start.x), - (int)std::round(animation.dy * (size.height + gap) + start.y), - start.width, - start.height, - }; - wall->set_viewport(viewport); - update_overlay_fb(); - - output->render->damage_whole(); - output->render->schedule_redraw(); - if (!animation.running()) - { - stop_switch(true); - } - }; - - /** - * Emit the view-change-workspace signal from the old workspace to the current - * workspace and unset the view. - */ - virtual void adjust_overlay_view_switch_done(wf::point_t old_workspace) - { - if (!overlay_view) - { - return; - } - - wf::view_change_workspace_signal data; - data.view = overlay_view; - data.from = old_workspace; - data.to = output->wset()->get_current_workspace(); - output->emit(&data); - - set_overlay_view(nullptr); - wf::get_core().seat->refocus(); - } -}; - /** * A simple class to register the vswitch bindings and get a custom callback called. */ From 4514234c0c1f0c01f79bac4f1b1f26b5ee0397e8 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 24 Jul 2024 09:58:58 +0200 Subject: [PATCH 12/12] ipc: migrate to jsoncpp nlohmann/json has very slow compilation times. --- meson.build | 2 +- plugins/ipc-rules/ipc-events.hpp | 67 +++++---- plugins/ipc-rules/ipc-input-methods.hpp | 19 +-- plugins/ipc-rules/ipc-rules-common.hpp | 18 +-- plugins/ipc-rules/ipc-rules.cpp | 87 +++++------ plugins/ipc-rules/ipc-utility-methods.hpp | 89 +++++------ plugins/ipc/demo-ipc.cpp | 92 ++++++------ plugins/ipc/ipc-activator.hpp | 39 ++--- plugins/ipc/ipc-helpers.hpp | 88 +++++++---- plugins/ipc/ipc-method-repository.hpp | 51 +++---- plugins/ipc/ipc.cpp | 23 ++- plugins/ipc/ipc.hpp | 5 +- plugins/ipc/stipc.cpp | 174 ++++++++++------------ plugins/single_plugins/alpha.cpp | 18 +-- plugins/single_plugins/command.cpp | 45 +++--- plugins/single_plugins/wsets.cpp | 21 ++- plugins/tile/tile-ipc.hpp | 99 ++++++------ plugins/tile/tile-plugin.cpp | 4 +- plugins/vswitch/vswitch.cpp | 18 +-- plugins/wm-actions/wm-actions.cpp | 22 ++- 20 files changed, 497 insertions(+), 484 deletions(-) diff --git a/meson.build b/meson.build index 0bb9680d9..294cdac5f 100644 --- a/meson.build +++ b/meson.build @@ -33,7 +33,7 @@ libinput = dependency('libinput', version: '>=1.7.0') pixman = dependency('pixman-1') xkbcommon = dependency('xkbcommon') libdl = meson.get_compiler('cpp').find_library('dl') -json = dependency('nlohmann_json', version: '>= 3.11.2') +json = dependency('jsoncpp') # We're not to use system wlroots: So we'll use the subproject if get_option('use_system_wlroots').disabled() diff --git a/plugins/ipc-rules/ipc-events.hpp b/plugins/ipc-rules/ipc-events.hpp index 639d862b3..efe03ba8c 100644 --- a/plugins/ipc-rules/ipc-events.hpp +++ b/plugins/ipc-rules/ipc-events.hpp @@ -3,6 +3,7 @@ #include "ipc-rules-common.hpp" #include #include "plugins/ipc/ipc-method-repository.hpp" +#include "wayfire/seat.hpp" #include namespace wf @@ -33,18 +34,18 @@ class ipc_rules_events_methods_t : public wf::per_output_tracker_mixin_t<> } } - nlohmann::json data; + Json::Value data; data["event"] = "output-added"; data["output"] = output_to_json(output); - send_event_to_subscribes(data, data["event"]); + send_event_to_subscribes(data, data["event"].asString()); } void handle_output_removed(wf::output_t *output) override { - nlohmann::json data; + Json::Value data; data["event"] = "output-removed"; data["output"] = output_to_json(output); - send_event_to_subscribes(data, data["event"]); + send_event_to_subscribes(data, data["event"].asString()); } // Template FOO for efficient management of signals: ensure that only actually listened-for signals @@ -128,23 +129,27 @@ class ipc_rules_events_methods_t : public wf::per_output_tracker_mixin_t<> std::map> clients; wf::ipc::method_callback_full on_client_watch = - [=] (nlohmann::json data, wf::ipc::client_interface_t *client) + [=] (Json::Value data, wf::ipc::client_interface_t *client) { static constexpr const char *EVENTS = "events"; - WFJSON_OPTIONAL_FIELD(data, EVENTS, array); + if (data.isMember(EVENTS) && !data[EVENTS].isArray()) + { + return wf::ipc::json_error("Event list is not an array!"); + } + std::set subscribed_to; - if (data.contains(EVENTS)) + if (data.isMember(EVENTS)) { for (auto& sub : data[EVENTS]) { - if (!sub.is_string()) + if (!sub.isString()) { return wf::ipc::json_error("Event list contains non-string entries!"); } - if (signal_map.count(sub)) + if (signal_map.count(sub.asString())) { - subscribed_to.insert((std::string)sub); + subscribed_to.insert(sub.asString()); } } } else @@ -177,13 +182,13 @@ class ipc_rules_events_methods_t : public wf::per_output_tracker_mixin_t<> void send_view_to_subscribes(wayfire_view view, std::string event_name) { - nlohmann::json event; + Json::Value event; event["event"] = event_name; event["view"] = view_to_json(view); send_event_to_subscribes(event, event_name); } - void send_event_to_subscribes(const nlohmann::json& data, const std::string& event_name) + void send_event_to_subscribes(const Json::Value& data, const std::string& event_name) { for (auto& [client, events] : clients) { @@ -207,32 +212,32 @@ class ipc_rules_events_methods_t : public wf::per_output_tracker_mixin_t<> wf::signal::connection_t on_view_set_output = [=] (wf::view_set_output_signal *ev) { - nlohmann::json data; + Json::Value data; data["event"] = "view-set-output"; data["output"] = output_to_json(ev->output); data["view"] = view_to_json(ev->view); - send_event_to_subscribes(data, data["event"]); + send_event_to_subscribes(data, data["event"].asString()); }; wf::signal::connection_t on_view_geometry_changed = [=] (wf::view_geometry_changed_signal *ev) { - nlohmann::json data; + Json::Value data; data["event"] = "view-geometry-changed"; data["old-geometry"] = wf::ipc::geometry_to_json(ev->old_geometry); data["view"] = view_to_json(ev->view); - send_event_to_subscribes(data, data["event"]); + send_event_to_subscribes(data, data["event"].asString()); }; wf::signal::connection_t on_view_moved_to_wset = [=] (wf::view_moved_to_wset_signal *ev) { - nlohmann::json data; + Json::Value data; data["event"] = "view-wset-changed"; data["old-wset"] = wset_to_json(ev->old_wset.get()); data["new-wset"] = wset_to_json(ev->new_wset.get()); data["view"] = view_to_json(ev->view); - send_event_to_subscribes(data, data["event"]); + send_event_to_subscribes(data, data["event"].asString()); }; wf::signal::connection_t on_kbfocus_changed = @@ -244,12 +249,12 @@ class ipc_rules_events_methods_t : public wf::per_output_tracker_mixin_t<> // Tiled rule handler. wf::signal::connection_t _tiled = [=] (wf::view_tiled_signal *ev) { - nlohmann::json data; + Json::Value data; data["event"] = "view-tiled"; data["old-edges"] = ev->old_edges; data["new-edges"] = ev->new_edges; data["view"] = view_to_json(ev->view); - send_event_to_subscribes(data, data["event"]); + send_event_to_subscribes(data, data["event"].asString()); }; // Minimized rule handler. @@ -273,12 +278,12 @@ class ipc_rules_events_methods_t : public wf::per_output_tracker_mixin_t<> wf::signal::connection_t _view_workspace = [=] (wf::view_change_workspace_signal *ev) { - nlohmann::json data; + Json::Value data; data["event"] = "view-workspace-changed"; data["from"] = wf::ipc::point_to_json(ev->from); data["to"] = wf::ipc::point_to_json(ev->to); data["view"] = view_to_json(ev->view); - send_event_to_subscribes(data, data["event"]); + send_event_to_subscribes(data, data["event"].asString()); }; wf::signal::connection_t on_title_changed = @@ -296,48 +301,48 @@ class ipc_rules_events_methods_t : public wf::per_output_tracker_mixin_t<> wf::signal::connection_t on_plugin_activation_changed = [=] (wf::output_plugin_activated_changed_signal *ev) { - nlohmann::json data; + Json::Value data; data["event"] = "plugin-activation-state-changed"; data["plugin"] = ev->plugin_name; data["state"] = ev->activated; data["output"] = ev->output ? (int)ev->output->get_id() : -1; data["output-data"] = output_to_json(ev->output); - send_event_to_subscribes(data, data["event"]); + send_event_to_subscribes(data, data["event"].asString()); }; wf::signal::connection_t on_output_gain_focus = [=] (wf::output_gain_focus_signal *ev) { - nlohmann::json data; + Json::Value data; data["event"] = "output-gain-focus"; data["output"] = output_to_json(ev->output); - send_event_to_subscribes(data, data["event"]); + send_event_to_subscribes(data, data["event"].asString()); }; wf::signal::connection_t on_wset_changed = [=] (wf::workspace_set_changed_signal *ev) { - nlohmann::json data; + Json::Value data; data["event"] = "output-wset-changed"; data["new-wset"] = ev->new_wset ? (int)ev->new_wset->get_id() : -1; data["output"] = ev->output ? (int)ev->output->get_id() : -1; data["new-wset-data"] = wset_to_json(ev->new_wset.get()); data["output-data"] = output_to_json(ev->output); - send_event_to_subscribes(data, data["event"]); + send_event_to_subscribes(data, data["event"].asString()); }; wf::signal::connection_t on_wset_workspace_changed = [=] (wf::workspace_changed_signal *ev) { - nlohmann::json data; + Json::Value data; data["event"] = "wset-workspace-changed"; data["previous-workspace"] = wf::ipc::point_to_json(ev->old_viewport); data["new-workspace"] = wf::ipc::point_to_json(ev->new_viewport); data["output"] = ev->output ? (int)ev->output->get_id() : -1; data["wset"] = (ev->output && ev->output->wset()) ? (int)ev->output->wset()->get_id() : -1; data["output-data"] = output_to_json(ev->output); - data["wset-data"] = ev->output ? wset_to_json(ev->output->wset().get()) : nullptr; - send_event_to_subscribes(data, data["event"]); + data["wset-data"] = ev->output ? wset_to_json(ev->output->wset().get()) : Json::nullValue; + send_event_to_subscribes(data, data["event"].asString()); }; }; } diff --git a/plugins/ipc-rules/ipc-input-methods.hpp b/plugins/ipc-rules/ipc-input-methods.hpp index e08be5dfc..b95922595 100644 --- a/plugins/ipc-rules/ipc-input-methods.hpp +++ b/plugins/ipc-rules/ipc-input-methods.hpp @@ -1,4 +1,5 @@ #pragma once +#include "plugins/ipc/ipc-helpers.hpp" #include "plugins/ipc/ipc-method-repository.hpp" #include "wayfire/core.hpp" #include "wayfire/debug.hpp" @@ -49,34 +50,34 @@ class ipc_rules_input_methods_t } } - wf::ipc::method_callback list_input_devices = [&] (const nlohmann::json&) + wf::ipc::method_callback list_input_devices = [&] (const Json::Value&) { - auto response = nlohmann::json::array(); + Json::Value response = Json::arrayValue; for (auto& device : wf::get_core().get_input_devices()) { - nlohmann::json d; + Json::Value d; d["id"] = (intptr_t)device->get_wlr_handle(); d["name"] = nonull(device->get_wlr_handle()->name); d["vendor"] = device->get_wlr_handle()->vendor; d["product"] = device->get_wlr_handle()->product; d["type"] = wlr_input_device_type_to_string(device->get_wlr_handle()->type); d["enabled"] = device->is_enabled(); - response.push_back(d); + response.append(d); } return response; }; - wf::ipc::method_callback configure_input_device = [&] (const nlohmann::json& data) + wf::ipc::method_callback configure_input_device = [&] (const Json::Value& data) { - WFJSON_EXPECT_FIELD(data, "id", number_unsigned); - WFJSON_EXPECT_FIELD(data, "enabled", boolean); + auto id = wf::ipc::json_get_int64(data, "id"); + auto enabled = wf::ipc::json_get_bool(data, "enabled"); for (auto& device : wf::get_core().get_input_devices()) { - if ((intptr_t)device->get_wlr_handle() == data["id"]) + if ((intptr_t)device->get_wlr_handle() == id) { - device->set_enabled(data["enabled"]); + device->set_enabled(enabled); return wf::ipc::json_ok(); } diff --git a/plugins/ipc-rules/ipc-rules-common.hpp b/plugins/ipc-rules/ipc-rules-common.hpp index 4cecf7f66..1022f4f96 100644 --- a/plugins/ipc-rules/ipc-rules-common.hpp +++ b/plugins/ipc-rules/ipc-rules-common.hpp @@ -9,14 +9,14 @@ #include #include -static inline nlohmann::json output_to_json(wf::output_t *o) +static inline Json::Value output_to_json(wf::output_t *o) { if (!o) { - return nullptr; + return Json::nullValue; } - nlohmann::json response; + Json::Value response; response["id"] = o->get_id(); response["name"] = o->to_string(); response["geometry"] = wf::ipc::geometry_to_json(o->get_layout_geometry()); @@ -165,15 +165,15 @@ static inline std::string get_view_type(wayfire_view view) return "unknown"; } -static inline nlohmann::json view_to_json(wayfire_view view) +static inline Json::Value view_to_json(wayfire_view view) { if (!view) { - return nullptr; + return Json::nullValue; } auto output = view->get_output(); - nlohmann::json description; + Json::Value description; description["id"] = view->get_id(); description["pid"] = get_view_pid(view); description["title"] = view->get_title(); @@ -206,14 +206,14 @@ static inline nlohmann::json view_to_json(wayfire_view view) return description; } -static inline nlohmann::json wset_to_json(wf::workspace_set_t *wset) +static inline Json::Value wset_to_json(wf::workspace_set_t *wset) { if (!wset) { - return nullptr; + return Json::nullValue; } - nlohmann::json response; + Json::Value response; response["index"] = wset->get_index(); response["name"] = wset->to_string(); diff --git a/plugins/ipc-rules/ipc-rules.cpp b/plugins/ipc-rules/ipc-rules.cpp index 88fa4b949..1f727ef56 100644 --- a/plugins/ipc-rules/ipc-rules.cpp +++ b/plugins/ipc-rules/ipc-rules.cpp @@ -60,23 +60,22 @@ class ipc_rules_t : public wf::plugin_interface_t, fini_events(method_repository.get()); } - wf::ipc::method_callback list_views = [=] (nlohmann::json) + wf::ipc::method_callback list_views = [=] (Json::Value) { - auto response = nlohmann::json::array(); - + Json::Value response = Json::arrayValue; for (auto& view : wf::get_core().get_all_views()) { - nlohmann::json v = view_to_json(view); - response.push_back(v); + Json::Value v = view_to_json(view); + response.append(v); } return response; }; - wf::ipc::method_callback get_view_info = [=] (nlohmann::json data) + wf::ipc::method_callback get_view_info = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "id", number_integer); - if (auto view = wf::ipc::find_view_by_id(data["id"])) + auto id = wf::ipc::json_get_uint64(data, "id"); + if (auto view = wf::ipc::find_view_by_id(id)) { auto response = wf::ipc::json_ok(); response["info"] = view_to_json(view); @@ -86,7 +85,7 @@ class ipc_rules_t : public wf::plugin_interface_t, return wf::ipc::json_error("no such view"); }; - wf::ipc::method_callback get_focused_view = [=] (nlohmann::json data) + wf::ipc::method_callback get_focused_view = [=] (Json::Value data) { if (auto view = wf::get_core().seat->get_active_view()) { @@ -96,12 +95,12 @@ class ipc_rules_t : public wf::plugin_interface_t, } else { auto response = wf::ipc::json_ok(); - response["info"] = nullptr; + response["info"] = Json::nullValue; return response; } }; - wf::ipc::method_callback get_focused_output = [=] (nlohmann::json data) + wf::ipc::method_callback get_focused_output = [=] (Json::Value data) { auto active_output = wf::get_core().seat->get_active_output(); auto response = wf::ipc::json_ok(); @@ -111,16 +110,16 @@ class ipc_rules_t : public wf::plugin_interface_t, response["info"] = output_to_json(active_output); } else { - response["info"] = nullptr; + response["info"] = Json::nullValue; } return response; }; - wf::ipc::method_callback focus_view = [=] (nlohmann::json data) + wf::ipc::method_callback focus_view = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "id", number_integer); - if (auto view = wf::ipc::find_view_by_id(data["id"])) + auto id = wf::ipc::json_get_uint64(data, "id"); + if (auto view = wf::ipc::find_view_by_id(id)) { auto response = wf::ipc::json_ok(); auto toplevel = wf::toplevel_cast(view); @@ -136,10 +135,10 @@ class ipc_rules_t : public wf::plugin_interface_t, return wf::ipc::json_error("no such view"); }; - wf::ipc::method_callback close_view = [=] (nlohmann::json data) + wf::ipc::method_callback close_view = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "id", number_integer); - if (auto view = wf::ipc::find_view_by_id(data["id"])) + auto id = wf::ipc::json_get_uint64(data, "id"); + if (auto view = wf::ipc::find_view_by_id(id)) { auto response = wf::ipc::json_ok(); view->close(); @@ -149,21 +148,21 @@ class ipc_rules_t : public wf::plugin_interface_t, return wf::ipc::json_error("no such view"); }; - wf::ipc::method_callback list_outputs = [=] (nlohmann::json) + wf::ipc::method_callback list_outputs = [=] (Json::Value) { - auto response = nlohmann::json::array(); + Json::Value response = Json::arrayValue; for (auto& output : wf::get_core().output_layout->get_outputs()) { - response.push_back(output_to_json(output)); + response.append(output_to_json(output)); } return response; }; - wf::ipc::method_callback get_output_info = [=] (nlohmann::json data) + wf::ipc::method_callback get_output_info = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "id", number_integer); - auto wo = wf::ipc::find_output_by_id(data["id"]); + auto id = wf::ipc::json_get_uint64(data, "id"); + auto wo = wf::ipc::find_output_by_id(id); if (!wo) { return wf::ipc::json_error("output not found"); @@ -173,14 +172,18 @@ class ipc_rules_t : public wf::plugin_interface_t, return response; }; - wf::ipc::method_callback configure_view = [=] (nlohmann::json data) + wf::ipc::method_callback configure_view = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "id", number_integer); - WFJSON_OPTIONAL_FIELD(data, "output_id", number_integer); - WFJSON_OPTIONAL_FIELD(data, "geometry", object); - WFJSON_OPTIONAL_FIELD(data, "sticky", boolean); + auto id = wf::ipc::json_get_uint64(data, "id"); + auto output_id = wf::ipc::json_get_optional_uint64(data, "output_id"); + + if (data.isMember("geometry") && !data["geometry"].isObject()) + { + return wf::ipc::json_error("invalid geometry"); + } - auto view = wf::ipc::find_view_by_id(data["id"]); + auto sticky = wf::ipc::json_get_optional_bool(data, "sticky"); + auto view = wf::ipc::find_view_by_id(id); if (!view) { return wf::ipc::json_error("view not found"); @@ -192,18 +195,18 @@ class ipc_rules_t : public wf::plugin_interface_t, return wf::ipc::json_error("view is not toplevel"); } - if (data.contains("output_id")) + if (output_id.has_value()) { - auto wo = wf::ipc::find_output_by_id(data["output_id"]); + auto wo = wf::ipc::find_output_by_id(output_id.value()); if (!wo) { return wf::ipc::json_error("output not found"); } - wf::move_view_to_output(toplevel, wo, !data.contains("geometry")); + wf::move_view_to_output(toplevel, wo, !data.isMember("geometry")); } - if (data.contains("geometry")) + if (data.isMember("geometry")) { auto geometry = wf::ipc::geometry_from_json(data["geometry"]); if (!geometry) @@ -214,29 +217,29 @@ class ipc_rules_t : public wf::plugin_interface_t, toplevel->set_geometry(*geometry); } - if (data.contains("sticky")) + if (sticky.has_value()) { - toplevel->set_sticky(data["sticky"]); + toplevel->set_sticky(sticky.value()); } return wf::ipc::json_ok(); }; - wf::ipc::method_callback list_wsets = [=] (nlohmann::json) + wf::ipc::method_callback list_wsets = [=] (Json::Value) { - auto response = nlohmann::json::array(); + Json::Value response = Json::arrayValue; for (auto& workspace_set : wf::workspace_set_t::get_all()) { - response.push_back(wset_to_json(workspace_set.get())); + response.append(wset_to_json(workspace_set.get())); } return response; }; - wf::ipc::method_callback get_wset_info = [=] (nlohmann::json data) + wf::ipc::method_callback get_wset_info = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "id", number_integer); - auto ws = wf::ipc::find_workspace_set_by_index(data["id"]); + auto id = wf::ipc::json_get_uint64(data, "id"); + auto ws = wf::ipc::find_workspace_set_by_index(id); if (!ws) { return wf::ipc::json_error("workspace set not found"); diff --git a/plugins/ipc-rules/ipc-utility-methods.hpp b/plugins/ipc-rules/ipc-utility-methods.hpp index bd61ca849..5a382b5bd 100644 --- a/plugins/ipc-rules/ipc-utility-methods.hpp +++ b/plugins/ipc-rules/ipc-utility-methods.hpp @@ -9,6 +9,7 @@ #include #include #include +#include "json/writer.h" extern "C" { #include @@ -42,9 +43,9 @@ class ipc_rules_utility_methods_t method_repository->unregister_method("wayfire/set-config-option"); } - wf::ipc::method_callback get_wayfire_configuration_info = [=] (nlohmann::json) + wf::ipc::method_callback get_wayfire_configuration_info = [=] (Json::Value) { - nlohmann::json response; + Json::Value response; response["api-version"] = WAYFIRE_API_ABI_VERSION; response["plugin-path"] = PLUGIN_PATH; @@ -56,10 +57,10 @@ class ipc_rules_utility_methods_t return response; }; - wf::ipc::method_callback create_headless_output = [=] (const nlohmann::json& data) + wf::ipc::method_callback create_headless_output = [=] (const Json::Value& data) { - WFJSON_EXPECT_FIELD(data, "width", number_unsigned); - WFJSON_EXPECT_FIELD(data, "height", number_unsigned); + auto width = wf::ipc::json_get_uint64(data, "width"); + auto height = wf::ipc::json_get_uint64(data, "height"); if (!headless_backend) { @@ -69,7 +70,7 @@ class ipc_rules_utility_methods_t wlr_backend_start(headless_backend); } - auto handle = wlr_headless_add_output(headless_backend, data["width"], data["height"]); + auto handle = wlr_headless_add_output(headless_backend, width, height); auto wo = wf::get_core().output_layout->find_output(handle); our_outputs.insert(wo->get_id()); @@ -78,45 +79,44 @@ class ipc_rules_utility_methods_t return response; }; - wf::ipc::method_callback destroy_headless_output = [=] (const nlohmann::json& data) + wf::ipc::method_callback destroy_headless_output = [=] (const Json::Value& data) { - WFJSON_OPTIONAL_FIELD(data, "output", string); - WFJSON_OPTIONAL_FIELD(data, "output-id", number_unsigned); + auto output = wf::ipc::json_get_optional_string(data, "output"); + auto output_id = wf::ipc::json_get_optional_uint64(data, "output-id"); - if (!data.count("output") && !data.count("output-id")) + if (!output.has_value() && !output_id.has_value()) { return wf::ipc::json_error("Missing `output` or `output-id`!"); } - wf::output_t *output = NULL; - if (data.count("output")) + wf::output_t *wo = NULL; + if (output.has_value()) { - output = wf::get_core().output_layout->find_output(data["output"]); - } else if (data.count("output-id")) + wo = wf::get_core().output_layout->find_output(output.value()); + } else if (output_id.has_value()) { - output = wf::ipc::find_output_by_id(data["output-id"]); + wo = wf::ipc::find_output_by_id(output_id.value()); } - if (!output) + if (!wo) { return wf::ipc::json_error("Output not found!"); } - if (!our_outputs.count(output->get_id())) + if (!our_outputs.count(wo->get_id())) { return wf::ipc::json_error("Output is not a headless output created from an IPC command!"); } - our_outputs.erase(output->get_id()); - wlr_output_destroy(output->handle); + our_outputs.erase(wo->get_id()); + wlr_output_destroy(wo->handle); return wf::ipc::json_ok(); }; - wf::ipc::method_callback get_config_option = [=] (const nlohmann::json& data) + wf::ipc::method_callback get_config_option = [=] (const Json::Value& data) { - WFJSON_EXPECT_FIELD(data, "option", string); - - auto option = wf::get_core().config->get_option(data["option"]); + auto option_name = wf::ipc::json_get_string(data, "option"); + auto option = wf::get_core().config->get_option(option_name); if (!option) { return wf::ipc::json_error("Option not found!"); @@ -128,17 +128,18 @@ class ipc_rules_utility_methods_t return response; }; - std::string json_to_string(const nlohmann::json& data) + std::string json_to_string(const Json::Value& data) { - if (data.is_string()) + if (data.isString()) { - return data; + return data.asString(); } - return data.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore); + Json::FastWriter writer; + return writer.write(data); } - std::optional add_compound_entry(const nlohmann::json& entry, + std::optional add_compound_entry(const Json::Value& entry, const std::string& entry_name, const wf::config::compound_option_t::entries_t& tuple_entries, std::vector>& values) @@ -146,7 +147,7 @@ class ipc_rules_utility_methods_t values.emplace_back(); values.back().push_back(entry_name); - if (!entry.is_structured() && (tuple_entries.size() == 1)) + if (!entry.isObject() && (tuple_entries.size() == 1)) { auto str_value = json_to_string(entry); if (!tuple_entries[0]->is_parsable(str_value)) @@ -155,7 +156,7 @@ class ipc_rules_utility_methods_t } values.back().push_back(str_value); - } else if (entry.is_array()) + } else if (entry.isArray()) { // A simple tuple => copy one to one if (entry.size() != tuple_entries.size()) @@ -165,7 +166,7 @@ class ipc_rules_utility_methods_t for (size_t i = 0; i < entry.size(); i++) { - auto str_value = json_to_string(entry[i]); + auto str_value = json_to_string(entry.get(i, Json::Value::null)); if (!tuple_entries[i]->is_parsable(str_value)) { return "Failed to parse entry " + str_value; @@ -173,11 +174,11 @@ class ipc_rules_utility_methods_t values.back().push_back(str_value); } - } else if (entry.is_object()) + } else if (entry.isObject()) { for (size_t i = 0; i < tuple_entries.size(); i++) { - if (entry.contains(tuple_entries[i]->get_name())) + if (entry.isMember(tuple_entries[i]->get_name())) { auto str_value = json_to_string(entry[tuple_entries[i]->get_name()]); if (!tuple_entries[i]->is_parsable(str_value)) @@ -202,14 +203,14 @@ class ipc_rules_utility_methods_t return {}; } - std::optional parse_compound_json(const nlohmann::json& data, + std::optional parse_compound_json(const Json::Value& data, std::shared_ptr option) { std::vector> values; const auto& tuple_entries = option->get_entries(); int counter = 0; - if (data.is_array()) + if (data.isArray()) { for (auto& entry : data) { @@ -219,11 +220,11 @@ class ipc_rules_utility_methods_t return err; } } - } else if (data.is_object()) + } else if (data.isObject()) { - for (auto& [key, tuple_items] : data.items()) + for (auto& key : data.getMemberNames()) { - if (auto err = add_compound_entry(tuple_items, key, tuple_entries, values)) + if (auto err = add_compound_entry(data[key], key, tuple_entries, values)) { return err; } @@ -237,14 +238,14 @@ class ipc_rules_utility_methods_t return {}; } - wf::ipc::method_callback set_config_options = [=] (const nlohmann::json& data) -> nlohmann::json + wf::ipc::method_callback set_config_options = [=] (const Json::Value& data) -> Json::Value { - if (!data.is_object()) + if (!data.isObject()) { return wf::ipc::json_error("Options must be an object!"); } - for (auto& [option, value] : data.items()) + for (auto& option : data.getMemberNames()) { auto opt = wf::get_core().config->get_option(option); if (!opt) @@ -254,17 +255,17 @@ class ipc_rules_utility_methods_t if (auto compound = std::dynamic_pointer_cast(opt)) { - auto error = parse_compound_json(value, compound); + auto error = parse_compound_json(data[option], compound); if (error.has_value()) { return wf::ipc::json_error(option + ": " + error.value()); } } else { - if (!opt->set_value_str(json_to_string(value))) + if (!opt->set_value_str(json_to_string(data[option]))) { return wf::ipc::json_error(option + ": Invalid value for option " + - std::string(json_to_string(value)) + "!"); + std::string(json_to_string(data[option])) + "!"); } } diff --git a/plugins/ipc/demo-ipc.cpp b/plugins/ipc/demo-ipc.cpp index a232da06d..e6f366958 100644 --- a/plugins/ipc/demo-ipc.cpp +++ b/plugins/ipc/demo-ipc.cpp @@ -34,64 +34,64 @@ class wayfire_demo_ipc : public wf::plugin_interface_t } wf::ipc::method_callback_full on_client_watch = - [=] (nlohmann::json data, wf::ipc::client_interface_t *client) + [=] (Json::Value data, wf::ipc::client_interface_t *client) { clients.insert(client); return wf::ipc::json_ok(); }; - wf::ipc::method_callback get_view_info = [=] (nlohmann::json data) + wf::ipc::method_callback get_view_info = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "id", number_integer); - - for (auto view : wf::get_core().get_all_views()) - { - if (view->get_id() == data["id"]) - { - auto response = wf::ipc::json_ok(); - response["info"] = view_to_json(view); - return response; - } - } +// WFJSON_EXPECT_FIELD(data, "id", number_integer); +// +// for (auto view : wf::get_core().get_all_views()) +// { +// if (view->get_id() == data["id"]) +// { +// auto response = wf::ipc::json_ok(); +// response["info"] = view_to_json(view); +// return response; +// } +// } return wf::ipc::json_error("no such view"); }; - wf::ipc::method_callback get_output_info = [=] (nlohmann::json data) + wf::ipc::method_callback get_output_info = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "id", number_integer); - auto wo = wf::ipc::find_output_by_id(data["id"]); - if (!wo) - { - return wf::ipc::json_error("output not found"); - } - - auto response = wf::ipc::json_ok(); - response["info"]["name"] = wo->to_string(); - response["info"]["geometry"] = wf::ipc::geometry_to_json(wo->get_layout_geometry()); - return response; +// WFJSON_EXPECT_FIELD(data, "id", number_integer); +// auto wo = wf::ipc::find_output_by_id(data["id"]); +// if (!wo) +// { +// return wf::ipc::json_error("output not found"); +// } +// +// auto response = wf::ipc::json_ok(); +// response["info"]["name"] = wo->to_string(); +// response["info"]["geometry"] = wf::ipc::geometry_to_json(wo->get_layout_geometry()); + return wf::ipc::json_ok(); }; - wf::ipc::method_callback set_view_geometry = [=] (nlohmann::json data) + wf::ipc::method_callback set_view_geometry = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "id", number_integer); - WFJSON_EXPECT_FIELD(data, "geometry", object); + // WFJSON_EXPECT_FIELD(data, "id", number_integer); + // WFJSON_EXPECT_FIELD(data, "geometry", object); - if (auto view = wf::ipc::find_view_by_id(data["id"])) - { - if (auto geometry = wf::ipc::geometry_from_json(data["geometry"])) - { - if (auto toplevel = toplevel_cast(view)) - { - toplevel->set_geometry(geometry.value()); - return wf::ipc::json_ok(); - } - - return wf::ipc::json_error("view is not toplevel"); - } - - return wf::ipc::json_error("geometry incorrect"); - } + // if (auto view = wf::ipc::find_view_by_id(data["id"])) + // { + // if (auto geometry = wf::ipc::geometry_from_json(data["geometry"])) + // { + // if (auto toplevel = toplevel_cast(view)) + // { + // toplevel->set_geometry(geometry.value()); + // return wf::ipc::json_ok(); + // } + + // return wf::ipc::json_error("view is not toplevel"); + // } + + // return wf::ipc::json_error("geometry incorrect"); + // } return wf::ipc::json_error("view not found"); }; @@ -108,7 +108,7 @@ class wayfire_demo_ipc : public wf::plugin_interface_t wf::signal::connection_t on_view_mapped = [=] (wf::view_mapped_signal *ev) { - nlohmann::json event; + Json::Value event; event["event"] = "view-mapped"; event["view"] = view_to_json(ev->view); for (auto& client : clients) @@ -117,9 +117,9 @@ class wayfire_demo_ipc : public wf::plugin_interface_t } }; - nlohmann::json view_to_json(wayfire_view view) + Json::Value view_to_json(wayfire_view view) { - nlohmann::json description; + Json::Value description; description["id"] = view->get_id(); description["app-id"] = view->get_app_id(); description["title"] = view->get_title(); diff --git a/plugins/ipc/ipc-activator.hpp b/plugins/ipc/ipc-activator.hpp index 86054f85c..a9b10b9ff 100644 --- a/plugins/ipc/ipc-activator.hpp +++ b/plugins/ipc/ipc-activator.hpp @@ -70,24 +70,24 @@ class ipc_activator_t return false; }; - ipc::method_callback ipc_cb = [=] (const nlohmann::json& data) + ipc::method_callback ipc_cb = [=] (const Json::Value& data) { - WFJSON_OPTIONAL_FIELD(data, "output_id", number_integer); - WFJSON_OPTIONAL_FIELD(data, "view_id", number_integer); - WFJSON_OPTIONAL_FIELD(data, "output-id", number_integer); - WFJSON_OPTIONAL_FIELD(data, "view-id", number_integer); + auto output_id = ipc::json_get_optional_int64(data, "output_id"); + if (!output_id.has_value()) + { + output_id = ipc::json_get_optional_int64(data, "output-id"); + } - wf::output_t *wo = wf::get_core().seat->get_active_output(); - if (data.contains("output_id")) + auto view_id = ipc::json_get_optional_int64(data, "view_id"); + if (!view_id.has_value()) { - wo = ipc::find_output_by_id(data["output_id"]); - if (!wo) - { - return ipc::json_error("output id not found!"); - } - } else if (data.contains("output-id")) + view_id = ipc::json_get_optional_int64(data, "view-id"); + } + + wf::output_t *wo = wf::get_core().seat->get_active_output(); + if (output_id.has_value()) { - wo = ipc::find_output_by_id(data["output-id"]); + wo = ipc::find_output_by_id(output_id.value()); if (!wo) { return ipc::json_error("output id not found!"); @@ -95,16 +95,9 @@ class ipc_activator_t } wayfire_view view; - if (data.contains("view_id")) - { - view = ipc::find_view_by_id(data["view_id"]); - if (!view) - { - return ipc::json_error("view id not found!"); - } - } else if (data.contains("view-id")) + if (view_id.has_value()) { - view = ipc::find_view_by_id(data["view-id"]); + view = ipc::find_view_by_id(view_id.has_value()); if (!view) { return ipc::json_error("view id not found!"); diff --git a/plugins/ipc/ipc-helpers.hpp b/plugins/ipc/ipc-helpers.hpp index ea3437fbb..0b4d2be96 100644 --- a/plugins/ipc/ipc-helpers.hpp +++ b/plugins/ipc/ipc-helpers.hpp @@ -1,18 +1,56 @@ #pragma once #include "wayfire/geometry.hpp" +#include #include #include #include #include #include #include -#include // IWYU pragma: keep namespace wf { namespace ipc { +#define WFJSON_GETTER_FUNCTION(type, suffix, rtype) \ + inline rtype json_get_ ## suffix(const Json::Value& data, std::string field) \ + { \ + if (!data.isMember(field)) \ + { \ + throw ("Missing \"" + field + "\""); \ + } \ + else if (!data[field].is ## type()) \ + { \ + throw ("Field \"" + field + "\" does not have the correct type, expected " #type); \ + } \ +\ + return data[field].as ## type(); \ + } \ + \ + inline std::optional json_get_optional_ ## suffix(const Json::Value& data, std::string field) \ + { \ + if (!data.isMember(field)) \ + { \ + return {}; \ + } \ + else if (!data[field].is ## type()) \ + { \ + throw ("Field \"" + field + "\" does not have the correct type, expected " #type); \ + } \ +\ + return data[field].as ## type(); \ + } + +WFJSON_GETTER_FUNCTION(Int64, int64, int64_t); +WFJSON_GETTER_FUNCTION(UInt64, uint64, uint64_t); +WFJSON_GETTER_FUNCTION(Double, f64, double); +WFJSON_GETTER_FUNCTION(String, string, std::string); +WFJSON_GETTER_FUNCTION(Bool, bool, bool); + +#undef WFJSON_GETTER_FUNCTION + + inline wayfire_view find_view_by_id(uint32_t id) { for (auto view : wf::get_core().get_all_views()) @@ -52,9 +90,9 @@ inline wf::workspace_set_t *find_workspace_set_by_index(int32_t index) return nullptr; } -inline nlohmann::json geometry_to_json(wf::geometry_t g) +inline Json::Value geometry_to_json(wf::geometry_t g) { - nlohmann::json j; + Json::Value j; j["x"] = g.x; j["y"] = g.y; j["width"] = g.width; @@ -62,11 +100,11 @@ inline nlohmann::json geometry_to_json(wf::geometry_t g) return j; } -inline std::optional geometry_from_json(const nlohmann::json& j) +inline std::optional geometry_from_json(const Json::Value& j) { -#define CHECK(field, type) (j.contains(field) && j[field].is_number_ ## type()) - if (!CHECK("x", integer) || !CHECK("y", integer) || - !CHECK("width", unsigned) || !CHECK("height", unsigned)) +#define CHECK(field, type) (j.isMember(field) && j[field].is ## type()) + if (!CHECK("x", Int) || !CHECK("y", Int) || + !CHECK("width", Int) || !CHECK("height", Int)) { return {}; } @@ -74,25 +112,25 @@ inline std::optional geometry_from_json(const nlohmann::json& j) #undef CHECK return wf::geometry_t{ - .x = j["x"], - .y = j["y"], - .width = j["width"], - .height = j["height"], + .x = j["x"].asInt(), + .y = j["y"].asInt(), + .width = j["width"].asInt(), + .height = j["height"].asInt(), }; } -inline nlohmann::json point_to_json(wf::point_t p) +inline Json::Value point_to_json(wf::point_t p) { - nlohmann::json j; + Json::Value j; j["x"] = p.x; j["y"] = p.y; return j; } -inline std::optional point_from_json(const nlohmann::json& j) +inline std::optional point_from_json(const Json::Value& j) { -#define CHECK(field, type) (j.contains(field) && j[field].is_number_ ## type()) - if (!CHECK("x", integer) || !CHECK("y", integer)) +#define CHECK(field, type) (j.isMember(field) && j[field].is ## type()) + if (!CHECK("x", Int) || !CHECK("y", Int)) { return {}; } @@ -100,23 +138,23 @@ inline std::optional point_from_json(const nlohmann::json& j) #undef CHECK return wf::point_t{ - .x = j["x"], - .y = j["y"], + .x = j["x"].asInt(), + .y = j["y"].asInt(), }; } -inline nlohmann::json dimensions_to_json(wf::dimensions_t d) +inline Json::Value dimensions_to_json(wf::dimensions_t d) { - nlohmann::json j; + Json::Value j; j["width"] = d.width; j["height"] = d.height; return j; } -inline std::optional dimensions_from_json(const nlohmann::json& j) +inline std::optional dimensions_from_json(const Json::Value& j) { -#define CHECK(field, type) (j.contains(field) && j[field].is_number_ ## type()) - if (!CHECK("width", integer) || !CHECK("height", integer)) +#define CHECK(field, type) (j.isMember(field) && j[field].is ## type()) + if (!CHECK("width", Int) || !CHECK("height", Int)) { return {}; } @@ -124,8 +162,8 @@ inline std::optional dimensions_from_json(const nlohmann::json #undef CHECK return wf::dimensions_t{ - .width = j["width"], - .height = j["height"], + .width = j["width"].asInt(), + .height = j["height"].asInt(), }; } } diff --git a/plugins/ipc/ipc-method-repository.hpp b/plugins/ipc/ipc-method-repository.hpp index 1105c6f1c..8de642f14 100644 --- a/plugins/ipc/ipc-method-repository.hpp +++ b/plugins/ipc/ipc-method-repository.hpp @@ -1,6 +1,6 @@ #pragma once -#include // IWYU pragma: keep +#include #include #include #include "wayfire/signal-provider.hpp" @@ -16,7 +16,7 @@ namespace ipc class client_interface_t { public: - virtual void send_json(nlohmann::json json) = 0; + virtual void send_json(Json::Value json) = 0; virtual ~client_interface_t() = default; }; @@ -32,12 +32,12 @@ struct client_disconnected_signal * An IPC method has a name and a callback. The callback is a simple function which takes a json object which * contains the method's parameters and returns the result of the operation. */ -using method_callback = std::function; +using method_callback = std::function; /** * Same as @method_callback, but also supports getting information about the connected ipc client. */ -using method_callback_full = std::function; +using method_callback_full = std::function; /** * The IPC method repository keeps track of all registered IPC methods. It can be used even without the IPC @@ -63,7 +63,7 @@ class method_repository_t : public wf::signal::provider_t */ void register_method(std::string method, method_callback handler) { - this->methods[method] = [handler] (const nlohmann::json& data, client_interface_t*) + this->methods[method] = [handler] (const Json::Value& data, client_interface_t*) { return handler(data); }; @@ -81,7 +81,7 @@ class method_repository_t : public wf::signal::provider_t * Call an IPC method with the given name and given parameters. * If the method was not registered, a JSON object containing an error will be returned. */ - nlohmann::json call_method(std::string method, nlohmann::json data, + Json::Value call_method(std::string method, Json::Value data, client_interface_t *client = nullptr) { if (this->methods.count(method)) @@ -98,11 +98,11 @@ class method_repository_t : public wf::signal::provider_t { register_method("list-methods", [this] (auto) { - nlohmann::json response; - response["methods"] = nlohmann::json::array(); + Json::Value response; + response["methods"] = Json::arrayValue; for (auto& [method, _] : methods) { - response["methods"].push_back(method); + response["methods"].append(method); } return response; @@ -114,35 +114,18 @@ class method_repository_t : public wf::signal::provider_t }; // A few helper definitions for IPC method implementations. -inline nlohmann::json json_ok() +inline Json::Value json_ok() { - return nlohmann::json{ - {"result", "ok"} - }; + Json::Value r; + r["result"] = "ok"; + return r; } -inline nlohmann::json json_error(std::string msg) +inline Json::Value json_error(std::string msg) { - return nlohmann::json{ - {"error", std::string(msg)} - }; + Json::Value r; + r["error"] = msg; + return r; } - -#define WFJSON_EXPECT_FIELD(data, field, type) \ - if (!data.count(field)) \ - { \ - return wf::ipc::json_error("Missing \"" field "\""); \ - } \ - else if (!data[field].is_ ## type()) \ - { \ - return wf::ipc::json_error("Field \"" field "\" does not have the correct type " #type); \ - } - -#define WFJSON_OPTIONAL_FIELD(data, field, type) \ - if (data.count(field) && !data[field].is_ ## type()) \ - { \ - return wf::ipc::json_error("Field \"" + std::string(field) + \ - "\" does not have the correct type " #type); \ - } } } diff --git a/plugins/ipc/ipc.cpp b/plugins/ipc/ipc.cpp index 35de9d7e7..ad2b60ede 100644 --- a/plugins/ipc/ipc.cpp +++ b/plugins/ipc/ipc.cpp @@ -10,6 +10,9 @@ #include #include +#include +#include + /** * Handle WL_EVENT_READABLE on the socket. * Indicates a new connection. @@ -131,9 +134,9 @@ void wf::ipc::server_t::client_disappeared(client_t *client) } void wf::ipc::server_t::handle_incoming_message( - client_t *client, nlohmann::json message) + client_t *client, Json::Value message) { - client->send_json(method_repository->call_method(message["method"], message["data"], client)); + client->send_json(method_repository->call_method(message["method"].asString(), message["data"], client)); } /* --------------------------- Per-client code ------------------------------*/ @@ -249,16 +252,19 @@ void wf::ipc::client_t::handle_fd_incoming(uint32_t event_mask) // Finally, received the message, make sure we have a terminating NULL byte buffer[current_buffer_valid] = '\0'; - char *str = buffer.data() + HEADER_LEN; - auto message = nlohmann::json::parse(str, nullptr, false); - if (message.is_discarded()) + char *str = buffer.data() + HEADER_LEN; + + Json::Reader reader; + Json::Value message; + + if (!reader.parse(str, message, false)) { LOGE("Client's message could not be parsed: ", str); ipc->client_disappeared(this); return; } - if (!message.contains("method")) + if (!message.isMember("method") || !message["method"].isString()) { LOGE("Client's message does not contain a method to be called!"); ipc->client_disappeared(this); @@ -295,9 +301,10 @@ static bool write_exact(int fd, char *buf, ssize_t n) return true; } -void wf::ipc::client_t::send_json(nlohmann::json json) +void wf::ipc::client_t::send_json(Json::Value json) { - std::string serialized = json.dump(-1, ' ', false, nlohmann::detail::error_handler_t::ignore); + Json::FastWriter writer; + std::string serialized = writer.write(json); if (serialized.length() > MAX_MESSAGE_LEN) { LOGE("Error sending json to client: message too long!"); diff --git a/plugins/ipc/ipc.hpp b/plugins/ipc/ipc.hpp index 69009de75..8b97c235b 100644 --- a/plugins/ipc/ipc.hpp +++ b/plugins/ipc/ipc.hpp @@ -1,6 +1,5 @@ #pragma once -#include // IWYU pragma: keep #include #include #include @@ -20,7 +19,7 @@ class client_t : public client_interface_t public: client_t(server_t *server, int client_fd); ~client_t(); - void send_json(nlohmann::json json) override; + void send_json(Json::Value json) override; private: int fd; @@ -51,7 +50,7 @@ class server_t friend class client_t; wf::shared_data::ref_ptr_t method_repository; - void handle_incoming_message(client_t *client, nlohmann::json message); + void handle_incoming_message(client_t *client, Json::Value message); void client_disappeared(client_t *client); diff --git a/plugins/ipc/stipc.cpp b/plugins/ipc/stipc.cpp index 06d3f2eab..8aa40f6b5 100644 --- a/plugins/ipc/stipc.cpp +++ b/plugins/ipc/stipc.cpp @@ -1,3 +1,4 @@ +#include "ipc-helpers.hpp" #include "ipc-method-repository.hpp" #include "wayfire/plugin.hpp" #include "wayfire/plugins/common/shared-core-data.hpp" @@ -312,56 +313,60 @@ class stipc_plugin_t : public wf::plugin_interface_t return false; } - ipc::method_callback layout_views = [] (nlohmann::json data) + ipc::method_callback layout_views = [] (Json::Value data) { auto views = wf::get_core().get_all_views(); - WFJSON_EXPECT_FIELD(data, "views", array); + if (!data.isMember("views") || !data["views"].isArray()) + { + return wf::ipc::json_error("Views not specified"); + } + for (auto v : data["views"]) { - WFJSON_EXPECT_FIELD(v, "id", number); - WFJSON_EXPECT_FIELD(v, "x", number); - WFJSON_EXPECT_FIELD(v, "y", number); - WFJSON_EXPECT_FIELD(v, "width", number); - WFJSON_EXPECT_FIELD(v, "height", number); + auto id = wf::ipc::json_get_uint64(v, "id"); + int x = wf::ipc::json_get_int64(v, "x"); + int y = wf::ipc::json_get_int64(v, "y"); + int width = wf::ipc::json_get_int64(v, "width"); + int height = wf::ipc::json_get_int64(v, "height"); + auto output = wf::ipc::json_get_optional_string(v, "output"); auto it = std::find_if(views.begin(), views.end(), [&] (auto& view) { - return view->get_id() == v["id"]; + return view->get_id() == v["id"].asUInt(); }); if (it == views.end()) { return wf::ipc::json_error("Could not find view with id " + - std::to_string((int)v["id"])); + std::to_string(id)); } auto toplevel = toplevel_cast(*it); if (!toplevel) { return wf::ipc::json_error("View is not toplevel view id " + - std::to_string((int)v["id"])); + std::to_string(id)); } - if (v.contains("output")) + if (output.has_value()) { - WFJSON_EXPECT_FIELD(v, "output", string); - auto wo = wf::get_core().output_layout->find_output(v["output"]); + auto wo = wf::get_core().output_layout->find_output(output.value()); if (!wo) { - return wf::ipc::json_error("Unknown output " + (std::string)v["output"]); + return wf::ipc::json_error("Unknown output " + (std::string)output.value()); } move_view_to_output(toplevel, wo, false); } - wf::geometry_t g{v["x"], v["y"], v["width"], v["height"]}; + wf::geometry_t g{x, y, width, height}; toplevel->set_geometry(g); } return wf::ipc::json_ok(); }; - ipc::method_callback create_wayland_output = [] (nlohmann::json) + ipc::method_callback create_wayland_output = [] (Json::Value) { auto backend = wf::get_core().backend; @@ -378,14 +383,13 @@ class stipc_plugin_t : public wf::plugin_interface_t return wf::ipc::json_ok(); }; - ipc::method_callback destroy_wayland_output = [] (nlohmann::json data) + ipc::method_callback destroy_wayland_output = [] (Json::Value data) -> Json::Value { - WFJSON_EXPECT_FIELD(data, "output", string); - auto output = wf::get_core().output_layout->find_output(data["output"]); + auto output_str = wf::ipc::json_get_string(data, "output"); + auto output = wf::get_core().output_layout->find_output(output_str); if (!output) { - return wf::ipc::json_error("Could not find output: \"" + - (std::string)data["output"] + "\""); + return wf::ipc::json_error("Could not find output: \"" + output_str + "\""); } if (!wlr_output_is_wl(output->handle)) @@ -403,14 +407,9 @@ class stipc_plugin_t : public wf::plugin_interface_t int code; }; - std::variant parse_key(nlohmann::json data) + std::variant parse_key(Json::Value data) { - if (!data.count("combo") || !data["combo"].is_string()) - { - return std::string("Missing or wrong json type for `combo`!"); - } - - std::string combo = data["combo"]; + auto combo = wf::ipc::json_get_string(data, "combo"); if (combo.size() < 4) { return std::string("Missing or wrong json type for `combo`!"); @@ -433,19 +432,17 @@ class stipc_plugin_t : public wf::plugin_interface_t return key_t{modifier, key}; } - ipc::method_callback feed_key = [=] (nlohmann::json data) + ipc::method_callback feed_key = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "key", string); - WFJSON_EXPECT_FIELD(data, "state", boolean); - - std::string key = data["key"]; - int keycode = libevdev_event_code_from_name(EV_KEY, key.c_str()); + auto key = wf::ipc::json_get_string(data, "key"); + auto state = wf::ipc::json_get_bool(data, "state"); + int keycode = libevdev_event_code_from_name(EV_KEY, key.c_str()); if (keycode == -1) { return wf::ipc::json_error("Failed to parse evdev key \"" + key + "\""); } - if (data["state"]) + if (state) { input->do_key(keycode, WL_KEYBOARD_KEY_STATE_PRESSED); } else @@ -456,7 +453,7 @@ class stipc_plugin_t : public wf::plugin_interface_t return wf::ipc::json_ok(); }; - ipc::method_callback feed_button = [=] (nlohmann::json data) + ipc::method_callback feed_button = [=] (Json::Value data) { auto result = parse_key(data); auto button = std::get_if(&result); @@ -465,13 +462,7 @@ class stipc_plugin_t : public wf::plugin_interface_t return wf::ipc::json_error(std::get(result)); } - if (!data.count("mode") || !data["mode"].is_string()) - { - return wf::ipc::json_error("No mode specified"); - } - - auto mode = data["mode"]; - + auto mode = wf::ipc::json_get_string(data, "mode"); if ((mode == "press") || (mode == "full")) { if (button->modifier) @@ -494,102 +485,91 @@ class stipc_plugin_t : public wf::plugin_interface_t return wf::ipc::json_ok(); }; - ipc::method_callback move_cursor = [=] (nlohmann::json data) + ipc::method_callback move_cursor = [=] (Json::Value data) { - if (!data.count("x") || !data.count("y") || - !data["x"].is_number() || !data["y"].is_number()) - { - return wf::ipc::json_error("Move cursor needs double x/y arguments"); - } - - double x = data["x"]; - double y = data["y"]; + auto x = wf::ipc::json_get_f64(data, "x"); + auto y = wf::ipc::json_get_f64(data, "y"); input->do_motion(x, y); return wf::ipc::json_ok(); }; - ipc::method_callback do_touch = [=] (nlohmann::json data) + ipc::method_callback do_touch = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "finger", number_integer); - WFJSON_EXPECT_FIELD(data, "x", number); - WFJSON_EXPECT_FIELD(data, "y", number); - - input->do_touch(data["finger"], data["x"], data["y"]); + auto finger = wf::ipc::json_get_int64(data, "finger"); + auto x = wf::ipc::json_get_f64(data, "x"); + auto y = wf::ipc::json_get_f64(data, "y"); + input->do_touch(finger, x, y); return wf::ipc::json_ok(); }; - ipc::method_callback do_touch_release = [=] (nlohmann::json data) + ipc::method_callback do_touch_release = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "finger", number_integer); - input->do_touch_release(data["finger"]); + auto finger = wf::ipc::json_get_int64(data, "finger"); + input->do_touch_release(finger); return wf::ipc::json_ok(); }; - ipc::method_callback run = [=] (nlohmann::json data) + ipc::method_callback run = [=] (Json::Value data) { - if (!data.count("cmd") || !data["cmd"].is_string()) - { - return wf::ipc::json_error("run command needs a cmd to run"); - } - + auto cmd = wf::ipc::json_get_string(data, "cmd"); auto response = wf::ipc::json_ok(); - response["pid"] = wf::get_core().run(data["cmd"]); + response["pid"] = wf::get_core().run(cmd); return response; }; - ipc::method_callback ping = [=] (nlohmann::json data) + ipc::method_callback ping = [=] (Json::Value data) { return wf::ipc::json_ok(); }; - ipc::method_callback get_display = [=] (nlohmann::json data) + ipc::method_callback get_display = [=] (Json::Value data) { - nlohmann::json dpy; + Json::Value dpy; dpy["wayland"] = wf::get_core().wayland_display; dpy["xwayland"] = wf::get_core().get_xwayland_display(); return dpy; }; - ipc::method_callback do_tool_proximity = [=] (nlohmann::json data) + ipc::method_callback do_tool_proximity = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "proximity_in", boolean); - WFJSON_EXPECT_FIELD(data, "x", number); - WFJSON_EXPECT_FIELD(data, "y", number); - input->do_tablet_proximity(data["proximity_in"], data["x"], data["y"]); + auto proximity_in = wf::ipc::json_get_bool(data, "proximity_in"); + auto x = wf::ipc::json_get_f64(data, "x"); + auto y = wf::ipc::json_get_f64(data, "y"); + input->do_tablet_proximity(proximity_in, x, y); return wf::ipc::json_ok(); }; - ipc::method_callback do_tool_button = [=] (nlohmann::json data) + ipc::method_callback do_tool_button = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "button", number_integer); - WFJSON_EXPECT_FIELD(data, "state", boolean); - input->do_tablet_button(data["button"], data["state"]); + auto button = wf::ipc::json_get_int64(data, "button"); + auto state = wf::ipc::json_get_bool(data, "state"); + input->do_tablet_button(button, state); return wf::ipc::json_ok(); }; - ipc::method_callback do_tool_axis = [=] (nlohmann::json data) + ipc::method_callback do_tool_axis = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "x", number); - WFJSON_EXPECT_FIELD(data, "y", number); - WFJSON_EXPECT_FIELD(data, "pressure", number); - input->do_tablet_axis(data["x"], data["y"], data["pressure"]); + auto x = wf::ipc::json_get_f64(data, "x"); + auto y = wf::ipc::json_get_f64(data, "y"); + auto pressure = wf::ipc::json_get_f64(data, "pressure"); + input->do_tablet_axis(x, y, pressure); return wf::ipc::json_ok(); }; - ipc::method_callback do_tool_tip = [=] (nlohmann::json data) + ipc::method_callback do_tool_tip = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "x", number); - WFJSON_EXPECT_FIELD(data, "y", number); - WFJSON_EXPECT_FIELD(data, "state", boolean); - input->do_tablet_tip(data["state"], data["x"], data["y"]); + auto x = wf::ipc::json_get_f64(data, "x"); + auto y = wf::ipc::json_get_f64(data, "y"); + auto state = wf::ipc::json_get_bool(data, "state"); + input->do_tablet_tip(state, x, y); return wf::ipc::json_ok(); }; - ipc::method_callback do_pad_button = [=] (nlohmann::json data) + ipc::method_callback do_pad_button = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "button", number_integer); - WFJSON_EXPECT_FIELD(data, "state", boolean); - input->do_tablet_pad_button(data["button"], data["state"]); + auto button = wf::ipc::json_get_int64(data, "button"); + auto state = wf::ipc::json_get_bool(data, "state"); + input->do_tablet_pad_button(button, state); return wf::ipc::json_ok(); }; @@ -621,7 +601,7 @@ class stipc_plugin_t : public wf::plugin_interface_t } }; - ipc::method_callback delay_next_tx = [=] (nlohmann::json) + ipc::method_callback delay_next_tx = [=] (Json::Value) { if (!on_new_tx.is_connected()) { @@ -632,14 +612,14 @@ class stipc_plugin_t : public wf::plugin_interface_t return wf::ipc::json_ok(); }; - ipc::method_callback get_xwayland_pid = [=] (nlohmann::json) + ipc::method_callback get_xwayland_pid = [=] (Json::Value) { auto response = wf::ipc::json_ok(); response["pid"] = wf::xwayland_get_pid(); return response; }; - ipc::method_callback get_xwayland_display = [=] (nlohmann::json) + ipc::method_callback get_xwayland_display = [=] (Json::Value) { auto response = wf::ipc::json_ok(); response["display"] = wf::xwayland_get_display(); diff --git a/plugins/single_plugins/alpha.cpp b/plugins/single_plugins/alpha.cpp index d859f29f3..ac3e363a2 100644 --- a/plugins/single_plugins/alpha.cpp +++ b/plugins/single_plugins/alpha.cpp @@ -32,7 +32,6 @@ #include "wayfire/plugins/common/shared-core-data.hpp" #include "wayfire/view-helpers.hpp" #include "wayfire/view-transform.hpp" -#include "wayfire/workspace-set.hpp" #include "plugins/ipc/ipc-helpers.hpp" #include "plugins/ipc/ipc-method-repository.hpp" @@ -56,16 +55,16 @@ class wayfire_alpha : public wf::plugin_interface_t ipc_repo->register_method("wf/alpha/get-view-alpha", ipc_get_view_alpha); } - wf::ipc::method_callback ipc_set_view_alpha = [=] (nlohmann::json data) -> nlohmann::json + wf::ipc::method_callback ipc_set_view_alpha = [=] (Json::Value data) -> Json::Value { - WFJSON_EXPECT_FIELD(data, "view-id", number_unsigned); - WFJSON_EXPECT_FIELD(data, "alpha", number); + auto view_id = wf::ipc::json_get_uint64(data, "view-id"); + auto alpha = wf::ipc::json_get_f64(data, "alpha"); - auto view = wf::ipc::find_view_by_id(data["view-id"]); + auto view = wf::ipc::find_view_by_id(view_id); if (view && view->is_mapped()) { auto tr = ensure_transformer(view); - adjust_alpha(view, tr, data["alpha"]); + adjust_alpha(view, tr, alpha); } else { return wf::ipc::json_error("Failed to find view with given id. Maybe it was closed?"); @@ -74,11 +73,10 @@ class wayfire_alpha : public wf::plugin_interface_t return wf::ipc::json_ok(); }; - wf::ipc::method_callback ipc_get_view_alpha = [=] (nlohmann::json data) -> nlohmann::json + wf::ipc::method_callback ipc_get_view_alpha = [=] (Json::Value data) -> Json::Value { - WFJSON_EXPECT_FIELD(data, "view-id", number_unsigned); - - auto view = wf::ipc::find_view_by_id(data["view-id"]); + auto view_id = wf::ipc::json_get_uint64(data, "view-id"); + auto view = wf::ipc::find_view_by_id(view_id); if (!view) { return wf::ipc::json_error("Failed to find view with given id. Maybe it was closed?"); diff --git a/plugins/single_plugins/command.cpp b/plugins/single_plugins/command.cpp index 8fc86d962..ecfd46eee 100644 --- a/plugins/single_plugins/command.cpp +++ b/plugins/single_plugins/command.cpp @@ -1,3 +1,4 @@ +#include "plugins/ipc/ipc-helpers.hpp" #include "wayfire/bindings.hpp" #include "wayfire/plugin.hpp" #include "wayfire/plugins/common/shared-core-data.hpp" @@ -316,34 +317,32 @@ class wayfire_command : public wf::plugin_interface_t } wf::ipc::method_callback_full on_register_binding = - [&] (const nlohmann::json& js, wf::ipc::client_interface_t *client) + [&] (const Json::Value& js, wf::ipc::client_interface_t *client) { - WFJSON_EXPECT_FIELD(js, "binding", string); - WFJSON_OPTIONAL_FIELD(js, "mode", string); - WFJSON_OPTIONAL_FIELD(js, "exec-always", boolean); - WFJSON_OPTIONAL_FIELD(js, "call-method", string); - WFJSON_OPTIONAL_FIELD(js, "command", string); + auto binding_str = wf::ipc::json_get_string(js, "binding"); + auto mode_str = wf::ipc::json_get_optional_string(js, "mode"); + auto exec_always = wf::ipc::json_get_optional_bool(js, "exec-always").value_or(false); + auto call_method = wf::ipc::json_get_optional_string(js, "call-method"); + auto command = wf::ipc::json_get_optional_string(js, "command"); - if (js.contains("call-method") && !js.contains("call-data")) + if (call_method.has_value() && !js.isMember("call-data")) { return wf::ipc::json_error("call-method requires call-data!"); } - auto binding = wf::option_type::from_string(js["binding"]); + auto binding = wf::option_type::from_string(binding_str); if (!binding) { return wf::ipc::json_error("Invalid binding!"); } - bool exec_always = js.contains("exec-always") && js["exec-always"]; - binding_mode mode = BINDING_NORMAL; - if (js.contains("mode")) + if (mode_str.has_value()) { - if (js["mode"] == "release") + if (mode_str == "release") { mode = BINDING_RELEASE; - } else if (js["mode"] == "repeat") + } else if (mode_str == "repeat") { mode = BINDING_REPEAT; } else @@ -359,22 +358,22 @@ class wayfire_command : public wf::plugin_interface_t wf::activator_callback act_callback; bool temporary_binding = false; - if (js.contains("call-method")) + if (call_method.has_value()) { act_callback = [=] (const wf::activator_data_t& data) { return on_binding([js, this] () { - method_repository->call_method(js["call-method"], js["call-data"]); + method_repository->call_method(js["call-method"].asString(), js["call-data"]); }, mode, exec_always, data); }; - } else if (js.contains("command")) + } else if (command.has_value()) { act_callback = [=] (const wf::activator_data_t& data) { return on_binding([js] () { - wf::get_core().run(js["command"]); + wf::get_core().run(js["command"].asString()); }, mode, exec_always, data); }; } else @@ -384,7 +383,7 @@ class wayfire_command : public wf::plugin_interface_t { return on_binding([client, id] () { - nlohmann::json event; + Json::Value event; event["event"] = "command-binding"; event["binding-id"] = id; client->send_json(event); @@ -396,17 +395,17 @@ class wayfire_command : public wf::plugin_interface_t ipc_bindings.back().client = temporary_binding ? client : NULL; wf::get_core().bindings->add_activator(wf::create_option(*binding), &ipc_bindings.back().callback); - nlohmann::json response = wf::ipc::json_ok(); + Json::Value response = wf::ipc::json_ok(); response["binding-id"] = id; return response; }; - wf::ipc::method_callback on_unregister_binding = [&] (const nlohmann::json& js) + wf::ipc::method_callback on_unregister_binding = [&] (const Json::Value& js) { - WFJSON_EXPECT_FIELD(js, "binding-id", number_integer); + auto binding_id = wf::ipc::json_get_uint64(js, "binding-id"); ipc_bindings.remove_if([&] (const ipc_binding_t& binding) { - if (binding_to_id(binding) == js["binding-id"]) + if (binding_to_id(binding) == binding_id) { wf::get_core().bindings->rem_binding((void*)&binding.callback); return true; @@ -432,7 +431,7 @@ class wayfire_command : public wf::plugin_interface_t }); } - wf::ipc::method_callback on_clear_ipc_bindings = [&] (const nlohmann::json& js) + wf::ipc::method_callback on_clear_ipc_bindings = [&] (const Json::Value& js) { clear_ipc_bindings([&] (const ipc_binding_t& binding) { diff --git a/plugins/single_plugins/wsets.cpp b/plugins/single_plugins/wsets.cpp index aa17cba91..0ae73f9cc 100644 --- a/plugins/single_plugins/wsets.cpp +++ b/plugins/single_plugins/wsets.cpp @@ -67,33 +67,32 @@ class wayfire_wsets_plugin_t : public wf::plugin_interface_t std::list send_callback; std::map> available_sets; - wf::ipc::method_callback set_output_wset = [=] (nlohmann::json data) + wf::ipc::method_callback set_output_wset = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "output-id", number_integer); - WFJSON_EXPECT_FIELD(data, "wset-index", number_integer); - - wf::output_t *o = wf::ipc::find_output_by_id(data["output-id"]); + auto output_id = wf::ipc::json_get_int64(data, "output-id"); + auto wset_index = wf::ipc::json_get_int64(data, "wset-index"); + wf::output_t *o = wf::ipc::find_output_by_id(output_id); if (!o) { return wf::ipc::json_error("output not found"); } - select_workspace(data["wset-index"], o); + select_workspace(wset_index, o); return wf::ipc::json_ok(); }; - wf::ipc::method_callback send_view_to_wset = [=] (nlohmann::json data) + wf::ipc::method_callback send_view_to_wset = [=] (Json::Value data) { - WFJSON_EXPECT_FIELD(data, "view-id", number_integer); - WFJSON_EXPECT_FIELD(data, "wset-index", number_integer); + auto view_id = wf::ipc::json_get_int64(data, "view-id"); + auto wset_index = wf::ipc::json_get_int64(data, "wset-index"); - wayfire_toplevel_view view = toplevel_cast(wf::ipc::find_view_by_id(data["view-id"])); + wayfire_toplevel_view view = toplevel_cast(wf::ipc::find_view_by_id(view_id)); if (!view) { return wf::ipc::json_error("view not found"); } - send_window_to(data["wset-index"], view); + send_window_to(wset_index, view); return wf::ipc::json_ok(); }; diff --git a/plugins/tile/tile-ipc.hpp b/plugins/tile/tile-ipc.hpp index 8aedef739..15b719c72 100644 --- a/plugins/tile/tile-ipc.hpp +++ b/plugins/tile/tile-ipc.hpp @@ -22,10 +22,10 @@ struct json_builder_data_t /** * Get a json description of the given tiling tree. */ -inline nlohmann::json tree_to_json(const std::unique_ptr& root, const wf::point_t& offset, +inline Json::Value tree_to_json(const std::unique_ptr& root, const wf::point_t& offset, double rel_size = 1.0) { - nlohmann::json js; + Json::Value js; js["percent"] = rel_size; js["geometry"] = wf::ipc::geometry_to_json(root->geometry - offset); if (auto view = root->as_view_node()) @@ -37,12 +37,12 @@ inline nlohmann::json tree_to_json(const std::unique_ptr& root, con auto split = root->as_split_node(); wf::dassert(split != nullptr, "Expected to be split node"); - nlohmann::json children = nlohmann::json::array(); + Json::Value children = Json::arrayValue; if (split->get_split_direction() == SPLIT_HORIZONTAL) { for (auto& child : split->children) { - children.push_back( + children.append( tree_to_json(child, offset, 1.0 * child->geometry.height / split->geometry.height)); } @@ -51,7 +51,7 @@ inline nlohmann::json tree_to_json(const std::unique_ptr& root, con { for (auto& child : split->children) { - children.push_back(tree_to_json( + children.append(tree_to_json( child, offset, 1.0 * child->geometry.width / split->geometry.width)); } @@ -65,10 +65,10 @@ inline nlohmann::json tree_to_json(const std::unique_ptr& root, con * Go over the json description and verify that it is a valid tiling tree. * @return An error message if the tree is invalid. */ -inline std::optional verify_json_tree(nlohmann::json& json, json_builder_data_t& data, +inline std::optional verify_json_tree(Json::Value& json, json_builder_data_t& data, const wf::dimensions_t& available_geometry) { - if (!json.is_object()) + if (!json.isObject()) { return "JSON Tree structure is wrong!"; } @@ -81,17 +81,17 @@ inline std::optional verify_json_tree(nlohmann::json& json, json_bu json["width"] = available_geometry.width; json["height"] = available_geometry.height; - if (json.count("view-id")) + if (json.isMember("view-id")) { - if (!json["view-id"].is_number_unsigned()) + if (!json["view-id"].isUInt64()) { return "view-id should be unsigned integer!"; } - auto view = toplevel_cast(wf::ipc::find_view_by_id(json["view-id"])); + auto view = toplevel_cast(wf::ipc::find_view_by_id(json["view-id"].asUInt())); if (!view) { - return "No view found with id " + std::to_string((uint32_t)json["view-id"]); + return "No view found with id " + std::to_string((uint32_t)json["view-id"].asUInt()); } if (!view->toplevel()->pending().mapped) @@ -109,8 +109,8 @@ inline std::optional verify_json_tree(nlohmann::json& json, json_bu return {}; } - const bool is_horiz_split = json.count("horizontal-split") && json["horizontal-split"].is_array(); - const bool is_vert_split = json.count("vertical-split") && json["vertical-split"].is_array(); + const bool is_horiz_split = json.isMember("horizontal-split") && json["horizontal-split"].isArray(); + const bool is_vert_split = json.isMember("vertical-split") && json["vertical-split"].isArray(); if (!is_horiz_split && !is_vert_split) { return "Node is neither a view, nor a split node!"; @@ -123,25 +123,25 @@ inline std::optional verify_json_tree(nlohmann::json& json, json_bu for (auto& child : children_list) { - if (!child.count("weight")) + if (!child.isMember("weight")) { return "Expected 'weight' field for each child node!"; } - if (!child["weight"].is_number()) + if (!child["weight"].isDouble()) { return "Expected 'weight' field to be a number!"; } - weight_sum += float(child["weight"]); + weight_sum += float(child["weight"].asDouble()); } int32_t size_sum = 0; for (auto& child : children_list) { - int32_t size = float(child["weight"]) / weight_sum * split_axis; + int32_t size = float(child["weight"].asDouble()) / weight_sum * split_axis; size_sum += size; - if (&child == &children_list.back()) + if (&child == &*std::prev(children_list.end())) { // This is needed because of rounding errors, we always round down, but in the end, we need to // make sure that the nodes cover the whole screen. @@ -163,18 +163,18 @@ inline std::optional verify_json_tree(nlohmann::json& json, json_bu return {}; } -inline std::unique_ptr build_tree_from_json_rec(const nlohmann::json& json, +inline std::unique_ptr build_tree_from_json_rec(const Json::Value& json, tile_workspace_set_data_t *wdata, wf::point_t vp) { std::unique_ptr root; - if (json.count("view-id")) + if (json.isMember("view-id")) { - auto view = toplevel_cast(wf::ipc::find_view_by_id(json["view-id"])); + auto view = toplevel_cast(wf::ipc::find_view_by_id(json["view-id"].asUInt())); root = wdata->setup_view_tiling(view, vp); } else { - const bool is_horiz_split = json.count("horizontal-split"); + const bool is_horiz_split = json.isMember("horizontal-split"); auto& children_list = is_horiz_split ? json["horizontal-split"] : json["vertical-split"]; auto split_parent = std::make_unique( is_horiz_split ? tile::SPLIT_HORIZONTAL : tile::SPLIT_VERTICAL); @@ -190,8 +190,8 @@ inline std::unique_ptr build_tree_from_json_rec(const nlohman root->geometry.x = 0; root->geometry.y = 0; - root->geometry.width = json["width"]; - root->geometry.height = json["height"]; + root->geometry.width = json["width"].asUInt(); + root->geometry.height = json["height"].asUInt(); return root; } @@ -200,7 +200,7 @@ inline std::unique_ptr build_tree_from_json_rec(const nlohman * * Note that the tree description first has to be verified and pre-processed by verify_json_tree(). */ -inline std::unique_ptr build_tree_from_json(const nlohmann::json& json, +inline std::unique_ptr build_tree_from_json(const Json::Value& json, tile_workspace_set_data_t *wdata, wf::point_t vp) { auto root = build_tree_from_json_rec(json, wdata, vp); @@ -215,16 +215,18 @@ inline std::unique_ptr build_tree_from_json(const nlohmann::j return root; } -inline nlohmann::json handle_ipc_get_layout(const nlohmann::json& params) +inline Json::Value handle_ipc_get_layout(const Json::Value& params) { - WFJSON_EXPECT_FIELD(params, "wset-index", number_unsigned); - WFJSON_EXPECT_FIELD(params, "workspace", object); - WFJSON_EXPECT_FIELD(params["workspace"], "x", number_unsigned); - WFJSON_EXPECT_FIELD(params["workspace"], "y", number_unsigned); - - int x = params["workspace"]["x"].get(); - int y = params["workspace"]["y"].get(); - auto ws = ipc::find_workspace_set_by_index(params["wset-index"].get()); + auto wset_index = wf::ipc::json_get_uint64(params, "wset-index"); + + if (!params.isMember("workspace") or !params["workspace"].isObject()) + { + return wf::ipc::json_error("Missing 'workspace' field"); + } + + auto x = wf::ipc::json_get_int64(params["workspace"], "x"); + auto y = wf::ipc::json_get_int64(params["workspace"], "y"); + auto ws = ipc::find_workspace_set_by_index(wset_index); if (ws) { auto grid_size = ws->get_workspace_grid_size(); @@ -247,17 +249,23 @@ inline nlohmann::json handle_ipc_get_layout(const nlohmann::json& params) return wf::ipc::json_error("wset-index not found"); } -inline nlohmann::json handle_ipc_set_layout(nlohmann::json params) +inline Json::Value handle_ipc_set_layout(Json::Value params) { - WFJSON_EXPECT_FIELD(params, "wset-index", number_unsigned); - WFJSON_EXPECT_FIELD(params, "workspace", object); - WFJSON_EXPECT_FIELD(params["workspace"], "x", number_unsigned); - WFJSON_EXPECT_FIELD(params["workspace"], "y", number_unsigned); - WFJSON_EXPECT_FIELD(params, "layout", object); - int x = params["workspace"]["x"].get(); - int y = params["workspace"]["y"].get(); - - auto ws = ipc::find_workspace_set_by_index(params["wset-index"].get()); + auto wset_index = wf::ipc::json_get_uint64(params, "wset-index"); + if (!params.isMember("workspace") or !params["workspace"].isObject()) + { + return wf::ipc::json_error("Missing 'workspace' field"); + } + + auto x = wf::ipc::json_get_int64(params["workspace"], "x"); + auto y = wf::ipc::json_get_int64(params["workspace"], "y"); + + if (!params.isMember("layout") || !params["layout"].isObject()) + { + return wf::ipc::json_error("Missing 'layout' field"); + } + + auto ws = ipc::find_workspace_set_by_index(wset_index); if (!ws) { return wf::ipc::json_error("wset-index not found"); @@ -322,7 +330,8 @@ inline nlohmann::json handle_ipc_set_layout(nlohmann::json params) } // Step 3: set up the new layout - tile_ws.roots[x][y] = build_tree_from_json(params["layout"], &tile_ws, {x, y}); + tile_ws.roots[x][y] = build_tree_from_json(params["layout"], &tile_ws, {static_cast(x), + static_cast(y)}); tile::flatten_tree(tile_ws.roots[x][y]); tile_ws.roots[x][y]->set_gaps(tile_ws.get_gaps()); tile_ws.roots[x][y]->set_geometry(workarea, tx.tx); diff --git a/plugins/tile/tile-plugin.cpp b/plugins/tile/tile-plugin.cpp index 258223d57..f19b5370e 100644 --- a/plugins/tile/tile-plugin.cpp +++ b/plugins/tile/tile-plugin.cpp @@ -505,12 +505,12 @@ class tile_plugin_t : public wf::plugin_interface_t, wf::per_output_tracker_mixi output->erase_data(); } - ipc::method_callback ipc_get_layout = [=] (const nlohmann::json& params) + ipc::method_callback ipc_get_layout = [=] (const Json::Value& params) { return tile::handle_ipc_get_layout(params); }; - ipc::method_callback ipc_set_layout = [=] (nlohmann::json params) -> nlohmann::json + ipc::method_callback ipc_set_layout = [=] (Json::Value params) -> Json::Value { return tile::handle_ipc_set_layout(params); }; diff --git a/plugins/vswitch/vswitch.cpp b/plugins/vswitch/vswitch.cpp index adc4906ef..a2d90ae33 100644 --- a/plugins/vswitch/vswitch.cpp +++ b/plugins/vswitch/vswitch.cpp @@ -558,14 +558,14 @@ class wf_vswitch_global_plugin_t : public wf::per_output_plugin_t ipc_repo->unregister_method("vswitch/set-workspace"); } - wf::ipc::method_callback request_workspace = [=] (const nlohmann::json& data) + wf::ipc::method_callback request_workspace = [=] (const Json::Value& data) { - WFJSON_EXPECT_FIELD(data, "x", number_unsigned); - WFJSON_EXPECT_FIELD(data, "y", number_unsigned); - WFJSON_EXPECT_FIELD(data, "output-id", number_unsigned); - WFJSON_OPTIONAL_FIELD(data, "view-id", number_unsigned); + uint64_t x = wf::ipc::json_get_uint64(data, "x"); + uint64_t y = wf::ipc::json_get_uint64(data, "y"); + uint64_t output_id = wf::ipc::json_get_uint64(data, "output-id"); + std::optional view_id = wf::ipc::json_get_optional_uint64(data, "view-id"); - auto wo = wf::ipc::find_output_by_id(data["output-id"]); + auto wo = wf::ipc::find_output_by_id(output_id); if (!wo) { return wf::ipc::json_error("Invalid output!"); @@ -578,9 +578,9 @@ class wf_vswitch_global_plugin_t : public wf::per_output_plugin_t } wayfire_toplevel_view switch_with_view; - if (data.contains("view-id")) + if (view_id.has_value()) { - auto view = toplevel_cast(wf::ipc::find_view_by_id(data["view-id"])); + auto view = toplevel_cast(wf::ipc::find_view_by_id(view_id.value())); if (!view) { return wf::ipc::json_error("Invalid view or view not toplevel!"); @@ -601,7 +601,7 @@ class wf_vswitch_global_plugin_t : public wf::per_output_plugin_t if (output_instance[wo]->set_capabilities(wf::CAPABILITY_MANAGE_COMPOSITOR)) { - wf::point_t new_viewport = {data["x"], data["y"]}; + wf::point_t new_viewport = {int(x), int(y)}; wf::point_t cur_viewport = wo->wset()->get_current_workspace(); wf::point_t delta = new_viewport - cur_viewport; output_instance[wo]->add_direction(delta, switch_with_view); diff --git a/plugins/wm-actions/wm-actions.cpp b/plugins/wm-actions/wm-actions.cpp index 2e09dd147..6673d5029 100644 --- a/plugins/wm-actions/wm-actions.cpp +++ b/plugins/wm-actions/wm-actions.cpp @@ -421,24 +421,22 @@ class wayfire_wm_actions_t : public wf::plugin_interface_t, ipc_repo->unregister_method("wm-actions/send-to-back"); } - nlohmann::json execute_for_view(const nlohmann::json& params, + Json::Value execute_for_view(const Json::Value& params, std::function view_op) { - WFJSON_EXPECT_FIELD(params, "view_id", number_integer); - WFJSON_EXPECT_FIELD(params, "state", boolean); - - wayfire_toplevel_view view = toplevel_cast(wf::ipc::find_view_by_id(params["view_id"])); + uint64_t view_id = wf::ipc::json_get_uint64(params, "view_id"); + bool state = wf::ipc::json_get_bool(params, "state"); + wayfire_toplevel_view view = toplevel_cast(wf::ipc::find_view_by_id(view_id)); if (!view) { return wf::ipc::json_error("toplevel view id not found!"); } - bool state = params["state"]; view_op(view, state); return wf::ipc::json_ok(); } - wf::ipc::method_callback ipc_minimize = [=] (const nlohmann::json& js) + wf::ipc::method_callback ipc_minimize = [=] (const Json::Value& js) { return execute_for_view(js, [=] (wayfire_toplevel_view view, bool state) { @@ -446,7 +444,7 @@ class wayfire_wm_actions_t : public wf::plugin_interface_t, }); }; - wf::ipc::method_callback ipc_maximize = [=] (const nlohmann::json& js) + wf::ipc::method_callback ipc_maximize = [=] (const Json::Value& js) { return execute_for_view(js, [=] (wayfire_toplevel_view view, bool state) { @@ -454,7 +452,7 @@ class wayfire_wm_actions_t : public wf::plugin_interface_t, }); }; - wf::ipc::method_callback ipc_set_always_on_top = [=] (const nlohmann::json& js) + wf::ipc::method_callback ipc_set_always_on_top = [=] (const Json::Value& js) { return execute_for_view(js, [=] (wayfire_toplevel_view view, bool state) { @@ -468,7 +466,7 @@ class wayfire_wm_actions_t : public wf::plugin_interface_t, }); }; - wf::ipc::method_callback ipc_set_fullscreen = [=] (const nlohmann::json& js) + wf::ipc::method_callback ipc_set_fullscreen = [=] (const Json::Value& js) { return execute_for_view(js, [=] (wayfire_toplevel_view view, bool state) { @@ -476,7 +474,7 @@ class wayfire_wm_actions_t : public wf::plugin_interface_t, }); }; - wf::ipc::method_callback ipc_set_sticky = [=] (const nlohmann::json& js) + wf::ipc::method_callback ipc_set_sticky = [=] (const Json::Value& js) { return execute_for_view(js, [=] (wayfire_toplevel_view view, bool state) { @@ -484,7 +482,7 @@ class wayfire_wm_actions_t : public wf::plugin_interface_t, }); }; - wf::ipc::method_callback ipc_send_to_back = [=] (const nlohmann::json& js) + wf::ipc::method_callback ipc_send_to_back = [=] (const Json::Value& js) { return execute_for_view(js, [=] (wayfire_toplevel_view view, bool state) {