1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
#ifndef WF_TILE_PLUGIN_TREE
#define WF_TILE_PLUGIN_TREE
#include "wayfire/signal-definitions.hpp"
#include "wayfire/workspace-set.hpp"
#include <wayfire/util/duration.hpp>
#include <wayfire/view.hpp>
#include <wayfire/option-wrapper.hpp>
#include <wayfire/txn/transaction.hpp>
namespace wf
{
namespace tile
{
/**
* A tree node represents a logical container of views in the tiled part of
* a workspace.
*
* There are two types of nodes:
* 1. View tree nodes, i.e leaves, they contain a single view
* 2. Split tree nodes, they contain at least 1 child view.
*/
struct split_node_t;
struct view_node_t;
struct gap_size_t
{
/* Gap on the left side */
int32_t left = 0;
/* Gap on the right side */
int32_t right = 0;
/* Gap on the top side */
int32_t top = 0;
/* Gap on the bottom side */
int32_t bottom = 0;
/* Gap for internal splits */
int32_t internal = 0;
};
struct tree_node_t
{
/** The node parent, or nullptr if this is the root node */
nonstd::observer_ptr<split_node_t> parent;
/** The children of the node */
std::vector<std::unique_ptr<tree_node_t>> children;
/** The geometry occupied by the node */
wf::geometry_t geometry;
/** Set the geometry available for the node and its subnodes. */
virtual void set_geometry(wf::geometry_t geometry, wf::txn::transaction_uptr& tx);
/** Set the gaps for the node and subnodes. */
virtual void set_gaps(const gap_size_t& gaps) = 0;
gap_size_t get_gaps() const
{
return gaps;
}
virtual ~tree_node_t()
{}
/** Simply dynamic cast this to a split_node_t */
nonstd::observer_ptr<split_node_t> as_split_node();
/** Simply dynamic cast this to a view_node_t */
nonstd::observer_ptr<view_node_t> as_view_node();
protected:
/* Gaps */
gap_size_t gaps;
};
/**
* A node which contains a split can be split either horizontally or vertically
*/
enum split_direction_t
{
SPLIT_HORIZONTAL = 0,
SPLIT_VERTICAL = 1,
};
/*
* Represents a node in the tree which contains at 1 one child node
*/
struct split_node_t : public tree_node_t
{
/**
* Add the given child to the list of children.
*
* The new child will get resized so that its area is at most 1/(N+1) of the
* total node area, where N is the number of children before adding the new
* child.
*
* @param index The index at which to insert the new child, or -1 for
* adding to the end of the child list.
*/
void add_child(std::unique_ptr<tree_node_t> child, wf::txn::transaction_uptr& tx, int index = -1);
/**
* Remove a child from the node, and return its unique_ptr
*/
std::unique_ptr<tree_node_t> remove_child(
nonstd::observer_ptr<tree_node_t> child, wf::txn::transaction_uptr& tx);
/**
* Set the total geometry available to the node. This will recursively
* resize the children nodes, so that they fit inside the new geometry and
* have a size proportional to their old size.
*/
void set_geometry(wf::geometry_t geometry, wf::txn::transaction_uptr& tx) override;
/**
* Set the gaps for the subnodes. The internal gap will override
* the corresponding edges for each child.
*/
void set_gaps(const gap_size_t& gaps) override;
split_node_t(split_direction_t direction);
split_direction_t get_split_direction() const;
private:
split_direction_t split_direction;
/**
* Resize the children so that they fit inside the given
* available_geometry.
*/
void recalculate_children(wf::geometry_t available_geometry, wf::txn::transaction_uptr& tx);
/**
* Calculate the geometry of a child if it has child_size as one
* dimension. Whether this is width/height depends on the node split type.
*
* @param child_pos The position from which the child starts, relative to
* the node itself
*
* @return The geometry of the child, in global coordinates
*/
wf::geometry_t get_child_geometry(int32_t child_pos, int32_t child_size);
/** Return the size of the node in the dimension in which the split happens */
int32_t calculate_splittable() const;
/** Return the size of the geometry in the dimension in which the split
* happens */
int32_t calculate_splittable(wf::geometry_t geometry) const;
};
struct tile_adjust_transformer_signal
{};
/**
* Represents a leaf in the tree, contains a single view
*/
struct view_node_t : public tree_node_t
{
view_node_t(wayfire_toplevel_view view);
~view_node_t();
wayfire_toplevel_view view;
/**
* Set the geometry of the node and the contained view.
*
* Note that the resulting view geometry will not always be equal to the
* geometry of the node. For example, a fullscreen view will always have
* the geometry of the whole output.
*/
void set_geometry(wf::geometry_t geometry, wf::txn::transaction_uptr& tx) override;
/**
* Set the gaps for non-fullscreen mode.
* The gap sizes will be subtracted from all edges of the view's geometry.
*/
void set_gaps(const gap_size_t& gaps) override;
/* Return the tree node corresponding to the view, or nullptr if none */
static nonstd::observer_ptr<view_node_t> get_node(wayfire_view view);
private:
struct scale_transformer_t;
nonstd::observer_ptr<scale_transformer_t> transformer;
wf::signal::connection_t<view_geometry_changed_signal> on_geometry_changed;
wf::signal::connection_t<tile_adjust_transformer_signal> on_adjust_transformer;
wf::option_wrapper_t<wf::animation_description_t> animation_duration{"simple-tile/animation_duration"};
/**
* Check whether the crossfade animation should be enabled for the view
* currently.
*/
bool needs_crossfade();
wf::geometry_t calculate_target_geometry();
void update_transformer();
};
/**
* Flatten the tree as much as possible, i.e remove nodes with only one
* split-node child.
*
* The only exception is "the root", which will always be a split node.
*
* Note: this will potentially invalidate pointers to the tree and modify
* the given parameter.
*
* @return True if the tree has any views in it.
*/
bool flatten_tree(std::unique_ptr<tree_node_t>& root);
/**
* Get the root of the tree which node is part of
*/
nonstd::observer_ptr<split_node_t> get_root(nonstd::observer_ptr<tree_node_t> node);
/**
* Transform coordinates from the tiling trees coordinate system to wset-local coordinates.
*/
wf::geometry_t get_wset_local_coordinates(std::shared_ptr<wf::workspace_set_t> wset, wf::geometry_t g);
wf::point_t get_wset_local_coordinates(std::shared_ptr<wf::workspace_set_t> wset, wf::point_t g);
// Since wsets may not have been attached to any output yet, they may not have a native 'resolution'.
// In this case, we use a default resolution of 1920x1080 in order to layout views. This resolution will be
// automatically adjusted once the wset is added to an output.
static constexpr wf::geometry_t default_output_resolution = {0, 0, 1920, 1080};
}
}
#endif /* end of include guard: WF_TILE_PLUGIN_TREE */
|