From 91a33fd074af5a54ada4a68942c03de755f6c405 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Fri, 16 Feb 2024 11:03:30 +0100 Subject: [PATCH 1/5] ipc-rules: add ability to select which events to listen for This way we could limit the amount of IPC messages in case a script needs just for ex. view-mapped. --- ipc-scripts/inactive-alpha.py | 11 +++++++---- ipc-scripts/ipc-rules-demo.py | 4 ++-- ipc-scripts/wayfire_socket.py | 4 +++- plugins/ipc/ipc-method-repository.hpp | 3 ++- plugins/single_plugins/ipc-rules.cpp | 27 +++++++++++++++++++++++---- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/ipc-scripts/inactive-alpha.py b/ipc-scripts/inactive-alpha.py index 83f471580..364d1c359 100644 --- a/ipc-scripts/inactive-alpha.py +++ b/ipc-scripts/inactive-alpha.py @@ -7,19 +7,22 @@ addr = os.getenv('WAYFIRE_SOCKET') sock = WayfireSocket(addr) -sock.watch() +sock.watch(['view-focused']) last_focused_toplevel = -1 while True: msg = sock.read_message() # The view-mapped event is emitted when a new window has been opened. - if "event" in msg and msg["event"] == "view-focused": + if "event" in msg: + print(msg["event"]) view = msg["view"] - print(view) new_focus = view["id"] if view and view["type"] == "toplevel" else -1 if last_focused_toplevel != new_focus: if last_focused_toplevel != -1 and new_focus != -1: - sock.set_view_alpha(last_focused_toplevel, 0.8) + try: + sock.set_view_alpha(last_focused_toplevel, 0.8) + except: + print("Last focused toplevel was closed?") if new_focus != -1: sock.set_view_alpha(new_focus, 1.0) diff --git a/ipc-scripts/ipc-rules-demo.py b/ipc-scripts/ipc-rules-demo.py index 7df36641a..78b1bb5de 100644 --- a/ipc-scripts/ipc-rules-demo.py +++ b/ipc-scripts/ipc-rules-demo.py @@ -19,12 +19,12 @@ # We could use the same socket, but this would complicate reading responses, as events and query responses would be mixed with just one socket. events_sock = WayfireSocket(addr) commands_sock = WayfireSocket(addr) -events_sock.watch() +events_sock.watch(['view-mapped']) while True: msg = events_sock.read_message() # The view-mapped event is emitted when a new window has been opened. - if "event" in msg and msg["event"] == "view-mapped": + if "event" in msg: view = msg["view"] if view["app-id"] == "gedit": output_data = commands_sock.query_output(view["output"]) diff --git a/ipc-scripts/wayfire_socket.py b/ipc-scripts/wayfire_socket.py index 918c3fdb1..1c5aa5502 100644 --- a/ipc-scripts/wayfire_socket.py +++ b/ipc-scripts/wayfire_socket.py @@ -50,8 +50,10 @@ def send_json(self, msg): def close(self): self.client.close() - def watch(self): + def watch(self, events = None): message = get_msg_template("window-rules/events/watch") + if events: + message["data"]["events"] = events return self.send_json(message) def query_output(self, output_id: int): diff --git a/plugins/ipc/ipc-method-repository.hpp b/plugins/ipc/ipc-method-repository.hpp index ed7047117..005ad550e 100644 --- a/plugins/ipc/ipc-method-repository.hpp +++ b/plugins/ipc/ipc-method-repository.hpp @@ -140,7 +140,8 @@ inline nlohmann::json json_error(std::string msg) #define WFJSON_OPTIONAL_FIELD(data, field, type) \ if (data.count(field) && !data[field].is_ ## type()) \ { \ - return wf::ipc::json_error("Field \"" field "\" does not have the correct type " #type); \ + return wf::ipc::json_error("Field \"" + std::string(field) + \ + "\" does not have the correct type " #type); \ } } } diff --git a/plugins/single_plugins/ipc-rules.cpp b/plugins/single_plugins/ipc-rules.cpp index b59e65756..08a22f525 100644 --- a/plugins/single_plugins/ipc-rules.cpp +++ b/plugins/single_plugins/ipc-rules.cpp @@ -317,12 +317,28 @@ class ipc_rules_t : public wf::plugin_interface_t, public wf::per_output_tracker wf::shared_data::ref_ptr_t method_repository; // Track a list of clients which have requested watch - std::set clients; + std::map> clients; wf::ipc::method_callback_full on_client_watch = [=] (nlohmann::json data, wf::ipc::client_interface_t *client) { - clients.insert(client); + static constexpr const char *EVENTS = "events"; + WFJSON_OPTIONAL_FIELD(data, EVENTS, array); + std::set subscribed_to; + if (data.contains(EVENTS)) + { + for (auto& sub : data[EVENTS]) + { + if (!sub.is_string()) + { + return wf::ipc::json_error("Event list contains non-string entries!"); + } + + subscribed_to.insert((std::string)sub); + } + } + + clients[client] = subscribed_to; return wf::ipc::json_ok(); }; @@ -337,9 +353,12 @@ class ipc_rules_t : public wf::plugin_interface_t, public wf::per_output_tracker nlohmann::json event; event["event"] = event_name; event["view"] = view_to_json(view); - for (auto& client : clients) + for (auto& [client, events] : clients) { - client->send_json(event); + if (events.empty() || events.count(event_name)) + { + client->send_json(event); + } } } From 849b4a46ef8b2bc5f0dd5bdad9fd559e4cc3fb33 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Fri, 16 Feb 2024 11:13:28 +0100 Subject: [PATCH 2/5] view: emit title/app-id-changed on core as well --- src/api/wayfire/signal-definitions.hpp | 4 ++-- src/view/view-impl.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/wayfire/signal-definitions.hpp b/src/api/wayfire/signal-definitions.hpp index 2daaed8d7..48897df55 100644 --- a/src/api/wayfire/signal-definitions.hpp +++ b/src/api/wayfire/signal-definitions.hpp @@ -579,7 +579,7 @@ struct view_set_sticky_signal }; /** - * on: view + * on: view, core * when: After the view's title has changed. */ struct view_title_changed_signal @@ -588,7 +588,7 @@ struct view_title_changed_signal }; /** - * on: view + * on: view, core * when: After the view's app-id has changed. */ struct view_app_id_changed_signal diff --git a/src/view/view-impl.cpp b/src/view/view-impl.cpp index 578fc1eca..a5974ce96 100644 --- a/src/view/view-impl.cpp +++ b/src/view/view-impl.cpp @@ -93,6 +93,7 @@ void wf::view_implementation::emit_title_changed_signal(wayfire_view view) view_title_changed_signal data; data.view = view; view->emit(&data); + wf::get_core().emit(&data); } void wf::view_implementation::emit_app_id_changed_signal(wayfire_view view) @@ -100,6 +101,7 @@ void wf::view_implementation::emit_app_id_changed_signal(wayfire_view view) view_app_id_changed_signal data; data.view = view; view->emit(&data); + wf::get_core().emit(&data); } void wf::view_implementation::emit_toplevel_state_change_signals(wayfire_toplevel_view view, From 5b75e8e9a46e154ded65361d493c7358def72a6f Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Fri, 16 Feb 2024 11:13:44 +0100 Subject: [PATCH 3/5] ipc-rules: emit view-{title,app-id}-changed to subscribed clients --- plugins/single_plugins/ipc-rules.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/single_plugins/ipc-rules.cpp b/plugins/single_plugins/ipc-rules.cpp index 08a22f525..5f21a2018 100644 --- a/plugins/single_plugins/ipc-rules.cpp +++ b/plugins/single_plugins/ipc-rules.cpp @@ -142,6 +142,8 @@ class ipc_rules_t : public wf::plugin_interface_t, public wf::per_output_tracker wf::get_core().connect(&on_view_mapped); wf::get_core().connect(&on_view_unmapped); wf::get_core().connect(&on_kbfocus_changed); + wf::get_core().connect(&on_title_changed); + wf::get_core().connect(&on_app_id_changed); init_output_tracking(); } @@ -396,6 +398,18 @@ class ipc_rules_t : public wf::plugin_interface_t, public wf::per_output_tracker send_view_to_subscribes(ev->view, "view-fullscreen"); }; + wf::signal::connection_t on_title_changed = + [=] (wf::view_title_changed_signal *ev) + { + send_view_to_subscribes(ev->view, "view-title-changed"); + }; + + wf::signal::connection_t on_app_id_changed = + [=] (wf::view_app_id_changed_signal *ev) + { + send_view_to_subscribes(ev->view, "view-app-id-changed"); + }; + std::string get_view_type(wayfire_view view) { if (view->role == wf::VIEW_ROLE_TOPLEVEL) @@ -523,7 +537,7 @@ class ipc_rules_t : public wf::plugin_interface_t, public wf::per_output_tracker wl_client_get_credentials(view->get_client(), &pid, 0, 0); } - return pid; + return pid; // NOLINT } }; From ce738437b066cdfc8489f137b04a58c977c7530f Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Fri, 16 Feb 2024 11:57:44 +0100 Subject: [PATCH 4/5] meson: use vcs_tag for git version information This way, the command is run every time we change the Wayfire version and not only when meson reconfigures itself. --- meson.build | 21 ++++----------------- src/api/wayfire/debug.hpp | 10 ++++++++++ src/main.cpp | 7 ++----- src/meson.build | 18 +++++++++++++++++- src/version/git-branch.cpp.in | 9 +++++++++ src/version/git-commit.cpp.in | 9 +++++++++ 6 files changed, 51 insertions(+), 23 deletions(-) create mode 100644 src/version/git-branch.cpp.in create mode 100644 src/version/git-commit.cpp.in diff --git a/meson.build b/meson.build index 7fe7a870f..914a6f53e 100644 --- a/meson.build +++ b/meson.build @@ -4,7 +4,7 @@ project( 'cpp', version: '0.9.0', license: 'MIT', - meson_version: '>=0.56.0', + meson_version: '>=0.63.0', default_options: [ 'cpp_std=c++17', 'c_std=c11', @@ -13,6 +13,9 @@ project( ], ) +version = '"@0@"'.format(meson.project_version()) +add_project_arguments('-DWAYFIRE_VERSION=@0@'.format(version), language: 'cpp') + wayfire_api_inc = include_directories('src/api') wayland_server = dependency('wayland-server') @@ -83,22 +86,6 @@ backtrace = meson.get_compiler('cpp').find_library('execinfo', required: false) conf_data = configuration_data() -version = '"@0@"'.format(meson.project_version()) -git = find_program('git', native: true, required: false) -if git.found() - git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'], check: false) - git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false) - if git_commit.returncode() == 0 and git_branch.returncode() == 0 - version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format( - meson.project_version(), - git_commit.stdout().strip(), - git_branch.stdout().strip(), - ) - endif -endif -add_project_arguments('-DWAYFIRE_VERSION=@0@'.format(version), language: 'cpp') -conf_data.set('WAYFIRE_VERSION', '-DWAYFIRE_VERSION=@0@'.format(version)) - conf_data.set('INSTALL_PREFIX', get_option('prefix')) conf_data.set('PLUGIN_PATH', join_paths(get_option('prefix'), get_option('libdir'), 'wayfire')) metadata_dir_suffix = 'share/wayfire/metadata' diff --git a/src/api/wayfire/debug.hpp b/src/api/wayfire/debug.hpp index 7b1d347b6..6843c35e6 100644 --- a/src/api/wayfire/debug.hpp +++ b/src/api/wayfire/debug.hpp @@ -19,6 +19,16 @@ namespace wf */ void dump_scene(scene::node_ptr root = wf::get_core().scene()); +/** + * Information about the version that Wayfire was built with. + * Made available at runtime. + */ +namespace version +{ +extern std::string git_commit; +extern std::string git_branch; +} + namespace log { /** diff --git a/src/main.cpp b/src/main.cpp index bfec5cf63..99ef70510 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,25 +3,22 @@ #include #include #include -#include #include -#include #include #include #include "main.hpp" -#include "wayfire/nonstd/safe-list.hpp" #include #include "wayfire/config-backend.hpp" #include "core/plugin-loader.hpp" #include "core/core-impl.hpp" -#include "wayfire/output.hpp" static void print_version() { - std::cout << WAYFIRE_VERSION << std::endl; + std::cout << WAYFIRE_VERSION << "-" << wf::version::git_commit << + " (" __DATE__ ") branch " << wf::version::git_branch << std::endl; exit(0); } diff --git a/src/meson.build b/src/meson.build index 7f37cdeed..cef012fb5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -90,6 +90,22 @@ if print_trace debug_arguments += ['-DPRINT_TRACE'] endif +# Generate information about Wayfire version +git = find_program('git', native: true, required: false) +git_commit_info = vcs_tag( + input: 'version/git-commit.cpp.in', + output: 'git-commit.cpp', + replace_string: '@GIT_COMMIT@', + command: git.found() ? [git, 'rev-parse', '--short', 'HEAD'] : ['echo', 'unknown'], + fallback: 'unknown') + +git_branch_info = vcs_tag( + input: 'version/git-branch.cpp.in', + output: 'git-branch.cpp', + replace_string: '@GIT_BRANCH@', + command: git.found() ? [git, 'rev-parse', '--abbrev-ref', 'HEAD'] : ['echo', 'unknown'], + fallback: 'unknown') + # First build a static library of all sources, so that it can be reused # in tests libwayfire_sta = static_library('libwayfire', wayfire_sources, @@ -105,7 +121,7 @@ libwayfire = declare_dependency(link_whole: libwayfire_sta, tests_include_dirs = include_directories('.') # Generate main executable -executable('wayfire', ['main.cpp'], +executable('wayfire', ['main.cpp', git_commit_info, git_branch_info], dependencies: libwayfire, install: true, cpp_args: debug_arguments) diff --git a/src/version/git-branch.cpp.in b/src/version/git-branch.cpp.in new file mode 100644 index 000000000..c920b0c3b --- /dev/null +++ b/src/version/git-branch.cpp.in @@ -0,0 +1,9 @@ +#include + +namespace wf +{ +namespace version +{ +std::string git_branch = "@GIT_BRANCH@"; +} +} diff --git a/src/version/git-commit.cpp.in b/src/version/git-commit.cpp.in new file mode 100644 index 000000000..b83400e17 --- /dev/null +++ b/src/version/git-commit.cpp.in @@ -0,0 +1,9 @@ +#include + +namespace wf +{ +namespace version +{ +std::string git_commit = "@GIT_COMMIT@"; +} +} From 468c5dde055b004107ecae982d5c60408f550ee1 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Fri, 16 Feb 2024 12:05:03 +0100 Subject: [PATCH 5/5] ipc-rules: add wayfire/configuration method Returns information about the current Wayfire instance. --- ipc-scripts/list-methods.py | 5 +++++ plugins/single_plugins/ipc-rules.cpp | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/ipc-scripts/list-methods.py b/ipc-scripts/list-methods.py index 01454728d..1d7f3d7ad 100644 --- a/ipc-scripts/list-methods.py +++ b/ipc-scripts/list-methods.py @@ -5,6 +5,11 @@ addr = os.getenv('WAYFIRE_SOCKET') sock = ws.WayfireSocket(addr) +query = ws.get_msg_template('wayfire/configuration') +response = sock.send_json(query) +print("Wayfire version:") +print(json.dumps(response, indent=4)) + query = ws.get_msg_template('list-methods') response = sock.send_json(query) print("Supported methods:") diff --git a/plugins/single_plugins/ipc-rules.cpp b/plugins/single_plugins/ipc-rules.cpp index 5f21a2018..0907ed68a 100644 --- a/plugins/single_plugins/ipc-rules.cpp +++ b/plugins/single_plugins/ipc-rules.cpp @@ -19,6 +19,7 @@ #include "wayfire/window-manager.hpp" #include "wayfire/workarea.hpp" #include "config.h" +#include #include @@ -128,6 +129,7 @@ class ipc_rules_t : public wf::plugin_interface_t, public wf::per_output_tracker public: void init() override { + method_repository->register_method("wayfire/configuration", get_wayfire_configuration_info); method_repository->register_method("input/list-devices", list_input_devices); method_repository->register_method("input/configure-device", configure_input_device); method_repository->register_method("window-rules/events/watch", on_client_watch); @@ -149,6 +151,7 @@ class ipc_rules_t : public wf::plugin_interface_t, public wf::per_output_tracker void fini() override { + method_repository->unregister_method("wayfire/configuration"); method_repository->unregister_method("input/list-devices"); method_repository->unregister_method("input/configure-device"); method_repository->unregister_method("window-rules/events/watch"); @@ -174,6 +177,20 @@ class ipc_rules_t : public wf::plugin_interface_t, public wf::per_output_tracker // no-op } + wf::ipc::method_callback get_wayfire_configuration_info = [=] (nlohmann::json) + { + nlohmann::json response; + + response["api-version"] = WAYFIRE_API_ABI_VERSION; + response["plugin-path"] = PLUGIN_PATH; + response["plugin-xml-dir"] = PLUGIN_XML_DIR; + response["xwayland-support"] = WF_HAS_XWAYLAND; + + response["build-commit"] = wf::version::git_commit; + response["build-branch"] = wf::version::git_branch; + return response; + }; + wf::ipc::method_callback list_views = [=] (nlohmann::json) { auto response = nlohmann::json::array();