mirror of
https://github.com/miracle-wm-org/miracle-wm.git
synced 2024-11-23 04:08:27 +03:00
An initial WIP
This commit is contained in:
parent
da7c5a3ca5
commit
5ccdee560c
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
1
.idea/.name
Normal file
1
.idea/.name
Normal file
@ -0,0 +1 @@
|
||||
MirCompositor
|
2
.idea/mir-i3.iml
Normal file
2
.idea/mir-i3.iml
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
4
.idea/misc.xml
Normal file
4
.idea/misc.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/mir-i3.iml" filepath="$PROJECT_DIR$/.idea/mir-i3.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -15,7 +15,13 @@ find_package(PkgConfig)
|
||||
pkg_check_modules(MIRAL miral REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
add_executable(compositor src/main.cpp src/TilingWindowManager.cpp src/TileNode.cpp)
|
||||
add_executable(compositor
|
||||
src/display_listener.cpp
|
||||
src/main.cpp
|
||||
src/mirie_window_management_policy.cpp
|
||||
src/tiling_region.cpp
|
||||
src/tiled_node.cpp
|
||||
)
|
||||
|
||||
target_include_directories(compositor PUBLIC SYSTEM ${MIRAL_INCLUDE_DIRS})
|
||||
target_link_libraries( compositor ${MIRAL_LDFLAGS})
|
173
src/TileNode.cpp
173
src/TileNode.cpp
@ -1,173 +0,0 @@
|
||||
#include "TileNode.hpp"
|
||||
#include "mir/geometry/forward.h"
|
||||
#include "miral/window.h"
|
||||
#include "miral/zone.h"
|
||||
#include <algorithm>
|
||||
#include <bits/ranges_algobase.h>
|
||||
#include <bits/ranges_util.h>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
TileNode::TileNode(mir::geometry::Rectangle rectangle, PlacementStrategy strategy):
|
||||
std::enable_shared_from_this<TileNode>(),
|
||||
mZone(rectangle)
|
||||
{
|
||||
mPlacementStrategy = strategy;
|
||||
}
|
||||
|
||||
TileNode::~TileNode() {
|
||||
std::cout << "Decounstructing " << getZoneId() << std::endl;
|
||||
}
|
||||
|
||||
miral::Zone TileNode::getZone() {
|
||||
return mZone;
|
||||
}
|
||||
|
||||
int TileNode::getZoneId() {
|
||||
return mZone.id();
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<TileNode>> TileNode::getChildNodeList() {
|
||||
return mChildNodes;
|
||||
}
|
||||
|
||||
std::shared_ptr<TileNode> TileNode::addWindow(std::shared_ptr<miral::Window> window) {
|
||||
// We don't have a root window
|
||||
if (!mWindow.get() && mChildNodes.size() == 0) {
|
||||
std::cout << "Adding window as root window in the group" << std::endl;
|
||||
mWindow = window;
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
if (mChildNodes.size() > 0 && mWindow.get()) {
|
||||
throw new std::exception();
|
||||
}
|
||||
|
||||
auto controllingTileNode = getControllingTileNode();
|
||||
|
||||
// If we are controlling ourselves AND we are just a single window, we need to go "amoeba-mode" and create
|
||||
// a new tile from the parent tile.
|
||||
if (controllingTileNode == shared_from_this() && mWindow) {
|
||||
std::cout << "Creating a new window group from the previous window." << std::endl;
|
||||
auto firstNewTileNode = controllingTileNode->makeTileNode(mWindow, PlacementStrategy::Parent);
|
||||
firstNewTileNode->mParent = shared_from_this();
|
||||
controllingTileNode->mChildNodes.push_back(firstNewTileNode);
|
||||
mWindow.reset();
|
||||
}
|
||||
|
||||
// Add the new window.
|
||||
std::cout << "Creating a new window group from the new window." << std::endl;
|
||||
auto secondNewTileNode = controllingTileNode->makeTileNode(window, PlacementStrategy::Parent);
|
||||
secondNewTileNode->mParent = controllingTileNode;
|
||||
controllingTileNode->mChildNodes.push_back(secondNewTileNode);
|
||||
return secondNewTileNode;
|
||||
}
|
||||
|
||||
size_t TileNode::getNumberOfTiles() {
|
||||
if (mWindow.get()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return mChildNodes.size();
|
||||
}
|
||||
|
||||
bool TileNode::removeWindow(std::shared_ptr<miral::Window> window) {
|
||||
if (mWindow == window) {
|
||||
// If this group represents the window, remove it.
|
||||
mWindow.reset();
|
||||
|
||||
// Remove the child from the parent and take its children.
|
||||
if (mParent.get()) {
|
||||
std::vector<std::shared_ptr<TileNode>>::iterator it = std::find(
|
||||
mParent->mChildNodes.begin(), mParent->mChildNodes.end(), shared_from_this());
|
||||
if (it != mParent->mChildNodes.end()) {
|
||||
for (auto adoptedTileNodes : mChildNodes) {
|
||||
mParent->mChildNodes.push_back(adoptedTileNodes);
|
||||
}
|
||||
std::cout << "Erasing window group from the parent. Size = " << mParent->mChildNodes.size() << std::endl;
|
||||
mParent->mChildNodes.erase(it);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// Otherwise, search the other groups to remove it.
|
||||
for (auto group: mChildNodes) {
|
||||
if (group->removeWindow(window)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<TileNode> TileNode::makeTileNode(std::shared_ptr<miral::Window> window, PlacementStrategy placementStrategy) {
|
||||
// Capture the size of the window to make it the size of the new group.
|
||||
auto nextGroupPosition = window->top_left();
|
||||
auto nextGroupSize = window->size();
|
||||
auto zoneSize = mir::geometry::Rectangle(nextGroupPosition, nextGroupSize);
|
||||
auto tileNode = std::make_shared<TileNode>(zoneSize, placementStrategy);
|
||||
tileNode->mWindow = window;
|
||||
return tileNode;
|
||||
}
|
||||
|
||||
PlacementStrategy TileNode::getPlacementStrategy() {
|
||||
return mPlacementStrategy;
|
||||
}
|
||||
|
||||
void TileNode::setPlacementStrategy(PlacementStrategy strategy) {
|
||||
mPlacementStrategy = strategy;
|
||||
}
|
||||
|
||||
std::shared_ptr<TileNode> TileNode::getControllingTileNode() {
|
||||
if (mPlacementStrategy == PlacementStrategy::Parent) {
|
||||
return mParent->getControllingTileNode();
|
||||
}
|
||||
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
bool TileNode::isEmpty() {
|
||||
return mParent.get() == nullptr && mWindow.get() == nullptr && mChildNodes.size() == 0;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<miral::Window>> TileNode::getWindowsInTile() {
|
||||
std::vector<std::shared_ptr<miral::Window>> retval;
|
||||
if (mWindow.get()) {
|
||||
retval.push_back(mWindow);
|
||||
}
|
||||
|
||||
for (auto tileNode : mChildNodes) {
|
||||
auto otherRetval = tileNode->getWindowsInTile();
|
||||
for (auto otherWindow : otherRetval) {
|
||||
retval.push_back(otherWindow);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::shared_ptr<TileNode> TileNode::getParent() {
|
||||
if (mParent.get()) return mParent;
|
||||
else return shared_from_this();
|
||||
}
|
||||
|
||||
std::shared_ptr<TileNode> TileNode::getTileNodeForWindow(std::shared_ptr<miral::Window> window) {
|
||||
if (mWindow == window) {
|
||||
return shared_from_this();
|
||||
}
|
||||
else {
|
||||
// Otherwise, search the other groups to remove it.
|
||||
for (auto group: mChildNodes) {
|
||||
auto tileNode = group->getTileNodeForWindow(window);
|
||||
if (tileNode) {
|
||||
return tileNode;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
136
src/TileNode.hpp
136
src/TileNode.hpp
@ -1,136 +0,0 @@
|
||||
#ifndef WINDOW_GROUP_HPP
|
||||
#define WINDOW_GROUP_HPP
|
||||
|
||||
#include "mir/geometry/forward.h"
|
||||
#include "miral/window.h"
|
||||
#include "miral/window_info.h"
|
||||
#include "miral/window_specification.h"
|
||||
#include "miral/zone.h"
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
/** Defines how new windows will be placed in the TileNode. */
|
||||
enum class PlacementStrategy {
|
||||
/** If horizontal, we will place the new window to the right of the selectd window. */
|
||||
Horizontal,
|
||||
/** If vertical, we will place the new window below the selected window. */
|
||||
Vertical,
|
||||
/** If parent, we will defer the placement strategy of this window to the parent's placement strategy. */
|
||||
Parent
|
||||
};
|
||||
|
||||
/**
|
||||
Each TileNode represents a Tilelable object on the desktop.
|
||||
The TileNodes create a Tree data structure that represents the
|
||||
control of placement on the desktop grid.
|
||||
|
||||
The smallest node is comprised of a single window.
|
||||
A large TileNode is made up of many TileNodes.
|
||||
*/
|
||||
class TileNode : public std::enable_shared_from_this<TileNode> {
|
||||
public:
|
||||
TileNode(mir::geometry::Rectangle, PlacementStrategy strategy);
|
||||
~TileNode();
|
||||
|
||||
/**
|
||||
Retrieve the zone defined by this TileNode.
|
||||
*/
|
||||
miral::Zone getZone();
|
||||
|
||||
/**
|
||||
Retrieve the unique identifier for this zone.
|
||||
|
||||
@returns Zone if
|
||||
*/
|
||||
int getZoneId();
|
||||
|
||||
/**
|
||||
Retrieve the child nodes of this group.
|
||||
|
||||
@returns A list of child nodes contained within this TileNode.
|
||||
*/
|
||||
std::vector<std::shared_ptr<TileNode>> getChildNodeList();
|
||||
|
||||
/**
|
||||
Adds a window to the TileNode.
|
||||
|
||||
@returns a pointer to the TileNode that the window now exists in.
|
||||
*/
|
||||
std::shared_ptr<TileNode> addWindow(std::shared_ptr<miral::Window>);
|
||||
|
||||
/**
|
||||
Removes a window from the ToleNode.
|
||||
|
||||
@returns True if the window was removed, otherwise false.
|
||||
*/
|
||||
bool removeWindow(std::shared_ptr<miral::Window>);
|
||||
|
||||
/**
|
||||
Collects all of the windows in the TileNode, including those in child nodes.
|
||||
|
||||
@returns A list of windows underneath this tile node.
|
||||
*/
|
||||
std::vector<std::shared_ptr<miral::Window>> getWindowsInTile();
|
||||
|
||||
/**
|
||||
Gets the number of tiles under the control of this node EXCLUDING child nodes.
|
||||
|
||||
@returns The immediate number of tiles under the control of this TileNode.
|
||||
*/
|
||||
size_t getNumberOfTiles();
|
||||
|
||||
/**
|
||||
Retrieves the placement strategy of this node.
|
||||
|
||||
@returns The placement strategy
|
||||
*/
|
||||
PlacementStrategy getPlacementStrategy();
|
||||
|
||||
/**
|
||||
Sets the placement strategy of this node.
|
||||
*/
|
||||
void setPlacementStrategy(PlacementStrategy);
|
||||
|
||||
/**
|
||||
Returns the TileNode who is in charge of organizing this TileNode.
|
||||
This COULD be itself.
|
||||
|
||||
@returns The TileNode that controls this TileNode.
|
||||
*/
|
||||
std::shared_ptr<TileNode> getControllingTileNode();
|
||||
|
||||
/**
|
||||
Returns true if the TileNode is the parent AND nothing has been added to it.
|
||||
|
||||
@returns True if it is empty, otherwise false.
|
||||
*/
|
||||
bool isEmpty();
|
||||
|
||||
/**
|
||||
Retrieves the parent of this child node. Expected to be nullptr for the root.
|
||||
|
||||
@returns The parent node
|
||||
*/
|
||||
std::shared_ptr<TileNode> getParent();
|
||||
|
||||
/**
|
||||
Given a window, searches recursively for the TileNode that holds it. Returns nullptr
|
||||
if none is found.
|
||||
|
||||
@returns The TileNode to which the window belongs.
|
||||
*/
|
||||
std::shared_ptr<TileNode> getTileNodeForWindow(std::shared_ptr<miral::Window>);
|
||||
|
||||
private:
|
||||
miral::Zone mZone;
|
||||
|
||||
std::shared_ptr<miral::Window> mWindow;
|
||||
std::shared_ptr<TileNode> mParent;
|
||||
std::vector<std::shared_ptr<TileNode>> mChildNodes;
|
||||
PlacementStrategy mPlacementStrategy;
|
||||
|
||||
std::shared_ptr<TileNode> makeTileNode(std::shared_ptr<miral::Window>, PlacementStrategy strategy);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,263 +0,0 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TilingWindowManager.hpp"
|
||||
#include "mir/geometry/forward.h"
|
||||
#include "mir/logging/logger.h"
|
||||
#include "mir_toolkit/events/enums.h"
|
||||
#include "miral/application.h"
|
||||
#include "miral/minimal_window_manager.h"
|
||||
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <memory>
|
||||
#include <miral/application_info.h>
|
||||
#include <miral/internal_client.h>
|
||||
#include <miral/toolkit_event.h>
|
||||
#include <miral/window_info.h>
|
||||
#include <miral/window_manager_tools.h>
|
||||
#include <miral/zone.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <csignal>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
using namespace miral;
|
||||
using namespace miral::toolkit;
|
||||
|
||||
TilingWindowManagerPolicy::TilingWindowManagerPolicy(
|
||||
WindowManagerTools const& inTools,
|
||||
miral::InternalClientLauncher const& launcher,
|
||||
std::function<void()>& shutdown_hook) :
|
||||
miral::MinimalWindowManager(inTools),
|
||||
mRootTileNode()
|
||||
{
|
||||
mDefaultStrategy = PlacementStrategy::Horizontal;
|
||||
shutdown_hook = [this] { };
|
||||
mActiveTileNode = nullptr;
|
||||
}
|
||||
|
||||
TilingWindowManagerPolicy::~TilingWindowManagerPolicy() = default;
|
||||
|
||||
bool TilingWindowManagerPolicy::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) & pModifierMask;
|
||||
|
||||
if (action == MirKeyboardAction::mir_keyboard_action_down && (modifiers && mir_input_event_modifier_meta)) {
|
||||
if (scan_code == KEY_V) {
|
||||
requestPlacementStrategyChange(PlacementStrategy::Vertical);
|
||||
return true;
|
||||
}
|
||||
else if (scan_code == KEY_H) {
|
||||
requestPlacementStrategyChange(PlacementStrategy::Horizontal);
|
||||
return true;
|
||||
}
|
||||
else if (scan_code == KEY_LEFT) {
|
||||
requestChangeActiveWindow(-1);
|
||||
return true;
|
||||
}
|
||||
else if (scan_code == KEY_RIGHT) {
|
||||
requestChangeActiveWindow(1);
|
||||
return true;
|
||||
}
|
||||
else if ((modifiers && mir_input_event_modifier_shift) && scan_code == KEY_Q) {
|
||||
requestQuitSelectedApplication();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TilingWindowManagerPolicy::requestPlacementStrategyChange(PlacementStrategy strategy) {
|
||||
auto activeWindow = tools.active_window();
|
||||
|
||||
if (!activeWindow) {
|
||||
// Nothing is selected which means nothing is added to the screen.
|
||||
mDefaultStrategy = strategy;
|
||||
return;
|
||||
}
|
||||
|
||||
mActiveTileNode->setPlacementStrategy(strategy);
|
||||
}
|
||||
|
||||
void TilingWindowManagerPolicy::requestQuitSelectedApplication() {
|
||||
if (!mActiveWindow.get()) {
|
||||
std::cout << "There is no current application to quit." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Kill the application and remove it from the grid.
|
||||
auto application = mActiveWindow->application();
|
||||
mRootTileNode->removeWindow(mActiveWindow);
|
||||
miral::kill(application, SIGTERM);
|
||||
|
||||
// Remove the window from our list of applications.
|
||||
auto it = std::find(mWindowsOnDesktop.begin(), mWindowsOnDesktop.end(), mActiveWindow);
|
||||
int index = it - mWindowsOnDesktop.begin();
|
||||
if (it != mWindowsOnDesktop.end()) {
|
||||
mWindowsOnDesktop.erase(it);
|
||||
}
|
||||
|
||||
// TODO: If I had more time, I would resize the grid when a quit occurs.
|
||||
if (index >= mWindowsOnDesktop.size()) {
|
||||
index = mWindowsOnDesktop.size() - 1;
|
||||
}
|
||||
|
||||
// Select the next available window.
|
||||
if (index >= 0) {
|
||||
mActiveWindow = mWindowsOnDesktop[index];
|
||||
mActiveTileNode = mRootTileNode->getTileNodeForWindow(mActiveWindow);
|
||||
}
|
||||
else {
|
||||
mActiveTileNode = mRootTileNode;
|
||||
mActiveWindow.reset();
|
||||
}
|
||||
|
||||
std::cout << "Quit the current application." << std::endl;
|
||||
}
|
||||
|
||||
bool TilingWindowManagerPolicy::requestChangeActiveWindow(int moveAmount) {
|
||||
auto it = std::find(mWindowsOnDesktop.begin(), mWindowsOnDesktop.end(), mActiveWindow);
|
||||
if (it == mWindowsOnDesktop.end()) {
|
||||
std::cerr << "Unable to find current window on the desktop." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = it - mWindowsOnDesktop.begin();
|
||||
int newIndex = index + moveAmount;
|
||||
while (newIndex < 0) {
|
||||
newIndex += mWindowsOnDesktop.size();
|
||||
}
|
||||
while (newIndex >= mWindowsOnDesktop.size()) {
|
||||
newIndex -= mWindowsOnDesktop.size();
|
||||
}
|
||||
|
||||
mActiveWindow = mWindowsOnDesktop[newIndex];
|
||||
mActiveTileNode = mRootTileNode->getTileNodeForWindow(mActiveWindow);
|
||||
tools.select_active_window(*mActiveWindow.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
WindowSpecification TilingWindowManagerPolicy::place_new_window(
|
||||
ApplicationInfo const& app_info, WindowSpecification const& request_parameters)
|
||||
{
|
||||
auto parameters = MinimalWindowManager::place_new_window(app_info, request_parameters);
|
||||
|
||||
// If it is our first time adding an item to the view, we initialize the root window group.
|
||||
if (!mRootTileNode.get()) {
|
||||
mRootTileNode = std::make_shared<TileNode>(tools.active_application_zone().extents(), mDefaultStrategy);
|
||||
mActiveTileNode = mRootTileNode;
|
||||
}
|
||||
|
||||
auto groupInCharge = mActiveTileNode->getControllingTileNode();
|
||||
auto targetNumberOfWindows = groupInCharge->getNumberOfTiles() + 1;
|
||||
auto activeZone = groupInCharge->getZone();
|
||||
auto placementStrategy = groupInCharge->getPlacementStrategy();
|
||||
|
||||
std::cout << "Placing new window into group. Group ID: " << activeZone.id() << ". Target Number of Windows: " << targetNumberOfWindows << std::endl;
|
||||
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 (placementStrategy == PlacementStrategy::Horizontal) {
|
||||
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 : groupInCharge->getWindowsInTile()) {
|
||||
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() * groupInCharge->getNumberOfTiles() + activeZone.extents().top_left.x.as_value();
|
||||
parameters.top_left() = Point{ x, y };
|
||||
parameters.size() = zoneFractionSize;
|
||||
}
|
||||
else if (placementStrategy == PlacementStrategy::Vertical) {
|
||||
auto zoneFractionSize = Size{ activeZone.extents().size.width, activeZone.extents().size.height / targetNumberOfWindows };
|
||||
const int x = activeZone.extents().top_left.x.as_value();
|
||||
for (unsigned short i = 0; auto window : groupInCharge->getWindowsInTile()) {
|
||||
window->resize(zoneFractionSize);
|
||||
|
||||
const int y = zoneFractionSize.height.as_int() * i + activeZone.extents().top_left.y.as_value();
|
||||
window->move_to(Point{ x, y });
|
||||
i++;
|
||||
}
|
||||
|
||||
const int y = zoneFractionSize.height.as_int() * groupInCharge->getNumberOfTiles() + activeZone.extents().top_left.y.as_value();
|
||||
parameters.top_left() = Point{ x, y };
|
||||
parameters.size() = zoneFractionSize;
|
||||
}
|
||||
|
||||
std::cout << "Placement of window complete." << std::endl;
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
bool TilingWindowManagerPolicy::handle_pointer_event(MirPointerEvent const* event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TilingWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void TilingWindowManagerPolicy::advise_new_window(WindowInfo const& window_info) {
|
||||
std::cout << "Adding window into the TileNode" << std::endl;
|
||||
|
||||
// Add the window into the current tile.
|
||||
auto window = std::make_shared<Window>(window_info.window());
|
||||
mActiveTileNode = mActiveTileNode->addWindow(window);
|
||||
mActiveWindow = window;
|
||||
|
||||
// Do the regular placing and sizing.
|
||||
WindowSpecification modifications;
|
||||
tools.place_and_size_for_state(modifications, window_info);
|
||||
tools.modify_window(window_info.window(), modifications);
|
||||
std::cout << "New window group has ID: " << mActiveTileNode->getZoneId() << ". New zone is now active." << std::endl;
|
||||
if (mActiveTileNode->getParent().get()) {
|
||||
std::cout << "Parent window group has ID: " << mActiveTileNode->getParent()->getZoneId() << std::endl;
|
||||
}
|
||||
|
||||
mWindowsOnDesktop.push_back(window);
|
||||
}
|
||||
|
||||
void TilingWindowManagerPolicy::handle_window_ready(WindowInfo& window_info) {
|
||||
MinimalWindowManager::handle_window_ready(window_info);
|
||||
return;
|
||||
}
|
||||
|
||||
void TilingWindowManagerPolicy::advise_focus_gained(WindowInfo const& info) {
|
||||
MinimalWindowManager::advise_focus_gained(info);
|
||||
return;
|
||||
}
|
||||
|
||||
void TilingWindowManagerPolicy::handle_modify_window(WindowInfo& window_info, WindowSpecification const& modifications) {
|
||||
MinimalWindowManager::handle_modify_window(window_info, modifications);
|
||||
return;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
#ifndef TILING_WINDOW_MANAGER_HPP
|
||||
#define TILING_WINDOW_MANAGER_HPP
|
||||
|
||||
#include "TileNode.hpp"
|
||||
#include "miral/window_management_policy.h"
|
||||
#include "miral/window_specification.h"
|
||||
#include <memory>
|
||||
#include <miral/minimal_window_manager.h>
|
||||
#include <mir_toolkit/events/enums.h>
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace miral {
|
||||
class InternalClientLauncher;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a tiling window manager, much like i3.
|
||||
*/
|
||||
class TilingWindowManagerPolicy : public miral::MinimalWindowManager {
|
||||
public:
|
||||
TilingWindowManagerPolicy(
|
||||
miral::WindowManagerTools const&,
|
||||
miral::InternalClientLauncher const&,
|
||||
std::function<void()>&);
|
||||
~TilingWindowManagerPolicy();
|
||||
|
||||
/**
|
||||
* Positions the new window in reference to the currently selected window and the current mode.
|
||||
*/
|
||||
virtual miral::WindowSpecification place_new_window(
|
||||
miral::ApplicationInfo const&, miral::WindowSpecification const&) override;
|
||||
|
||||
|
||||
bool handle_pointer_event(MirPointerEvent const*) override;
|
||||
bool handle_touch_event(MirTouchEvent const*) override;
|
||||
bool handle_keyboard_event(MirKeyboardEvent const*) override;
|
||||
|
||||
/** Add the window to the active zone. */
|
||||
void advise_new_window(miral::WindowInfo const&) override;
|
||||
void handle_window_ready(miral::WindowInfo&) override;
|
||||
void advise_focus_gained(miral::WindowInfo const&) override;
|
||||
|
||||
void handle_modify_window(miral::WindowInfo&, miral::WindowSpecification const&) override;
|
||||
|
||||
protected:
|
||||
static const int pModifierMask =
|
||||
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:
|
||||
std::shared_ptr<TileNode> mRootTileNode;
|
||||
std::shared_ptr<TileNode> mActiveTileNode;
|
||||
PlacementStrategy mDefaultStrategy;
|
||||
std::vector<std::shared_ptr<miral::Window>> mWindowsOnDesktop;
|
||||
std::shared_ptr<miral::Window> mActiveWindow;
|
||||
|
||||
void requestPlacementStrategyChange(PlacementStrategy);
|
||||
void requestQuitSelectedApplication();
|
||||
bool requestChangeActiveWindow(int);
|
||||
};
|
||||
|
||||
#endif //TILING_WINDOW_MANAGER_HPP
|
12
src/display_listener.cpp
Normal file
12
src/display_listener.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
//
|
||||
// Created by mattkae on 9/8/23.
|
||||
//
|
||||
|
||||
#include "display_listener.h"
|
||||
|
||||
using namespace mirie;
|
||||
|
||||
void DisplayListener::operator()(mir::Server &server) const
|
||||
{
|
||||
|
||||
}
|
25
src/display_listener.h
Normal file
25
src/display_listener.h
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// Created by mattkae on 9/8/23.
|
||||
//
|
||||
|
||||
#ifndef MIRCOMPOSITOR_DISPLAY_LISTENER_H
|
||||
#define MIRCOMPOSITOR_DISPLAY_LISTENER_H
|
||||
|
||||
|
||||
namespace mir
|
||||
{
|
||||
class Server;
|
||||
}
|
||||
|
||||
namespace mirie
|
||||
{
|
||||
class DisplayListener
|
||||
{
|
||||
public:
|
||||
DisplayListener() = default;
|
||||
void operator()(mir::Server& server) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //MIRCOMPOSITOR_DISPLAY_LISTENER_H
|
54
src/main.cpp
54
src/main.cpp
@ -1,80 +1,38 @@
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#include "TilingWindowManager.hpp"
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <miral/set_window_management_policy.h>
|
||||
#include <miral/external_client.h>
|
||||
#include <miral/runner.h>
|
||||
#include <miral/window_management_options.h>
|
||||
#include <miral/append_event_filter.h>
|
||||
#include <miral/internal_client.h>
|
||||
#include <miral/keymap.h>
|
||||
#include <miral/toolkit_event.h>
|
||||
#include <miral/x11_support.h>
|
||||
#include <miral/wayland_extensions.h>
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
#include <miral/minimal_window_manager.h>
|
||||
#include "mirie_window_management_policy.h"
|
||||
|
||||
using namespace miral;
|
||||
using namespace miral::toolkit;
|
||||
|
||||
int main(int argc, char const* argv[]) {
|
||||
int main(int argc, char const* argv[])
|
||||
{
|
||||
MirRunner runner{argc, argv};
|
||||
|
||||
std::function<void()> shutdown_hook{[]{}};
|
||||
runner.add_stop_callback([&] { shutdown_hook(); });
|
||||
|
||||
InternalClientLauncher launcher;
|
||||
|
||||
ExternalClientLauncher external_client_launcher;
|
||||
WindowManagerOptions window_managers
|
||||
{
|
||||
add_window_manager_policy<TilingWindowManagerPolicy>("tiling", launcher, shutdown_hook)
|
||||
};
|
||||
|
||||
std::string terminal_cmd{"xfce4-terminal"};
|
||||
|
||||
auto const onEvent = [&](MirEvent const* event){
|
||||
if (mir_event_get_type(event) != mir_event_type_input)
|
||||
return false;
|
||||
|
||||
MirInputEvent const* input_event = mir_event_get_input_event(event);
|
||||
if (mir_input_event_get_type(input_event) != mir_input_event_type_key)
|
||||
return false;
|
||||
|
||||
MirKeyboardEvent const* kev = mir_input_event_get_keyboard_event(input_event);
|
||||
if (mir_keyboard_event_action(kev) != mir_keyboard_action_down)
|
||||
return false;
|
||||
|
||||
MirInputEventModifiers modifiers = mir_keyboard_event_modifiers(kev);
|
||||
auto const keyEvent = mir_keyboard_event_keysym(kev);
|
||||
if ((modifiers & mir_input_event_modifier_meta) && keyEvent == XKB_KEY_Return) {
|
||||
external_client_launcher.launch({terminal_cmd});
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(modifiers & mir_input_event_modifier_alt) || !(modifiers & mir_input_event_modifier_ctrl))
|
||||
return false;
|
||||
|
||||
switch (keyEvent) {
|
||||
case XKB_KEY_BackSpace:
|
||||
runner.stop();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
{
|
||||
add_window_manager_policy<mirie::MirieWindowManagementPolicy>("tiling", external_client_launcher)
|
||||
};
|
||||
|
||||
|
||||
Keymap config_keymap;
|
||||
|
||||
|
||||
return runner.run_with(
|
||||
{
|
||||
window_managers,
|
||||
WaylandExtensions{},
|
||||
X11Support{},
|
||||
AppendEventFilter{onEvent},
|
||||
config_keymap,
|
||||
external_client_launcher
|
||||
});
|
||||
|
54
src/mirie_window_management_policy.cpp
Normal file
54
src/mirie_window_management_policy.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// Created by mattkae on 9/8/23.
|
||||
//
|
||||
#define MIR_LOG_COMPONENT "mirie"
|
||||
|
||||
#include "mirie_window_management_policy.h"
|
||||
#include <mir_toolkit/events/enums.h>
|
||||
#include <miral/toolkit_event.h>
|
||||
#include <mir/log.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
|
||||
using namespace mirie;
|
||||
|
||||
namespace
|
||||
{
|
||||
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;
|
||||
|
||||
const std::string TERMINAL = "xfce4-terminal";
|
||||
}
|
||||
|
||||
MirieWindowManagementPolicy::MirieWindowManagementPolicy(
|
||||
const miral::WindowManagerTools & tools,
|
||||
miral::ExternalClientLauncher const& launcher)
|
||||
: miral::MinimalWindowManager(tools),
|
||||
window_manager_tools{tools},
|
||||
launcher{launcher}
|
||||
{
|
||||
}
|
||||
|
||||
bool MirieWindowManagementPolicy::handle_keyboard_event(MirKeyboardEvent const* event)
|
||||
{
|
||||
if (MinimalWindowManager::handle_keyboard_event(event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto const action = miral::toolkit::mir_keyboard_event_action(event);
|
||||
auto const scan_code = miral::toolkit::mir_keyboard_event_scan_code(event);
|
||||
auto const modifiers = miral::toolkit::mir_keyboard_event_modifiers(event) & MODIFIER_MASK;
|
||||
|
||||
if (action == MirKeyboardAction::mir_keyboard_action_down && (modifiers && mir_input_event_modifier_alt)) {
|
||||
if (scan_code == KEY_ENTER) {
|
||||
launcher.launch({TERMINAL});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
37
src/mirie_window_management_policy.h
Normal file
37
src/mirie_window_management_policy.h
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// Created by mattkae on 9/8/23.
|
||||
//
|
||||
|
||||
#ifndef MIRCOMPOSITOR_MIRIE_WINDOW_MANAGEMENT_POLICY_H
|
||||
#define MIRCOMPOSITOR_MIRIE_WINDOW_MANAGEMENT_POLICY_H
|
||||
|
||||
#include <miral/window_manager_tools.h>
|
||||
#include <miral/minimal_window_manager.h>
|
||||
#include <miral/external_client.h>
|
||||
#include <memory>
|
||||
|
||||
namespace mirie
|
||||
{
|
||||
class TilingRegion;
|
||||
class DisplayListener;
|
||||
|
||||
class MirieWindowManagementPolicy : public miral::MinimalWindowManager
|
||||
{
|
||||
public:
|
||||
MirieWindowManagementPolicy(
|
||||
miral::WindowManagerTools const&,
|
||||
miral::ExternalClientLauncher const&,
|
||||
mirie::DisplayListener& display_listener);
|
||||
~MirieWindowManagementPolicy() = default;
|
||||
|
||||
bool handle_keyboard_event(MirKeyboardEvent const* event) override;
|
||||
|
||||
private:
|
||||
miral::WindowManagerTools const window_manager_tools;
|
||||
miral::ExternalClientLauncher const launcher;
|
||||
std::shared_ptr<TilingRegion> root;
|
||||
mirie::DisplayListener const display_listener;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //MIRCOMPOSITOR_MIRIE_WINDOW_MANAGEMENT_POLICY_H
|
27
src/tiled_node.cpp
Normal file
27
src/tiled_node.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created by mattkae on 9/8/23.
|
||||
//
|
||||
|
||||
#include "tiled_node.h"
|
||||
|
||||
using namespace mirie;
|
||||
|
||||
TiledNode::TiledNode(
|
||||
miral::Window const& window,
|
||||
std::shared_ptr<TilingRegion> const& region):
|
||||
window{window},
|
||||
region{region}
|
||||
{
|
||||
}
|
||||
|
||||
auto TiledNode::get_rectangle() -> mir::geometry::Rectangle
|
||||
{
|
||||
return mir::geometry::Rectangle(
|
||||
window.top_left(),
|
||||
window.size());
|
||||
}
|
||||
|
||||
void TiledNode::update_region(const std::shared_ptr<TilingRegion>& in_region)
|
||||
{
|
||||
region = in_region;
|
||||
}
|
28
src/tiled_node.h
Normal file
28
src/tiled_node.h
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// Created by mattkae on 9/8/23.
|
||||
//
|
||||
|
||||
#ifndef MIRCOMPOSITOR_TILED_NODE_H
|
||||
#define MIRCOMPOSITOR_TILED_NODE_H
|
||||
|
||||
#include <miral/window.h>
|
||||
#include <mir/geometry/rectangle.h>
|
||||
|
||||
namespace mirie
|
||||
{
|
||||
class TilingRegion;
|
||||
|
||||
class TiledNode
|
||||
{
|
||||
public:
|
||||
TiledNode(miral::Window const&, std::shared_ptr<TilingRegion> const&);
|
||||
auto get_rectangle() -> mir::geometry::Rectangle;
|
||||
void update_region(std::shared_ptr<TilingRegion> const&);
|
||||
private:
|
||||
miral::Window window;
|
||||
std::shared_ptr<TilingRegion> region;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //MIRCOMPOSITOR_TILED_NODE_H
|
5
src/tiling_region.cpp
Normal file
5
src/tiling_region.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by mattkae on 9/8/23.
|
||||
//
|
||||
|
||||
#include "tiling_region.h"
|
40
src/tiling_region.h
Normal file
40
src/tiling_region.h
Normal file
@ -0,0 +1,40 @@
|
||||
//
|
||||
// Created by mattkae on 9/8/23.
|
||||
//
|
||||
|
||||
#ifndef MIRCOMPOSITOR_TILING_REGION_H
|
||||
#define MIRCOMPOSITOR_TILING_REGION_H
|
||||
|
||||
#include "tiled_node.h"
|
||||
|
||||
#include <mir/geometry/rectangle.h>
|
||||
#include <miral/window.h>
|
||||
#include <miral/application.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace mirie
|
||||
{
|
||||
|
||||
enum class TilingRegionDirection
|
||||
{
|
||||
horizontal,
|
||||
vertical,
|
||||
length
|
||||
};
|
||||
|
||||
class TilingRegion
|
||||
{
|
||||
public:
|
||||
explicit TilingRegion(mir::geometry::Rectangle const&);
|
||||
void split(TilingRegionDirection direction);
|
||||
|
||||
private:
|
||||
mir::geometry::Rectangle rectangle;
|
||||
std::vector<TiledNode> windows;
|
||||
std::vector<std::shared_ptr<TilingRegion>> sub_regions;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //MIRCOMPOSITOR_TILING_REGION_H
|
Loading…
Reference in New Issue
Block a user