commit 67fc7bc8bb2b264864d6b6c1ecfd8c870311b8d4
parent deb1f490ba502a6a56a59cace8f57c2d0c445412
Author: deurzen <max@deurzen.net>
Date: Sun, 5 Jun 2022 17:48:12 +0200
implements track layer cycling
Diffstat:
12 files changed, 444 insertions(+), 124 deletions(-)
diff --git a/include/kranewl/cycle.hh b/include/kranewl/cycle.hh
@@ -261,8 +261,8 @@ public:
void reverse();
void rotate(Direction);
void rotate_range(Direction, Index, Index);
- std::optional<T> cycle_active(Direction);
- std::optional<T> drag_active(Direction);
+ std::pair<std::optional<T>, std::optional<T>> cycle_active(Direction);
+ std::pair<std::optional<T>, std::optional<T>> drag_active(Direction);
template<typename UnaryPredicate>
std::optional<T>
@@ -406,3 +406,6 @@ private:
HistoryStack<T> m_stack;
};
+
+template<typename T>
+using Cycle_ptr = Cycle<T>*;
diff --git a/include/kranewl/cycle.t.hh b/include/kranewl/cycle.t.hh
@@ -497,16 +497,23 @@ Cycle<T>::rotate_range(Direction direction, Index begin, Index end)
}
template <typename T>
-std::optional<T>
+std::pair<std::optional<T>, std::optional<T>>
Cycle<T>::cycle_active(Direction direction)
{
push_active_to_stack();
+
+ std::optional<T> prev_active = active_element();
m_index = next_index(direction);
- return active_element();
+ std::optional<T> next_active = active_element();
+
+ return std::pair{
+ prev_active,
+ next_active
+ };
}
template <typename T>
-std::optional<T>
+std::pair<std::optional<T>, std::optional<T>>
Cycle<T>::drag_active(Direction direction)
{
Index index = next_index(direction);
diff --git a/include/kranewl/input/key-bindings.hh b/include/kranewl/input/key-bindings.hh
@@ -97,7 +97,7 @@ static const KeyBindings key_bindings = {
.action = [](Model& model) {
View_ptr focus = model.focused_view();
- if (focus && model.is_free(focus))
+ if (focus && focus->free())
model.nudge_focus(Edge::Left, 50);
else
model.shuffle_main(Direction::Backward);
@@ -110,7 +110,7 @@ static const KeyBindings key_bindings = {
.action = [](Model& model) {
View_ptr focus = model.focused_view();
- if (focus && model.is_free(focus))
+ if (focus && focus->free())
model.nudge_focus(Edge::Bottom, 50);
else
model.shuffle_stack(Direction::Forward);
@@ -123,7 +123,7 @@ static const KeyBindings key_bindings = {
.action = [](Model& model) {
View_ptr focus = model.focused_view();
- if (focus && model.is_free(focus))
+ if (focus && focus->free())
model.nudge_focus(Edge::Top, 50);
else
model.shuffle_stack(Direction::Backward);
@@ -136,7 +136,7 @@ static const KeyBindings key_bindings = {
.action = [](Model& model) {
View_ptr focus = model.focused_view();
- if (focus && model.is_free(focus))
+ if (focus && focus->free())
model.nudge_focus(Edge::Right, 50);
else
model.shuffle_main(Direction::Forward);
@@ -218,28 +218,34 @@ static const KeyBindings key_bindings = {
},
{ { XKB_KEY_j, MODKEY },
{
- .action = CALL(cycle_track(Direction::Forward)),
+ .action = CALL(cycle_focus_track(Direction::Forward)),
.repeatable = true
}
},
{ { XKB_KEY_k, MODKEY },
{
- .action = CALL(cycle_track(Direction::Backward)),
+ .action = CALL(cycle_focus_track(Direction::Backward)),
.repeatable = true
}
},
{ { XKB_KEY_J, MODKEY | WLR_MODIFIER_SHIFT },
{
- .action = CALL(drag_focus(Direction::Forward)),
+ .action = CALL(drag_focus_track(Direction::Forward)),
.repeatable = true
}
},
{ { XKB_KEY_K, MODKEY | WLR_MODIFIER_SHIFT },
{
- .action = CALL(drag_focus(Direction::Backward)),
+ .action = CALL(drag_focus_track(Direction::Backward)),
.repeatable = true
}
},
+{ { XKB_KEY_a, MODKEY },
+ {
+ .action = CALL(cycle_track(Direction::Forward)),
+ .repeatable = false
+ }
+},
{ { XKB_KEY_r, MODKEY },
{
.action = CALL(reverse_views()),
diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh
@@ -90,6 +90,7 @@ public:
void focus_view(View_ptr);
void refocus();
void place_view(Placement&);
+ void relayer_view(View_ptr, SceneLayer);
bool view_matches_search(View_ptr, SearchSelector const&) const;
View_ptr search_view(SearchSelector const&);
@@ -101,14 +102,19 @@ public:
void abort_cursor_interactive();
void cycle_focus(Direction);
- void cycle_track(Direction);
+ void cycle_focus_track(Direction);
void drag_focus(Direction);
- void drag_track(Direction);
+ void drag_focus_track(Direction);
+
+ void toggle_track();
+ void activate_track(SceneLayer);
+ void cycle_track(Direction);
void sync_focus();
void relayer_views(Workspace_ptr);
void relayer_views(Context_ptr);
void relayer_views(Output_ptr);
+ void move_view_to_track(View_ptr, SceneLayer);
void reverse_views();
void rotate_views(Direction);
@@ -205,9 +211,6 @@ public:
void set_focus_follows_cursor(Toggle, Workspace_ptr);
void set_focus_follows_cursor(Toggle, Context_ptr);
- bool is_free(View_ptr) const;
- bool belongs_to_track(View_ptr) const;
-
void spawn_external(std::string&&) const;
Output_ptr mp_output;
@@ -238,8 +241,6 @@ private:
View_ptr mp_focus;
View_ptr mp_jumped_from;
- SceneLayer m_current_track;
-
std::vector<std::tuple<SearchSelector_ptr, Rules>> m_default_rules;
const KeyBindings m_key_bindings;
diff --git a/include/kranewl/tree/view.hh b/include/kranewl/tree/view.hh
@@ -102,6 +102,7 @@ typedef struct View : public Node {
bool focused() const { return m_focused; }
bool mapped() const { return m_mapped; }
bool managed() const { return m_managed; }
+ bool free() const { return m_free; }
bool urgent() const { return m_urgent; }
bool floating() const { return m_floating; }
bool fullscreen() const { return m_fullscreen; }
@@ -116,6 +117,7 @@ typedef struct View : public Node {
void set_focused(bool);
void set_mapped(bool);
void set_managed(bool);
+ void set_free(bool);
void set_urgent(bool);
void set_floating(bool);
void set_fullscreen(bool);
@@ -127,6 +129,8 @@ typedef struct View : public Node {
void set_iconified(bool);
void set_disowned(bool);
+ bool belongs_to_active_track() const;
+
std::chrono::time_point<std::chrono::steady_clock> last_focused() const;
std::chrono::time_point<std::chrono::steady_clock> last_touched() const;
std::chrono::time_point<std::chrono::steady_clock> managed_since() const;
@@ -207,6 +211,7 @@ private:
bool m_focused;
bool m_mapped;
bool m_managed;
+ bool m_free;
bool m_urgent;
bool m_floating;
bool m_fullscreen;
diff --git a/include/kranewl/workspace.hh b/include/kranewl/workspace.hh
@@ -5,6 +5,7 @@
#include <kranewl/geometry.hh>
#include <kranewl/layout.hh>
#include <kranewl/placement.hh>
+#include <kranewl/scene-layer.hh>
#include <kranewl/util.hh>
typedef struct View* View_ptr;
@@ -73,18 +74,8 @@ public:
};
- Workspace(Index index, std::string name, Context_ptr context)
- : m_index(index),
- m_name(name),
- m_layout_handler({}),
- mp_context(context),
- mp_active(nullptr),
- m_views({}, true),
- m_free_views({}, true),
- m_iconified_views({}, true),
- m_disowned_views({}, true),
- m_focus_follows_cursor(true)
- {}
+ Workspace(Index, std::string, Context_ptr);
+ ~Workspace();
bool empty() const;
bool contains(View_ptr) const;
@@ -100,6 +91,7 @@ public:
bool layout_wraps() const;
Index size() const;
+ Index track_size() const;
Index length() const;
int main_count() const;
@@ -111,6 +103,15 @@ public:
std::string identifier() const;
View_ptr active() const;
+ SceneLayer track_layer() const;
+ void activate_track(SceneLayer);
+ void toggle_track();
+ void cycle_track(Direction);
+
+ void add_view_to_track(View_ptr, SceneLayer);
+ void remove_view_from_track(View_ptr, SceneLayer);
+ void change_view_track(View_ptr, SceneLayer);
+
Cycle<View_ptr> const& views() const;
std::vector<View_ptr> stack_after_focus() const;
@@ -118,8 +119,10 @@ public:
View_ptr prev_view() const;
std::optional<View_ptr> find_view(ViewSelector const&) const;
- void cycle(Direction);
- void drag(Direction);
+ std::pair<std::optional<View_ptr>, std::optional<View_ptr>> cycle(Direction);
+ std::pair<std::optional<View_ptr>, std::optional<View_ptr>> cycle_focus_track(Direction);
+ std::pair<std::optional<View_ptr>, std::optional<View_ptr>> drag(Direction);
+ std::pair<std::optional<View_ptr>, std::optional<View_ptr>> drag_focus_track(Direction);
template<typename UnaryPredicate>
void
@@ -243,6 +246,12 @@ private:
View_ptr mp_active;
Cycle<View_ptr> m_views;
+
+ SceneLayer m_track_layer;
+ SceneLayer m_prev_track_layer;
+ const std::array<Cycle_ptr<View_ptr>, 8> m_tracks;
+ Cycle_ptr<View_ptr> mp_track;
+
Cycle<View_ptr> m_free_views;
Cycle<View_ptr> m_iconified_views;
Cycle<View_ptr> m_disowned_views;
diff --git a/src/kranewl/input/cursor.cc b/src/kranewl/input/cursor.cc
@@ -388,7 +388,7 @@ cursor_motion_to_client(
cursor->mp_seat->mp_wlr_seat
);
- if (view && view != prev_view && cursor->mp_model->belongs_to_track(view)
+ if (view && view != prev_view && view->belongs_to_active_track()
&& view->mp_workspace->focus_follows_cursor() && view->managed())
{
cursor->mp_seat->mp_model->focus_view(view);
@@ -558,7 +558,7 @@ Cursor::handle_cursor_button(struct wl_listener* listener, void* data)
return;
if (view && (!cursor->mp_model->mp_workspace->focus_follows_cursor()
- || !cursor->mp_model->belongs_to_track(view)))
+ || !view->belongs_to_active_track()))
{
if (!view->focused() && view->managed())
cursor->mp_seat->mp_model->focus_view(view);
diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc
@@ -56,7 +56,6 @@ Model::Model(Config const& config)
m_sticky_views{},
mp_focus(nullptr),
mp_jumped_from(nullptr),
- m_current_track(SceneLayer::SCENE_LAYER_TILE),
m_key_bindings(Bindings::key_bindings),
m_cursor_bindings(Bindings::cursor_bindings)
{
@@ -310,10 +309,11 @@ Model::focus_view(View_ptr view)
view->set_urgent(false);
mp_focus = view;
- m_current_track = view->scene_layer();
if (mp_workspace->layout_is_persistent() || mp_workspace->layout_is_single())
apply_layout(mp_workspace);
+
+ view->mp_workspace->activate_track(view->scene_layer());
}
void
@@ -358,13 +358,17 @@ Model::place_view(Placement& placement)
switch (placement.method) {
case Placement::PlacementMethod::Free:
{
+ view->set_free(true);
view->set_free_decoration(placement.decoration);
+ move_view_to_track(view, SceneLayer::SCENE_LAYER_FREE);
break;
}
case Placement::PlacementMethod::Tile:
{
+ view->set_free(false);
view->set_free_decoration(FREE_DECORATION);
view->set_tile_decoration(placement.decoration);
+ move_view_to_track(view, SceneLayer::SCENE_LAYER_TILE);
break;
}
}
@@ -376,15 +380,19 @@ Model::place_view(Placement& placement)
switch (placement.method) {
case Placement::PlacementMethod::Free:
{
+ view->set_free(true);
view->set_free_decoration(placement.decoration);
view->set_free_region(*placement.region);
+ move_view_to_track(view, SceneLayer::SCENE_LAYER_FREE);
break;
}
case Placement::PlacementMethod::Tile:
{
+ view->set_free(false);
view->set_free_decoration(FREE_DECORATION);
view->set_tile_decoration(placement.decoration);
view->set_tile_region(*placement.region);
+ move_view_to_track(view, SceneLayer::SCENE_LAYER_TILE);
break;
}
}
@@ -508,7 +516,7 @@ Model::cursor_interactive(Cursor::Mode mode, View_ptr view)
{
TRACE();
- if (is_free(view))
+ if (view->free())
mp_server->mp_seat->mp_cursor->initiate_cursor_interactive(mode, view);
}
@@ -545,20 +553,20 @@ void
Model::relayer_views(Workspace_ptr workspace)
{
for (View_ptr view : *workspace) {
- if (is_free(view)) {
+ if (view->free()) {
if (view->scene_layer() != SceneLayer::SCENE_LAYER_FREE)
- view->relayer(SceneLayer::SCENE_LAYER_FREE);
+ move_view_to_track(view, SceneLayer::SCENE_LAYER_FREE);
view->lower();
} else {
if (view->scene_layer() != SceneLayer::SCENE_LAYER_TILE) {
- view->relayer(SceneLayer::SCENE_LAYER_TILE);
+ move_view_to_track(view, SceneLayer::SCENE_LAYER_TILE);
}
}
}
if (mp_focus) {
mp_focus->raise();
- m_current_track = mp_focus->scene_layer();
+ mp_focus->mp_workspace->activate_track(mp_focus->scene_layer());
}
}
@@ -575,6 +583,15 @@ Model::relayer_views(Output_ptr output)
}
void
+Model::move_view_to_track(View_ptr view, SceneLayer layer)
+{
+ TRACE();
+
+ view->mp_workspace->change_view_track(view, layer);
+ view->relayer(layer);
+}
+
+void
Model::cycle_focus(Direction direction)
{
TRACE();
@@ -587,13 +604,14 @@ Model::cycle_focus(Direction direction)
}
void
-Model::cycle_track(Direction direction)
+Model::cycle_focus_track(Direction direction)
{
TRACE();
- mp_workspace->cycle_with_condition(direction, [this](View_ptr view) {
- return belongs_to_track(view);
- });
+ if (mp_workspace->track_size() <= 1)
+ return;
+
+ mp_workspace->cycle_focus_track(direction);
sync_focus();
}
@@ -611,21 +629,51 @@ Model::drag_focus(Direction direction)
}
void
-Model::drag_track(Direction direction)
+Model::drag_focus_track(Direction direction)
{
TRACE();
- if (mp_workspace->size() <= 1)
+ if (mp_workspace->track_size() <= 1)
return;
- mp_workspace->drag_with_condition(direction, [this](View_ptr view) {
- return belongs_to_track(view);
- });
+ auto [prev,next] = mp_workspace->drag_focus_track(direction);
+
+ if (prev && next) {
+ Region region_prev = (*prev)->free_region();
+ Region region_next = (*next)->free_region();
+ (*prev)->set_free_region(region_next);
+ (*next)->set_free_region(region_prev);
+ }
+
sync_focus();
apply_layout(mp_workspace);
}
void
+Model::toggle_track()
+{
+ TRACE();
+ mp_workspace->toggle_track();
+ sync_focus();
+}
+
+void
+Model::activate_track(SceneLayer layer)
+{
+ TRACE();
+ mp_workspace->activate_track(layer);
+ sync_focus();
+}
+
+void
+Model::cycle_track(Direction direction)
+{
+ TRACE();
+ mp_workspace->cycle_track(direction);
+ sync_focus();
+}
+
+void
Model::reverse_views()
{
TRACE();
@@ -1163,8 +1211,8 @@ Model::toggle_layout()
TRACE();
mp_workspace->toggle_layout();
- relayer_views(mp_workspace);
apply_layout(mp_workspace);
+ relayer_views(mp_workspace);
}
void
@@ -1173,8 +1221,8 @@ Model::set_layout(LayoutHandler::LayoutKind layout)
TRACE();
mp_workspace->set_layout(layout);
- relayer_views(mp_workspace);
apply_layout(mp_workspace);
+ relayer_views(mp_workspace);
}
void
@@ -1195,7 +1243,7 @@ Model::set_layout_retain_region(LayoutHandler::LayoutKind layout)
views.end(),
std::back_inserter(regions),
[=,this](View_ptr view) -> Region {
- if (is_free(view))
+ if (view->free())
return view->free_region();
else
return view->tile_region();
@@ -1390,9 +1438,10 @@ Model::set_floating_view(Toggle toggle, View_ptr view)
}
apply_layout(view->mp_workspace);
+ move_view_to_track(view, view->scene_layer());
if (view == mp_focus)
- m_current_track = view->scene_layer();
+ view->mp_workspace->activate_track(view->scene_layer());
}
void
@@ -1453,7 +1502,8 @@ Model::set_fullscreen_view(Toggle toggle, View_ptr view)
apply_layout(workspace);
if (view == mp_focus)
- m_current_track = view->scene_layer();
+ // TODO: separate layer?
+ move_view_to_track(view, SceneLayer::SCENE_LAYER_OVERLAY);
}
void
@@ -1706,7 +1756,7 @@ Model::center_view(View_ptr view)
{
TRACE();
- if (!is_free(view) || !view->mp_output)
+ if (!view->free() || !view->mp_output)
return;
view->center();
@@ -1735,7 +1785,7 @@ Model::nudge_view(Edge edge, Util::Change<std::size_t> change, View_ptr view)
{
TRACE();
- if (!is_free(view))
+ if (!view->free())
return;
Region region = view->free_region();
@@ -1786,7 +1836,7 @@ Model::stretch_view(Edge edge, Util::Change<int> change, View_ptr view)
{
TRACE();
- if (!is_free(view))
+ if (!view->free())
return;
Decoration decoration = view->free_decoration();
@@ -1882,7 +1932,7 @@ Model::inflate_view(Util::Change<int> change, View_ptr view)
{
TRACE();
- if (!is_free(view))
+ if (!view->free())
return;
Decoration decoration = view->free_decoration();
@@ -1955,7 +2005,7 @@ Model::snap_view(View_ptr view, uint32_t edges)
{
TRACE();
- if (!is_free(view))
+ if (!view->free())
return;
Region region = view->free_region();
@@ -2088,23 +2138,23 @@ Model::initialize_view(View_ptr view, Workspace_ptr workspace)
if (rules.to_workspace && *rules.to_workspace < context->workspaces().size())
workspace = (*context)[*rules.to_workspace];
- move_view_to_workspace(view, workspace);
+ if (rules.do_float) {
+ view->set_floating(*rules.do_float);
+ view->relayer(*rules.do_float
+ ? SceneLayer::SCENE_LAYER_FREE
+ : SceneLayer::SCENE_LAYER_TILE
+ );
+ } else
+ view->relayer(SceneLayer::SCENE_LAYER_TILE);
- view->relayer(
- is_free(view)
- ? SCENE_LAYER_FREE
- : SCENE_LAYER_TILE
- );
+ move_view_to_workspace(view, workspace);
- if (rules.do_float)
- set_floating_view(*rules.do_float ? Toggle::On : Toggle::Off, view);
if (rules.snap_edges)
snap_view(view, *rules.snap_edges);
if (rules.do_fullscreen)
set_fullscreen_view(*rules.do_fullscreen ? Toggle::On : Toggle::Off, view);
- if (view == mp_focus)
- m_current_track = view->scene_layer();
+ move_view_to_track(view, view->scene_layer());
}
XDGView_ptr
@@ -2248,23 +2298,6 @@ Model::register_layer(Layer_ptr layer)
spdlog::info("Registered layer {}", layer->uid_formatted());
}
-bool
-Model::is_free(View_ptr view) const
-{
- return View::is_free(view)
- || ((!view->fullscreen() || view->contained())
- && (view->sticky()
- ? mp_workspace
- : view->mp_workspace
- )->layout_is_free());
-}
-
-bool
-Model::belongs_to_track(View_ptr view) const
-{
- return m_current_track == view->scene_layer();
-}
-
void
Model::spawn_external(std::string&& command) const
{
diff --git a/src/kranewl/tree/output.cc b/src/kranewl/tree/output.cc
@@ -105,8 +105,11 @@ Output::handle_present(struct wl_listener* listener, void*)
View_ptr view_under_cursor
= output->mp_seat->mp_cursor->view_under_cursor();
- if (view_under_cursor && view_under_cursor->managed())
+ if (view_under_cursor && view_under_cursor->managed()
+ && view_under_cursor->belongs_to_active_track())
+ {
output->mp_model->focus_view(view_under_cursor);
+ }
}
output->m_cursor_focus_on_present = false;
diff --git a/src/kranewl/tree/view.cc b/src/kranewl/tree/view.cc
@@ -56,6 +56,7 @@ View::View(
m_focused(false),
m_mapped(false),
m_managed(true),
+ m_free(false),
m_urgent(false),
m_floating(false),
m_fullscreen(false),
@@ -176,6 +177,12 @@ View::set_managed(bool managed)
}
void
+View::set_free(bool free)
+{
+ m_free = free;
+}
+
+void
View::set_urgent(bool urgent)
{
m_urgent = urgent;
@@ -265,6 +272,12 @@ View::set_disowned(bool disowned)
}
}
+bool
+View::belongs_to_active_track() const
+{
+ return m_scene_layer == mp_workspace->track_layer();
+}
+
std::chrono::time_point<std::chrono::steady_clock>
View::last_focused() const
{
@@ -321,7 +334,7 @@ View::tile(Toggle toggle)
return;
set_floating(false);
- if (!mp_model->is_free(this))
+ if (!m_free)
relayer(SCENE_LAYER_TILE);
break;
@@ -332,7 +345,7 @@ View::tile(Toggle toggle)
return;
set_floating(true);
- if (mp_model->is_free(this))
+ if (m_free)
relayer(SCENE_LAYER_FREE);
break;
@@ -357,7 +370,6 @@ View::relayer(SceneLayer layer)
return;
m_scene_layer = layer;
-
wlr_scene_node_reparent(
mp_scene,
mp_server->m_scene_layers[layer]
diff --git a/src/kranewl/tree/xwayland-view.cc b/src/kranewl/tree/xwayland-view.cc
@@ -431,7 +431,7 @@ XWaylandView::handle_request_configure(struct wl_listener* listener, void* data)
return;
}
- if (view->mp_model->is_free(view)) {
+ if (view->free()) {
view->set_preferred_dim(Dim{
.w = event->width,
.h = event->height,
@@ -490,7 +490,7 @@ XWaylandView::handle_request_move(struct wl_listener* listener, void*)
if (!xwayland_surface->mapped)
return;
- if (!view->mp_model->is_free(view))
+ if (!view->free())
return;
view->mp_model->cursor_interactive(Cursor::Mode::Move, view);
@@ -504,10 +504,7 @@ XWaylandView::handle_request_resize(struct wl_listener* listener, void* data)
XWaylandView_ptr view = wl_container_of(listener, view, ml_request_resize);
struct wlr_xwayland_surface* xwayland_surface = view->mp_wlr_xwayland_surface;
- if (!xwayland_surface->mapped)
- return;
-
- if (!view->mp_model->is_free(view))
+ if (!xwayland_surface->mapped || !view->free())
return;
struct wlr_xwayland_resize_event* event
diff --git a/src/kranewl/workspace.cc b/src/kranewl/workspace.cc
@@ -10,6 +10,35 @@
#include <algorithm>
#include <optional>
+Workspace::Workspace(Index index, std::string name, Context_ptr context)
+ : m_index(index),
+ m_name(name),
+ m_layout_handler({}),
+ mp_context(context),
+ mp_active(nullptr),
+ m_views({}, true),
+ m_track_layer(SceneLayer::SCENE_LAYER_FREE),
+ m_prev_track_layer(SceneLayer::SCENE_LAYER_TILE),
+ m_tracks({
+ new Cycle<View_ptr>{{}, false}, // SceneLayer::SCENE_LAYER_BACKGROUND
+ new Cycle<View_ptr>{{}, true}, // SceneLayer::SCENE_LAYER_BOTTOM
+ new Cycle<View_ptr>{{}, true}, // SceneLayer::SCENE_LAYER_TILE
+ new Cycle<View_ptr>{{}, true}, // SceneLayer::SCENE_LAYER_FREE
+ new Cycle<View_ptr>{{}, true}, // SceneLayer::SCENE_LAYER_TOP
+ new Cycle<View_ptr>{{}, true}, // SceneLayer::SCENE_LAYER_OVERLAY
+ new Cycle<View_ptr>{{}, false}, // SceneLayer::SCENE_LAYER_POPUP
+ new Cycle<View_ptr>{{}, false}, // SceneLayer::SCENE_LAYER_NOFOCUS
+ }),
+ mp_track(m_tracks[SceneLayer::SCENE_LAYER_FREE]),
+ m_free_views({}, true),
+ m_iconified_views({}, true),
+ m_disowned_views({}, true),
+ m_focus_follows_cursor(true)
+{}
+
+Workspace::~Workspace()
+{}
+
bool
Workspace::empty() const
{
@@ -77,6 +106,12 @@ Workspace::size() const
}
std::size_t
+Workspace::track_size() const
+{
+ return mp_track->size();
+}
+
+std::size_t
Workspace::length() const
{
return m_views.length();
@@ -134,23 +169,112 @@ Workspace::active() const
}
-Cycle<View_ptr> const&
-Workspace::views() const
+SceneLayer
+Workspace::track_layer() const
{
- return m_views;
+ return m_track_layer;
+}
+
+void
+Workspace::activate_track(SceneLayer layer)
+{
+ TRACE();
+
+ mp_track = m_tracks[layer];
+ mp_active = mp_track->active_element().value_or(nullptr);
+ m_prev_track_layer = m_track_layer;
+ m_track_layer = layer;
+
+ if (mp_active)
+ m_views.activate_element(mp_active);
+}
+
+void
+Workspace::toggle_track()
+{
+ TRACE();
+ activate_track(m_prev_track_layer);
+}
+
+void
+Workspace::cycle_track(Direction direction)
+{
+ TRACE();
+
+ int last_index, cycles;
+ last_index = cycles = Util::last_index(m_tracks);
+
+ do {
+ switch (direction) {
+ case Direction::Backward:
+ m_track_layer = static_cast<SceneLayer>(
+ m_track_layer == 0
+ ? last_index
+ : m_track_layer - 1
+ );
+ break;
+ case Direction::Forward:
+ m_track_layer = static_cast<SceneLayer>(
+ m_track_layer == last_index
+ ? 0
+ : m_track_layer + 1
+ );
+ break;
+ default: return;
+ }
+ } while (m_tracks[m_track_layer]->empty() && cycles--);
+
+ activate_track(m_track_layer);
+}
+
+void
+Workspace::add_view_to_track(View_ptr view, SceneLayer layer)
+{
+ TRACE();
+
+ if (m_tracks[layer]->contains(view))
+ return;
+
+ m_tracks[layer]->insert_at_back(view);
+
+ if (layer == m_track_layer)
+ mp_active = view;
}
-std::vector<View_ptr>
-Workspace::stack_after_focus() const
+void
+Workspace::remove_view_from_track(View_ptr view, SceneLayer layer)
{
- std::vector<View_ptr> stack = m_views.stack();
+ TRACE();
+
+ m_tracks[layer]->remove_element(view);
- if (mp_active) {
- Util::erase_remove(stack, mp_active);
- stack.push_back(mp_active);
+ if (layer == m_track_layer) {
+ mp_active = m_tracks[layer]->active_element().value_or(nullptr);
+
+ if (mp_active)
+ m_views.activate_element(mp_active);
+ else
+ cycle_track(Direction::Forward);
}
+}
- return stack;
+void
+Workspace::change_view_track(View_ptr view, SceneLayer layer)
+{
+ TRACE();
+
+ if (view->scene_layer() == layer)
+ return;
+
+ remove_view_from_track(view, view->scene_layer());
+ add_view_to_track(view, layer);
+}
+
+
+Cycle<View_ptr> const&
+Workspace::views() const
+{
+ return m_views;
}
View_ptr
@@ -159,7 +283,7 @@ Workspace::next_view() const
std::optional<View_ptr> view
= m_views.next_element(Direction::Forward);
- if (view != mp_active)
+ if (view && *view != mp_active)
return *view;
return nullptr;
@@ -171,7 +295,7 @@ Workspace::prev_view() const
std::optional<View_ptr> view
= m_views.next_element(Direction::Backward);
- if (view != mp_active)
+ if (view && *view != mp_active)
return *view;
return nullptr;
@@ -180,6 +304,8 @@ Workspace::prev_view() const
std::optional<View_ptr>
Workspace::find_view(ViewSelector const& selector) const
{
+ TRACE();
+
if (m_views.empty())
return std::nullopt;
@@ -215,57 +341,127 @@ Workspace::find_view(ViewSelector const& selector) const
return std::nullopt;
}
-void
+std::pair<std::optional<View_ptr>, std::optional<View_ptr>>
Workspace::cycle(Direction direction)
{
+ TRACE();
+
switch (direction) {
case Direction::Forward:
{
if (!layout_wraps() && m_views.active_index() == m_views.last_index())
- return;
-
+ return std::pair{std::nullopt, std::nullopt};
break;
}
case Direction::Backward:
{
if (!layout_wraps() && m_views.active_index() == 0)
- return;
+ return std::pair{std::nullopt, std::nullopt};
+ break;
+ }
+ }
+ std::pair<std::optional<View_ptr>, std::optional<View_ptr>> views
+ = m_views.cycle_active(direction);
+ mp_active = views.second.value_or(nullptr);
+
+ return views;
+}
+
+std::pair<std::optional<View_ptr>, std::optional<View_ptr>>
+Workspace::cycle_focus_track(Direction direction)
+{
+ TRACE();
+
+ switch (direction) {
+ case Direction::Forward:
+ {
+ if (!layout_wraps() && mp_track->active_index() == mp_track->last_index())
+ return std::pair{std::nullopt, std::nullopt};
+ break;
+ }
+ case Direction::Backward:
+ {
+ if (!layout_wraps() && mp_track->active_index() == 0)
+ return std::pair{std::nullopt, std::nullopt};
break;
}
}
- m_views.cycle_active(direction);
- mp_active = m_views.active_element().value_or(nullptr);
+ std::pair<std::optional<View_ptr>, std::optional<View_ptr>> views
+ = mp_track->cycle_active(direction);
+
+ mp_active = views.second.value_or(nullptr);
+ if (mp_active)
+ m_views.activate_element(mp_active);
+
+ return views;
}
-void
+std::pair<std::optional<View_ptr>, std::optional<View_ptr>>
Workspace::drag(Direction direction)
{
+ TRACE();
+
switch (direction) {
case Direction::Forward:
{
if (!layout_wraps() && m_views.active_index() == m_views.last_index())
- return;
-
+ return std::pair{std::nullopt, std::nullopt};
break;
}
case Direction::Backward:
{
if (!layout_wraps() && m_views.active_index() == 0)
- return;
+ return std::pair{std::nullopt, std::nullopt};
+ break;
+ }
+ }
+
+ std::pair<std::optional<View_ptr>, std::optional<View_ptr>> views
+ = m_views.drag_active(direction);
+ mp_active = views.second.value_or(nullptr);
+
+ return views;
+}
+std::pair<std::optional<View_ptr>, std::optional<View_ptr>>
+Workspace::drag_focus_track(Direction direction)
+{
+ TRACE();
+
+ switch (direction) {
+ case Direction::Forward:
+ {
+ if (!layout_wraps() && mp_track->active_index() == mp_track->last_index())
+ return std::pair{std::nullopt, std::nullopt};
+ break;
+ }
+ case Direction::Backward:
+ {
+ if (!layout_wraps() && mp_track->active_index() == 0)
+ return std::pair{std::nullopt, std::nullopt};
break;
}
}
- m_views.drag_active(direction);
- mp_active = m_views.active_element().value_or(nullptr);
+ std::pair<std::optional<View_ptr>, std::optional<View_ptr>> views
+ = mp_track->drag_active(direction);
+
+ if (views.first && views.second)
+ m_views.swap_elements(*views.first, *views.second);
+
+ mp_active = views.second.value_or(nullptr);
+ if (mp_active)
+ m_views.activate_element(mp_active);
+
+ return views;
}
void
Workspace::reverse()
{
+ TRACE();
m_views.reverse();
mp_active = m_views.active_element().value_or(nullptr);
}
@@ -273,6 +469,7 @@ Workspace::reverse()
void
Workspace::rotate(Direction direction)
{
+ TRACE();
m_views.rotate(direction);
mp_active = m_views.active_element().value_or(nullptr);
}
@@ -280,6 +477,8 @@ Workspace::rotate(Direction direction)
void
Workspace::shuffle_main(Direction direction)
{
+ TRACE();
+
m_views.rotate_range(
direction,
0,
@@ -292,6 +491,8 @@ Workspace::shuffle_main(Direction direction)
void
Workspace::shuffle_stack(Direction direction)
{
+ TRACE();
+
m_views.rotate_range(
direction,
static_cast<Index>(m_layout_handler.main_count()),
@@ -304,8 +505,11 @@ Workspace::shuffle_stack(Direction direction)
void
Workspace::activate_view(View_ptr view)
{
+ TRACE();
+
if (m_views.contains(view)) {
m_views.activate_element(view);
+ m_tracks[view->scene_layer()]->activate_element(view);
mp_active = view;
}
}
@@ -313,23 +517,32 @@ Workspace::activate_view(View_ptr view)
void
Workspace::add_view(View_ptr view)
{
+ TRACE();
+
if (m_views.contains(view))
return;
m_views.insert_at_back(view);
+ m_tracks[view->scene_layer()]->insert_at_back(view);
+
+ m_track_layer = view->scene_layer();
mp_active = view;
}
void
Workspace::remove_view(View_ptr view)
{
+ TRACE();
+
m_views.remove_element(view);
- mp_active = m_views.active_element().value_or(nullptr);
+ remove_view_from_track(view, view->scene_layer());
}
void
Workspace::replace_view(View_ptr view, View_ptr replacement)
{
+ TRACE();
+
bool was_active
= m_views.active_element().value_or(nullptr) == view;
@@ -344,6 +557,8 @@ Workspace::replace_view(View_ptr view, View_ptr replacement)
void
Workspace::view_to_icon(View_ptr view)
{
+ TRACE();
+
if (m_views.remove_element(view))
m_iconified_views.insert_at_back(view);
@@ -353,6 +568,8 @@ Workspace::view_to_icon(View_ptr view)
void
Workspace::icon_to_view(View_ptr view)
{
+ TRACE();
+
if (m_iconified_views.remove_element(view))
m_views.insert_at_back(view);
@@ -362,6 +579,8 @@ Workspace::icon_to_view(View_ptr view)
void
Workspace::add_icon(View_ptr view)
{
+ TRACE();
+
if (m_iconified_views.contains(view))
return;
@@ -371,12 +590,15 @@ Workspace::add_icon(View_ptr view)
void
Workspace::remove_icon(View_ptr view)
{
+ TRACE();
m_iconified_views.remove_element(view);
}
std::optional<View_ptr>
Workspace::pop_icon()
{
+ TRACE();
+
return m_iconified_views.empty()
? std::nullopt
: std::optional(m_iconified_views[m_iconified_views.size() - 1]);
@@ -385,6 +607,8 @@ Workspace::pop_icon()
void
Workspace::view_to_disowned(View_ptr view)
{
+ TRACE();
+
if (m_views.remove_element(view))
m_disowned_views.insert_at_back(view);
@@ -394,6 +618,8 @@ Workspace::view_to_disowned(View_ptr view)
void
Workspace::disowned_to_view(View_ptr view)
{
+ TRACE();
+
if (m_disowned_views.remove_element(view))
m_views.insert_at_back(view);
@@ -403,6 +629,8 @@ Workspace::disowned_to_view(View_ptr view)
void
Workspace::add_disowned(View_ptr view)
{
+ TRACE();
+
if (m_disowned_views.contains(view))
return;
@@ -412,36 +640,42 @@ Workspace::add_disowned(View_ptr view)
void
Workspace::remove_disowned(View_ptr view)
{
+ TRACE();
m_disowned_views.remove_element(view);
}
void
Workspace::save_layout(int number) const
{
+ TRACE();
m_layout_handler.save_layout(number);
}
void
Workspace::load_layout(int number)
{
+ TRACE();
m_layout_handler.load_layout(number);
}
void
Workspace::toggle_layout_data()
{
+ TRACE();
m_layout_handler.set_prev_layout_data();
}
void
Workspace::cycle_layout_data(Direction direction)
{
+ TRACE();
m_layout_handler.cycle_layout_data(direction);
}
void
Workspace::copy_data_from_prev_layout()
{
+ TRACE();
m_layout_handler.copy_data_from_prev_layout();
}
@@ -449,48 +683,56 @@ Workspace::copy_data_from_prev_layout()
void
Workspace::change_gap_size(Util::Change<int> change)
{
+ TRACE();
m_layout_handler.change_gap_size(change);
}
void
Workspace::change_main_count(Util::Change<int> change)
{
+ TRACE();
m_layout_handler.change_main_count(change);
}
void
Workspace::change_main_factor(Util::Change<float> change)
{
+ TRACE();
m_layout_handler.change_main_factor(change);
}
void
Workspace::change_margin(Util::Change<int> change)
{
+ TRACE();
m_layout_handler.change_margin(change);
}
void
Workspace::change_margin(Edge edge, Util::Change<int> change)
{
+ TRACE();
m_layout_handler.change_margin(edge, change);
}
void
Workspace::reset_gap_size()
{
+ TRACE();
m_layout_handler.reset_gap_size();
}
void
Workspace::reset_margin()
{
+ TRACE();
m_layout_handler.reset_margin();
}
void
Workspace::reset_layout_data()
{
+ TRACE();
m_layout_handler.reset_layout_data();
}
@@ -498,12 +740,14 @@ Workspace::reset_layout_data()
void
Workspace::toggle_layout()
{
+ TRACE();
m_layout_handler.set_prev_kind();
}
void
Workspace::set_layout(LayoutHandler::LayoutKind layout)
{
+ TRACE();
m_layout_handler.set_kind(layout);
}