diff --git a/CMakeLists.txt b/CMakeLists.txt index 1276a73..2de1d2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ find_package(PkgConfig) pkg_check_modules(MIRAL miral REQUIRED) find_package(OpenGL REQUIRED) -add_executable(compositor src/main.cpp src/FloatingWindowManager.cpp) +add_executable(compositor src/main.cpp src/FloatingWindowManager.cpp src/WindowGroup.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 5c2a302..2f3dec2 100644 --- a/NOTES.md +++ b/NOTES.md @@ -13,6 +13,8 @@ I will begin my searching for documentation on how I made write a Mir-based comp ### Programming 1. To get started at a reasonabel pace, I copy and pasted the example `FloatingWindowManager` class. I plan to rework it for a `TilingWindowManager` with controls that mimic those if `i3.` +2. Zones seem like a good candidate for the purposes of grouping windows together here. +3. I have successfully created the `WindowGroup` which allows me to continually create new windows horizontally. Now I will hook up keybinds to support vertical. 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 diff --git a/src/FloatingWindowManager.cpp b/src/FloatingWindowManager.cpp index d227304..68389a6 100644 --- a/src/FloatingWindowManager.cpp +++ b/src/FloatingWindowManager.cpp @@ -15,7 +15,10 @@ */ #include "FloatingWindowManager.hpp" +#include "WindowGroup.hpp" +#include "mir/geometry/forward.h" +#include #include #include #include @@ -50,7 +53,8 @@ FloatingWindowManagerPolicy::FloatingWindowManagerPolicy( WindowManagerTools const& tools, miral::InternalClientLauncher const& launcher, std::function& shutdown_hook) : - MinimalWindowManager(tools) + MinimalWindowManager(tools), + mRootWindowGroup() { mActivePlacementStrategy = PlacementStrategy::Horizontal; shutdown_hook = [this] { }; @@ -234,6 +238,8 @@ void FloatingWindowManagerPolicy::advise_new_window(WindowInfo const& window_inf if (policy_data_for(tools.info_for(parent)).in_hidden_workspace) apply_workspace_hidden_to(window_info.window()); } + + mActiveWindowGroup->addWindow(std::make_shared(window_info.window())); } void FloatingWindowManagerPolicy::handle_window_ready(WindowInfo& window_info) @@ -453,15 +459,39 @@ WindowSpecification FloatingWindowManagerPolicy::place_new_window( auto parameters = MinimalWindowManager::place_new_window(app_info, request_parameters); bool const needs_titlebar = WindowInfo::needs_titlebar(parameters.type().value()); - auto activeWindow = tools.active_window(); - auto activeZone = tools.active_application_zone(); - if (!activeWindow) { - parameters.top_left() = Point{0, 0}; - parameters.size() = Size{ activeZone.extents().size }; - + // If it is our first time adding an item to the view, we initialize the root window group. + if (!mActiveWindowGroup.get()) { + mRootWindowGroup = WindowGroup(tools.active_application_zone().extents()); + mActiveWindowGroup = std::make_shared(mRootWindowGroup); } - parameters.top_left() = Point{0, 0}; + auto targetNumberOfWindows = mActiveWindowGroup->getNumWindowsInGroup() + 1; + auto activeZone = mActiveWindowGroup->getZone(); + + if (targetNumberOfWindows == 1) { + // There are no windows in the current zone so we can place it to take up the whole zone. + parameters.top_left() = activeZone.extents().top_left; + parameters.size() = Size{ activeZone.extents().size }; + } + else if (mActivePlacementStrategy == PlacementStrategy::Horizontal) { + // Adjust current windows + auto zoneFractionSize = Size{ activeZone.extents().size.width / targetNumberOfWindows, activeZone.extents().size.height }; + const int y = activeZone.extents().top_left.y.as_value(); + for (unsigned short i = 0; auto window : mActiveWindowGroup->getWindowsInZone()) { + window->resize(zoneFractionSize); + + const int x = zoneFractionSize.width.as_int() * i + activeZone.extents().top_left.x.as_value(); + window->move_to(Point{ x, y }); + i++; + } + + const int x = zoneFractionSize.width.as_int() * mActiveWindowGroup->getNumWindowsInGroup() + activeZone.extents().top_left.x.as_value(); + parameters.top_left() = Point{ x, y }; + parameters.size() = zoneFractionSize; + } + else { + + } parameters.userdata() = std::make_shared(); return parameters; diff --git a/src/FloatingWindowManager.hpp b/src/FloatingWindowManager.hpp index 4b58614..27ba017 100644 --- a/src/FloatingWindowManager.hpp +++ b/src/FloatingWindowManager.hpp @@ -1,6 +1,8 @@ #ifndef TILING_WINDOW_MANAGER_HPP #define TILING_WINDOW_MANAGER_HPP +#include "WindowGroup.hpp" +#include #include #include #include @@ -40,6 +42,8 @@ public: bool handle_pointer_event(MirPointerEvent const* event) override; bool handle_touch_event(MirTouchEvent const* event) override; bool handle_keyboard_event(MirKeyboardEvent const* event) override; + + /** Add the window to the active zone. */ void advise_new_window(miral::WindowInfo const& window_info) override; void handle_window_ready(miral::WindowInfo& window_info) override; void advise_focus_gained(miral::WindowInfo const& info) override; @@ -56,7 +60,9 @@ protected: private: PlacementStrategy mActivePlacementStrategy; - std::vector> mActiveWindows; + std::map mZoneIdToWindowMap; + WindowGroup mRootWindowGroup; + std::shared_ptr mActiveWindowGroup; void toggle(MirWindowState state); diff --git a/src/WindowGroup.cpp b/src/WindowGroup.cpp new file mode 100644 index 0000000..e676926 --- /dev/null +++ b/src/WindowGroup.cpp @@ -0,0 +1,48 @@ +#include "WindowGroup.hpp" +#include "mir/geometry/forward.h" +#include "miral/window.h" +#include "miral/zone.h" +#include +#include + +WindowGroup::WindowGroup(): + mZone(mir::geometry::Rectangle()) +{ + +} + +WindowGroup::WindowGroup(mir::geometry::Rectangle rectangle): + mZone(rectangle) +{ +} + +WindowGroup::~WindowGroup() { + +} + +miral::Zone WindowGroup::getZone() { + return mZone; +} + +int WindowGroup::getZoneId() { + return mZone.id(); +} + +size_t WindowGroup::getNumWindowsInGroup() { + return mWindowsInZone.size(); +} + +void WindowGroup::addWindow(std::shared_ptr window) { + mWindowsInZone.push_back(window); +} + +void WindowGroup::removeWindow(std::shared_ptr window) { + auto toErase = std::ranges::find(mWindowsInZone, window); + if (toErase != mWindowsInZone.end()) { + mWindowsInZone.erase(toErase); + } +} + +std::vector> WindowGroup::getWindowsInZone() { + return mWindowsInZone; +} \ No newline at end of file diff --git a/src/WindowGroup.hpp b/src/WindowGroup.hpp new file mode 100644 index 0000000..baa7ada --- /dev/null +++ b/src/WindowGroup.hpp @@ -0,0 +1,31 @@ +#ifndef WINDOW_GROUP_HPP +#define WINDOW_GROUP_HPP + +#include "mir/geometry/forward.h" +#include "miral/window_info.h" +#include "miral/zone.h" +#include +#include +#include + +/** Represents a group of windows in the tiler. */ +class WindowGroup { +public: + WindowGroup(); + WindowGroup(mir::geometry::Rectangle); + ~WindowGroup(); + + miral::Zone getZone(); + int getZoneId(); + void addWindow(std::shared_ptr); + void removeWindow(std::shared_ptr); + std::vector> getWindowsInZone(); + size_t getNumWindowsInGroup(); + +private: + miral::Zone mZone; + std::vector> mSubGroups; + std::vector> mWindowsInZone; +}; + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index d6cb577..740538b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,7 +35,7 @@ int main(int argc, char const* argv[]) { add_window_manager_policy("floating", launcher, shutdown_hook) }; - std::string terminal_cmd{"gedit"}; + std::string terminal_cmd{"xfce4-terminal"}; auto const onEvent = [&](MirEvent const* event) { @@ -60,14 +60,9 @@ int main(int argc, char const* argv[]) { runner.stop(); return true; - case XKB_KEY_t: - case XKB_KEY_T: - external_client_launcher.launch({terminal_cmd}); - return false; - case XKB_KEY_x: case XKB_KEY_X: - external_client_launcher.launch_using_x11({"xterm"}); + external_client_launcher.launch({terminal_cmd}); return false; default: