From cb50196482f41e4173ca02d8e7d862519f97acba Mon Sep 17 00:00:00 2001 From: mattkae Date: Sun, 19 Feb 2023 12:57:46 -0500 Subject: [PATCH] I have something functionng, time to dissect! --- CMakeLists.txt | 2 +- NOTES.md | 16 +- run.sh | 3 +- src/FloatingWindowManager.cpp | 604 +++++++++++++++++++++++++++++++++- src/FloatingWindowManager.hpp | 129 ++++++-- src/main.cpp | 35 +- 6 files changed, 718 insertions(+), 71 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8c17ca..e277d8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ find_package(PkgConfig) pkg_check_modules(MIRAL miral REQUIRED) find_package(OpenGL REQUIRED) -add_executable(compositor src/main.cpp) +add_executable(compositor src/main.cpp src/FloatingWindowManager.cpp) target_include_directories(compositor PUBLIC SYSTEM ${MIRAL_INCLUDE_DIRS}) target_link_libraries( compositor ${MIRAL_LDFLAGS}) \ No newline at end of file diff --git a/NOTES.md b/NOTES.md index ad1b088..ca24da1 100644 --- a/NOTES.md +++ b/NOTES.md @@ -2,22 +2,18 @@ The following file will serve the purpose of documenting my thought processes and progress as I complete the assignment. I am starting this project on February 18, 2023. ## Step 1: Setting up the miral app -At first, I went the virtual box route, but then I saw how easy it would be to do this locally, so I opted for that instead. On Arch, I did: -```sh -git clone https://aur.archlinux.org/mir.git -cd mir -makepkg -si -``` - -and voila. It lives! +.. TODO ## Step 2: Hacking ### Research I will begin my searching for documentation on how I made write a Mir-based compositor: -1. https://mir-server.io/docs/developing-a-wayland-compositor-using-mir This seems like a good match! +1. https://mir-server.io/docs/developing-a-wayland-compositor-using-mir This seems like a good match. +2. I will also look extensively at the `miral-app` demo to see how it is starting the miral server. The `miral-shell` looks like the easiest barebone candidate for me to follow. -### +### Programming +1. I started off by implementing the simple miral-terminal example, however I am runnning into an issue where the `ExternalClientLauncher` is claiming that the server has not yet been set. +2. My task is to build a compositor, so I will first define what is that I need in my compositor. As an MVP, I would like to support: - Window transparency - Drop shadows diff --git a/run.sh b/run.sh index 036ba1b..42cc59e 100755 --- a/run.sh +++ b/run.sh @@ -8,5 +8,6 @@ if [ -O "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" ] then unset WAYLAND_DISPLAY fi -# miral-shell can launch it's own terminal with Ctrl-Alt-T + +echo $bindir MIR_SERVER_ENABLE_X11=1 MIR_SERVER_SHELL_TERMINAL_EMULATOR=${terminal} exec ${bindir}${miral_server} $* \ No newline at end of file diff --git a/src/FloatingWindowManager.cpp b/src/FloatingWindowManager.cpp index 72048f6..2f74e4d 100644 --- a/src/FloatingWindowManager.cpp +++ b/src/FloatingWindowManager.cpp @@ -1,29 +1,601 @@ +/* + * Copyright © Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 or 3 as + * published by the Free Software Foundation. + * + * 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 . + */ + #include "FloatingWindowManager.hpp" -#include -const int title_bar_height = 16; +#include +#include +#include +#include +#include +#include -FloatingWindowManager::FloatingWindowManager(const miral::WindowManagerTools& tools) { +#include +#include +using namespace miral; +using namespace miral::toolkit; + +namespace +{ +DeltaY const title_bar_height{12}; + +struct PolicyData +{ + bool in_hidden_workspace{false}; + + MirWindowState old_state; +}; + +inline PolicyData& policy_data_for(WindowInfo const& info) +{ + return *std::static_pointer_cast(info.userdata()); +} } -miral::WindowSpecification FloatingWindowManager::place_new_window( - miral::ApplicationInfo const& app_info, - miral::WindowSpecification const& requested_specification) +FloatingWindowManagerPolicy::FloatingWindowManagerPolicy( + WindowManagerTools const& tools, + miral::InternalClientLauncher const& launcher, + std::function& shutdown_hook) : + MinimalWindowManager(tools) { - auto parameters = miral::MinimalWindowManager::place_new_window(app_info, requested_specification); + shutdown_hook = [this] { }; - // if (app_info.application() == miral::decoration_provider->session()) - // { - // parameters.type() = mir_window_type_decoration; - // parameters.depth_layer() = mir_depth_layer_background; - // } + for (auto key : {KEY_F1, KEY_F2, KEY_F3, KEY_F4}) + key_to_workspace[key] = this->tools.create_workspace(); - bool const needs_titlebar = miral::WindowInfo::needs_titlebar(parameters.type().value()); + active_workspace = key_to_workspace[KEY_F1]; +} + +FloatingWindowManagerPolicy::~FloatingWindowManagerPolicy() = default; + +bool FloatingWindowManagerPolicy::handle_pointer_event(MirPointerEvent const* event) +{ + if (MinimalWindowManager::handle_pointer_event(event)) + return true; + + auto const action = mir_pointer_event_action(event); + auto const modifiers = mir_pointer_event_modifiers(event) & modifier_mask; + Point const cursor{ + mir_pointer_event_axis_value(event, mir_pointer_axis_x), + mir_pointer_event_axis_value(event, mir_pointer_axis_y)}; + + bool consumes_event = false; + + if (action == mir_pointer_action_button_down) + { + if (auto const window = tools.window_at(cursor)) + tools.select_active_window(window); + + if (auto const window = tools.active_window()) + { + if (mir_pointer_event_button_state(event, mir_pointer_button_tertiary)) + { + if (modifiers == mir_input_event_modifier_alt) + { + Rectangle const old_pos{window.top_left(), window.size()}; + + auto anchor = old_pos.bottom_right(); + auto edge = mir_resize_edge_northwest; + + struct Corner { Point point; MirResizeEdge edge; }; + + for (auto const& corner : { + Corner{old_pos.top_right(), mir_resize_edge_southwest}, + Corner{old_pos.bottom_left(), mir_resize_edge_northeast}, + Corner{old_pos.top_left, mir_resize_edge_southeast}}) + { + if ((cursor - anchor).length_squared() < + (cursor - corner.point).length_squared()) + { + anchor = corner.point; + edge = corner.edge; + } + } + + begin_pointer_resize(tools.info_for(window), mir_pointer_event_input_event(event), edge); + consumes_event = true; + } + } + } + } + + return consumes_event; +} + +bool FloatingWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event) +{ + auto const count = mir_touch_event_point_count(event); + + if (MinimalWindowManager::handle_touch_event(event) || count != 3) + { + pinching = false; + return false; + } + + for (auto i = 0U; i != count; ++i) + { + switch (mir_touch_event_action(event, i)) + { + case mir_touch_action_up: + case mir_touch_action_down: + pinching = false; + return false; + + default: + continue; + } + } + + int touch_pinch_top = std::numeric_limits::max(); + int touch_pinch_left = std::numeric_limits::max(); + int touch_pinch_width = 0; + int touch_pinch_height = 0; + + for (auto i = 0U; i != count; ++i) + { + for (auto j = 0U; j != i; ++j) + { + int dx = mir_touch_event_axis_value(event, i, mir_touch_axis_x) - + mir_touch_event_axis_value(event, j, mir_touch_axis_x); + + int dy = mir_touch_event_axis_value(event, i, mir_touch_axis_y) - + mir_touch_event_axis_value(event, j, mir_touch_axis_y); + + if (touch_pinch_width < dx) + touch_pinch_width = dx; + + if (touch_pinch_height < dy) + touch_pinch_height = dy; + } + + int const x = mir_touch_event_axis_value(event, i, mir_touch_axis_x); + + int const y = mir_touch_event_axis_value(event, i, mir_touch_axis_y); + + if (touch_pinch_top > y) + touch_pinch_top = y; + + if (touch_pinch_left > x) + touch_pinch_left = x; + } + + if (auto window = tools.active_window()) + { + auto const old_size = window.size(); + auto const delta_width = DeltaX{touch_pinch_width - old_touch_pinch_width}; + auto const delta_height = DeltaY{touch_pinch_height - old_touch_pinch_height}; + + auto new_width = std::max(old_size.width + delta_width, Width{5}); + auto new_height = std::max(old_size.height + delta_height, Height{5}); + Displacement movement{ + DeltaX{touch_pinch_left - old_touch_pinch_left}, + DeltaY{touch_pinch_top - old_touch_pinch_top}}; + + auto& window_info = tools.info_for(window); + keep_window_within_constraints(window_info, movement, new_width, new_height); + + auto new_pos = window.top_left() + movement; + Size new_size{new_width, new_height}; + + { // Workaround for lp:1627697 + auto now = std::chrono::steady_clock::now(); + if (pinching && now < last_resize+std::chrono::milliseconds(20)) + return true; + + last_resize = now; + } + + if (pinching) + { + WindowSpecification modifications; + modifications.top_left() = new_pos; + modifications.size() = new_size; + tools.modify_window(window_info, modifications); + } + else + { + pinching = true; + } + + old_touch_pinch_top = touch_pinch_top; + old_touch_pinch_left = touch_pinch_left; + old_touch_pinch_width = touch_pinch_width; + old_touch_pinch_height = touch_pinch_height; + } + + return true; +} + +void FloatingWindowManagerPolicy::advise_new_window(WindowInfo const& window_info) +{ + MinimalWindowManager::advise_new_window(window_info); + + auto const parent = window_info.parent(); + + if (!parent) + tools.add_tree_to_workspace(window_info.window(), active_workspace); + else + { + if (policy_data_for(tools.info_for(parent)).in_hidden_workspace) + apply_workspace_hidden_to(window_info.window()); + } +} + +void FloatingWindowManagerPolicy::handle_window_ready(WindowInfo& window_info) +{ + MinimalWindowManager::handle_window_ready(window_info); +} + +void FloatingWindowManagerPolicy::advise_focus_gained(WindowInfo const& info) +{ + MinimalWindowManager::advise_focus_gained(info); +} + +bool FloatingWindowManagerPolicy::handle_keyboard_event(MirKeyboardEvent const* event) +{ + if (MinimalWindowManager::handle_keyboard_event(event)) + return true; + + auto const action = mir_keyboard_event_action(event); + auto const scan_code = mir_keyboard_event_scan_code(event); + auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask; + + // Switch workspaces + if (action == mir_keyboard_action_down && + modifiers == (mir_input_event_modifier_alt | mir_input_event_modifier_meta)) + { + auto const found = key_to_workspace.find(scan_code); + + if (found != key_to_workspace.end()) + { + switch_workspace_to(found->second); + return true; + } + } + + // Switch workspace taking the active window + if (action == mir_keyboard_action_down && + modifiers == (mir_input_event_modifier_ctrl | mir_input_event_modifier_meta)) + { + auto const found = key_to_workspace.find(scan_code); + + if (found != key_to_workspace.end()) + { + switch_workspace_to(found->second, tools.active_window()); + return true; + } + } + + if (action == mir_keyboard_action_down && scan_code == KEY_F11) + { + switch (modifiers) + { + case mir_input_event_modifier_alt: + toggle(mir_window_state_maximized); + return true; + + case mir_input_event_modifier_shift: + toggle(mir_window_state_vertmaximized); + return true; + + case mir_input_event_modifier_ctrl: + toggle(mir_window_state_horizmaximized); + return true; + + case mir_input_event_modifier_meta: + toggle(mir_window_state_fullscreen); + return true; + + default: + break; + } + } + else if (action == mir_keyboard_action_down && scan_code == KEY_F4 && + modifiers == (mir_input_event_modifier_alt|mir_input_event_modifier_shift)) + { + if (auto const& window = tools.active_window()) + kill(window.application(), SIGTERM); + return true; + } + else if (action == mir_keyboard_action_down && + modifiers == (mir_input_event_modifier_ctrl|mir_input_event_modifier_meta)) + { + if (auto active_window = tools.active_window()) + { + auto active_zone = tools.active_application_zone().extents(); + auto& window_info = tools.info_for(active_window); + WindowSpecification modifications; + + switch (scan_code) + { + case KEY_LEFT: + modifications.state() = mir_window_state_vertmaximized; + tools.place_and_size_for_state(modifications, window_info); + modifications.top_left() = window_info.needs_titlebar(window_info.type()) ? + active_zone.top_left + title_bar_height : + active_zone.top_left; + break; + + case KEY_RIGHT: + { + modifications.state() = mir_window_state_vertmaximized; + tools.place_and_size_for_state(modifications, window_info); + + auto const new_width = + (modifications.size().is_set() ? modifications.size().value() : active_window.size()).width; + + modifications.top_left() = window_info.needs_titlebar(window_info.type()) ? + active_zone.top_right() - Displacement{as_delta(new_width), 0} + title_bar_height : + active_zone.top_right() - Displacement{as_delta(new_width), 0}; + break; + } + + case KEY_UP: + modifications.state() = mir_window_state_horizmaximized; + tools.place_and_size_for_state(modifications, window_info); + modifications.top_left() = window_info.needs_titlebar(window_info.type()) ? + active_zone.top_left + title_bar_height : + active_zone.top_left; + break; + + case KEY_DOWN: + modifications.state() = mir_window_state_horizmaximized; + tools.place_and_size_for_state(modifications, window_info); + modifications.top_left() = + active_zone.bottom_right() - as_displacement( + modifications.size().is_set() ? modifications.size().value() : active_window.size()); + break; + + default: + return false; + } + + tools.modify_window(window_info, modifications); + return true; + } + } + + return false; +} + +void FloatingWindowManagerPolicy::toggle(MirWindowState state) +{ + if (auto const window = tools.active_window()) + { + auto& info = tools.info_for(window); + + WindowSpecification modifications; + + modifications.state() = (info.state() == state) ? mir_window_state_restored : state; + tools.place_and_size_for_state(modifications, info); + tools.modify_window(info, modifications); + } +} + +void FloatingWindowManagerPolicy::keep_window_within_constraints( + WindowInfo const& window_info, Displacement& movement, Width& new_width, Height& new_height) const +{ + switch (window_info.state()) + { + case mir_window_state_maximized: + case mir_window_state_fullscreen: + new_width = window_info.window().size().width; + new_height = window_info.window().size().height; + movement = {0, 0}; + break; + + case mir_window_state_vertmaximized: + new_height = window_info.window().size().height; + movement.dy = DeltaY{0}; + break; + + case mir_window_state_horizmaximized: + new_width = window_info.window().size().width; + movement.dx - DeltaX{0}; + break; + + default:; + } + + auto const min_width = std::max(window_info.min_width(), Width{5}); + auto const min_height = std::max(window_info.min_height(), Height{5}); + + if (new_width < min_width) + { + new_width = min_width; + if (movement.dx > DeltaX{0}) + movement.dx = DeltaX{0}; + } + + if (new_height < min_height) + { + new_height = min_height; + if (movement.dy > DeltaY{0}) + movement.dy = DeltaY{0}; + } + + auto const max_width = window_info.max_width(); + auto const max_height = window_info.max_height(); + + if (new_width > max_width) + { + new_width = max_width; + if (movement.dx < DeltaX{0}) + movement.dx = DeltaX{0}; + } + + if (new_height > max_height) + { + new_height = max_height; + if (movement.dy < DeltaY{0}) + movement.dy = DeltaY{0}; + } +} + +WindowSpecification FloatingWindowManagerPolicy::place_new_window( + ApplicationInfo const& app_info, WindowSpecification const& request_parameters) +{ + auto parameters = MinimalWindowManager::place_new_window(app_info, request_parameters); + + bool const needs_titlebar = WindowInfo::needs_titlebar(parameters.type().value()); if (parameters.state().value() != mir_window_state_fullscreen && needs_titlebar) - parameters.top_left() = miral::Point{parameters.top_left().value().x, parameters.top_left().value().y + title_bar_height}; + parameters.top_left() = Point{parameters.top_left().value().x, parameters.top_left().value().y + title_bar_height}; - parameters.userdata() = std::make_shared(); + parameters.userdata() = std::make_shared(); return parameters; -} \ No newline at end of file +} + +void FloatingWindowManagerPolicy::advise_adding_to_workspace( + std::shared_ptr const& workspace, std::vector const& windows) +{ + if (windows.empty()) + return; + + for (auto const& window : windows) + { + if (workspace == active_workspace) + { + apply_workspace_visible_to(window); + } + else + { + apply_workspace_hidden_to(window); + } + } +} + +auto FloatingWindowManagerPolicy::confirm_placement_on_display( + miral::WindowInfo const& window_info, MirWindowState new_state, Rectangle const& new_placement) -> Rectangle +{ + switch (new_state) + { + case mir_window_state_maximized: + case mir_window_state_vertmaximized: + if (window_info.needs_titlebar(window_info.type())) + { + auto result = new_placement; + + result.top_left.y = result.top_left.y + title_bar_height; + result.size.height = result.size.height - title_bar_height; + return result; + } + // else + // Falls through. + default: + return new_placement; + } +} + +void FloatingWindowManagerPolicy::switch_workspace_to( + std::shared_ptr const& workspace, + Window const& window) +{ + if (workspace == active_workspace) + return; + + auto const old_active = active_workspace; + active_workspace = workspace; + + auto const old_active_window = tools.active_window(); + + if (!old_active_window) + { + // If there's no active window, the first shown grabs focus: get the right one + if (auto const ww = workspace_to_active[workspace]) + { + tools.for_each_workspace_containing(ww, [&](std::shared_ptr const& ws) + { + if (ws == workspace) + { + apply_workspace_visible_to(ww); + } + }); + } + } + + tools.remove_tree_from_workspace(window, old_active); + tools.add_tree_to_workspace(window, active_workspace); + + tools.for_each_window_in_workspace(active_workspace, [&](Window const& window) + { + apply_workspace_visible_to(window); + }); + + bool hide_old_active = false; + tools.for_each_window_in_workspace(old_active, [&](Window const& window) + { + if (window == old_active_window) + { + // If we hide the active window focus will shift: do that last + hide_old_active = true; + return; + } + + apply_workspace_hidden_to(window); + }); + + if (hide_old_active) + { + apply_workspace_hidden_to(old_active_window); + + // Remember the old active_window when we switch away + workspace_to_active[old_active] = old_active_window; + } +} + +void FloatingWindowManagerPolicy::apply_workspace_hidden_to(Window const& window) +{ + auto const& window_info = tools.info_for(window); + auto& pdata = policy_data_for(window_info); + if (!pdata.in_hidden_workspace) + { + pdata.in_hidden_workspace = true; + pdata.old_state = window_info.state(); + + WindowSpecification modifications; + modifications.state() = mir_window_state_hidden; + tools.place_and_size_for_state(modifications, window_info); + tools.modify_window(window_info.window(), modifications); + } +} + +void FloatingWindowManagerPolicy::apply_workspace_visible_to(Window const& window) +{ + auto const& window_info = tools.info_for(window); + auto& pdata = policy_data_for(window_info); + if (pdata.in_hidden_workspace) + { + pdata.in_hidden_workspace = false; + WindowSpecification modifications; + modifications.state() = pdata.old_state; + tools.place_and_size_for_state(modifications, window_info); + tools.modify_window(window_info.window(), modifications); + } +} + +void FloatingWindowManagerPolicy::handle_modify_window(WindowInfo& window_info, WindowSpecification const& modifications) +{ + auto mods = modifications; + + auto& pdata = policy_data_for(window_info); + + if (pdata.in_hidden_workspace && mods.state().is_set()) + pdata.old_state = mods.state().consume(); + + MinimalWindowManager::handle_modify_window(window_info, mods); +} diff --git a/src/FloatingWindowManager.hpp b/src/FloatingWindowManager.hpp index 7d01b8e..a9cd7fb 100644 --- a/src/FloatingWindowManager.hpp +++ b/src/FloatingWindowManager.hpp @@ -1,38 +1,117 @@ -#ifndef FLOATING_WINDOW_MANAGER_HPP -#define FLOATING_WINDOW_MANAGER_HPP +/* + * Copyright © Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 or 3 as + * published by the Free Software Foundation. + * + * 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 MIRAL_SHELL_FLOATING_WINDOW_MANAGER_H +#define MIRAL_SHELL_FLOATING_WINDOW_MANAGER_H -#include "mir/geometry/rectangles.h" -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -class FloatingWindowManager : public miral::WindowManagementPolicy { +#include + +#include +#include + +namespace miral { class InternalClientLauncher; } + +using namespace mir::geometry; + +class FloatingWindowManagerPolicy : public miral::MinimalWindowManager +{ public: - FloatingWindowManager(const miral::WindowManagerTools&); - ~FloatingWindowManager(); - miral::WindowSpecification place_new_window( - miral::ApplicationInfo const& app_info, - miral::WindowSpecification const& requested_specification) override; + FloatingWindowManagerPolicy( + miral::WindowManagerTools const& tools, + miral::InternalClientLauncher const& launcher, + std::function& shutdown_hook); + ~FloatingWindowManagerPolicy(); + + virtual miral::WindowSpecification place_new_window( + miral::ApplicationInfo const& app_info, miral::WindowSpecification const& request_parameters) override; + + /** @name example event handling: + * o Switch apps: Alt+Tab, tap or click on the corresponding window + * o Switch window: Alt+`, tap or click on the corresponding window + * o Move window: Alt-leftmousebutton drag (three finger drag) + * o Resize window: Alt-middle_button drag (three finger pinch) + * o Maximize/restore current window (to display size): Alt-F11 + * o Maximize/restore current window (to display height): Shift-F11 + * o Maximize/restore current window (to display width): Ctrl-F11 + * o Switch workspace . . . . . . . . . . : Meta-Alt-[F1|F2|F3|F4] + * o Switch workspace taking active window: Meta-Ctrl-[F1|F2|F3|F4] + * @{ */ bool handle_pointer_event(MirPointerEvent const* event) override; bool handle_touch_event(MirTouchEvent const* event) override; bool handle_keyboard_event(MirKeyboardEvent const* event) override; + /** @} */ + + /** @name track events that affect titlebar + * @{ */ void advise_new_window(miral::WindowInfo const& window_info) override; void handle_window_ready(miral::WindowInfo& window_info) override; - void handle_raise_window (miral::WindowInfo &window_info) override; void advise_focus_gained(miral::WindowInfo const& info) override; + void handle_modify_window(miral::WindowInfo& window_info, miral::WindowSpecification const& modifications) override; - mir::geometry::Rectangle confirm_placement_on_display (miral::WindowInfo const &window_info, MirWindowState new_state, mir::geometry::Rectangle const &new_placement) override; - void handle_request_drag_and_drop (miral::WindowInfo &window_info) override; - void handle_request_move (miral::WindowInfo &window_info, MirInputEvent const *input_event) override; - void handle_request_resize (miral::WindowInfo &window_info, MirInputEvent const *input_event, MirResizeEdge edge) override; - mir::geometry::Rectangle confirm_inherited_move (miral::WindowInfo const &window_info, mir::geometry::Displacement movement) override; + /** @} */ + +protected: + static const int modifier_mask = + mir_input_event_modifier_alt | + mir_input_event_modifier_shift | + mir_input_event_modifier_sym | + mir_input_event_modifier_ctrl | + mir_input_event_modifier_meta; + +private: + void toggle(MirWindowState state); + + int old_touch_pinch_top = 0; + int old_touch_pinch_left = 0; + int old_touch_pinch_width = 0; + int old_touch_pinch_height = 0; + bool pinching = false; + + void keep_window_within_constraints( + miral::WindowInfo const& window_info, + Displacement& movement, + Width& new_width, + Height& new_height) const; + + // Workaround for lp:1627697 + std::chrono::steady_clock::time_point last_resize; + + void advise_adding_to_workspace( + std::shared_ptr const& workspace, + std::vector const& windows) override; + + auto confirm_placement_on_display( + miral::WindowInfo const& window_info, + MirWindowState new_state, + Rectangle const& new_placement) -> Rectangle override; + + // Switch workspace, taking window (if not null) + void switch_workspace_to( + std::shared_ptr const& workspace, + miral::Window const& window = miral::Window{}); + + std::shared_ptr active_workspace; + std::map> key_to_workspace; + std::map, miral::Window> workspace_to_active; + + void apply_workspace_visible_to(miral::Window const& window); + + void apply_workspace_hidden_to(miral::Window const& window); }; -#endif \ No newline at end of file +#endif //MIRAL_SHELL_FLOATING_WINDOW_MANAGER_H diff --git a/src/main.cpp b/src/main.cpp index 1267075..d6cb577 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include #include +#include "FloatingWindowManager.hpp" #include #include #include @@ -26,14 +27,15 @@ int main(int argc, char const* argv[]) { std::function shutdown_hook{[]{}}; runner.add_stop_callback([&] { shutdown_hook(); }); - WindowManagerOptions windowManagers - { - add_window_manager_policy("floating"), - }; + InternalClientLauncher launcher; ExternalClientLauncher external_client_launcher; + WindowManagerOptions window_managers + { + add_window_manager_policy("floating", launcher, shutdown_hook) + }; - std::string terminal_cmd{"miral-terminal"}; + std::string terminal_cmd{"gedit"}; auto const onEvent = [&](MirEvent const* event) { @@ -74,24 +76,21 @@ int main(int argc, char const* argv[]) { }; Keymap config_keymap; - - auto run_startup_apps = [&](std::string const& apps) - { - for (auto i = begin(apps); i != end(apps); ) - { - auto const j = find(i, end(apps), ':'); - external_client_launcher.launch(std::vector{std::string{i, j}}); - if ((i = j) != end(apps)) ++i; - } - }; - return runner.run_with( + auto runResult = runner.run_with( { - windowManagers, + window_managers, WaylandExtensions{}, X11Support{}, AppendEventFilter{onEvent}, - config_keymap + config_keymap, + external_client_launcher }); + + if (runResult == EXIT_FAILURE) { + return runResult; + } + + return EXIT_SUCCESS; } \ No newline at end of file