From 9f38b095a41d4d0b2d4f6ca6482be4ddd0dd4fda Mon Sep 17 00:00:00 2001 From: Matthew Kosarek Date: Wed, 21 Aug 2024 19:31:02 -0400 Subject: [PATCH] feature: adding the skeleton of support for the sway input command via IPC (#212) --- src/i3_command.cpp | 7 ++-- src/i3_command.h | 3 +- src/i3_command_executor.cpp | 64 ++++++++++++++++++++++++++++++++++++- src/i3_command_executor.h | 1 + src/policy.cpp | 2 +- src/string_extensions.h | 31 ++++++++++++++++++ 6 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 src/string_extensions.h diff --git a/src/i3_command.cpp b/src/i3_command.cpp index c7d8e2a..f7748e3 100644 --- a/src/i3_command.cpp +++ b/src/i3_command.cpp @@ -19,6 +19,7 @@ along with this program. If not, see . #include "jpcre2.h" #include "window_controller.h" #include "window_helpers.h" +#include "string_extensions.h" #include #include @@ -215,7 +216,7 @@ std::vector I3ScopedCommandList::parse(std::string_view con I3Command next_command = { I3CommandType::none }; // Next, we can now read the command tokens space-by-space - for (auto const& command_token : ((command_view) | std::ranges::views::split(' '))) + for (auto const& command_token : ((trim_left(command_view)) | std::ranges::views::split(' '))) { if (next_command.type == I3CommandType::none) { @@ -261,6 +262,8 @@ std::vector I3ScopedCommandList::parse(std::string_view con next_command.type = I3CommandType::i3_bar; else if (equals(command_token.data(), "gaps")) next_command.type = I3CommandType::gaps; + else if (equals(command_token.data(), "input")) + next_command.type = I3CommandType::input; else { mir::log_error("Invalid i3 command type: %s", command_token.data()); @@ -281,4 +284,4 @@ std::vector I3ScopedCommandList::parse(std::string_view con } return list; -} \ No newline at end of file +} diff --git a/src/i3_command.h b/src/i3_command.h index d6fc3b3..1df1520 100644 --- a/src/i3_command.h +++ b/src/i3_command.h @@ -51,7 +51,8 @@ enum class I3CommandType scratchpad, nop, i3_bar, - gaps + gaps, + input }; enum class I3ScopeType diff --git a/src/i3_command_executor.cpp b/src/i3_command_executor.cpp index 78cd5d4..6f60005 100644 --- a/src/i3_command_executor.cpp +++ b/src/i3_command_executor.cpp @@ -69,6 +69,9 @@ void I3CommandExecutor::process(miracle::I3ScopedCommandList const& command_list case I3CommandType::exit: policy.quit(); break; + case I3CommandType::input: + process_input(command, command_list); + break; default: break; } @@ -429,4 +432,63 @@ void I3CommandExecutor::process_sticky(I3Command const& command, I3ScopedCommand policy.toggle_pinned_to_workspace(); else mir::log_warning("process_sticky: unknown arguments: %s", arg0.c_str()); -} \ No newline at end of file +} + +// This command will be +void I3CommandExecutor::process_input(I3Command const& command, I3ScopedCommandList const& command_list) +{ + // Payloads appear in the following format: + // [type:X, xkb_Y, Z] + // where X is something like "keyboard", Y is the variable that we want to change + // and Z is the value of that variable. Z may not be included at all, in which + // case the variable is set to the default. + if (command.arguments.size() < 2) + { + mir::log_warning("process_input: expects at least 2 arguments"); + return; + } + + const char* const TYPE_PREFIX = "type:"; + const size_t TYPE_PREFIX_LEN = strlen(TYPE_PREFIX); + std::string_view type_str = command.arguments[0]; + if (!type_str.starts_with("type:")) + { + mir::log_warning("process_input: 'type' string is misformatted: %s", command.arguments[0].c_str()); + return; + } + + std::string_view type = type_str.substr(TYPE_PREFIX_LEN); + assert(type == "keyboard"); + + std::string_view xkb_str = command.arguments[1]; + const char* const XKB_PREFIX = "xkb_"; + const size_t XKB_PREFIX_LEN = strlen(XKB_PREFIX); + if (!xkb_str.starts_with(XKB_PREFIX)) + { + mir::log_warning("process_input: 'xkb' string is misformatted: %s", command.arguments[1].c_str()); + return; + } + + std::string_view xkb_variable_name = xkb_str.substr(XKB_PREFIX_LEN); + assert(xkb_variable_name == "model" + || xkb_variable_name == "layout" + || xkb_variable_name == "variant" + || xkb_variable_name == "options"); + + mir::log_info("Processing input from locale1: type=%s, xkb_variable=%s", type.data(), xkb_variable_name.data()); + + // TODO: This is where we need to process the request + if (command.arguments.size() == 3) + { + + } + else if (command.arguments.size() < 3) + { + // TODO: Set to the default + } + else + { + mir::log_warning("process_input: > 3 arguments were provided but only <= 3 are expected"); + return; + } +} diff --git a/src/i3_command_executor.h b/src/i3_command_executor.h index c0707a0..9819f49 100644 --- a/src/i3_command_executor.h +++ b/src/i3_command_executor.h @@ -55,6 +55,7 @@ private: void process_focus(I3Command const&, I3ScopedCommandList const&); void process_move(I3Command const&, I3ScopedCommandList const&); void process_sticky(I3Command const&, I3ScopedCommandList const&); + void process_input(I3Command const&, I3ScopedCommandList const&); }; } // miracle diff --git a/src/policy.cpp b/src/policy.cpp index fba1814..46450ed 100644 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -265,7 +265,7 @@ bool Policy::handle_pointer_event(MirPointerEvent const* event) } } - if (state.has_clicked_floating_window || state.active->get_type() == ContainerType::floating_window) + if (state.has_clicked_floating_window || (state.active && state.active->get_type() == ContainerType::floating_window)) { if (action == mir_pointer_action_button_down) state.has_clicked_floating_window = true; diff --git a/src/string_extensions.h b/src/string_extensions.h new file mode 100644 index 0000000..8f9cd6d --- /dev/null +++ b/src/string_extensions.h @@ -0,0 +1,31 @@ +/** +Copyright (C) 2024 Matthew Kosarek + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +**/ + +#ifndef MIRACLE_WM_STRING_EXTENSIONS_H +#define MIRACLE_WM_STRING_EXTENSIONS_H + +#include + +template +std::string_view trim_left (T const & data) +{ + std::string_view sv{data}; + sv.remove_prefix( std::min(sv.find_first_not_of(' '), sv.size())); + return sv; +} + +#endif //MIRACLE_WM_STRING_EXTENSIONS_H