kranewl

A wlroots-based dynamic Wayland compositor, written in C++, configurable with Lua
git clone git://git.deurzen.net/kranewl
Log | Files | Refs | LICENSE

commit 94a883640ac427d72fb2fcbef4db4cdf4d6ce6ac
parent 5fa10341abe96782477d69416815a6f0c0e976c5
Author: deurzen <max@deurzen.net>
Date:   Sat,  4 Jun 2022 10:33:27 +0200

implements track-bound cycle and drag

Diffstat:
Minclude/kranewl/cycle.hh | 211++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Minclude/kranewl/input/key-bindings.hh | 4++--
Minclude/kranewl/model.hh | 4+++-
Minclude/kranewl/workspace.hh | 23+++++++++++++++++++++++
Msrc/kranewl/model.cc | 42++++++++++++++++++++++++++++++++++++------
5 files changed, 269 insertions(+), 15 deletions(-)

diff --git a/include/kranewl/cycle.hh b/include/kranewl/cycle.hh @@ -62,6 +62,131 @@ public: Index next_index(Direction) const; Index next_index_from(Index, Direction) const; + template<typename UnaryPredicate> + std::optional<Index> + next_index_with_condition( + Direction direction, + UnaryPredicate predicate + ) const + { + if (m_index >= m_elements.size()) + return std::nullopt; + + switch (direction) { + case Direction::Forward: + { + auto after_it = m_index != last_index() + ? std::find_if( + m_elements.begin() + m_index + 1, + m_elements.end(), + predicate + ) + : m_elements.end(); + + if (after_it != m_elements.end()) + return std::distance(m_elements.begin(), after_it); + + auto before_it = std::find_if( + m_elements.begin(), + m_elements.begin() + m_index, + predicate + ); + + if (before_it != m_elements.begin() + m_index) + return std::distance(m_elements.begin(), before_it); + + break; + } + case Direction::Backward: + { + auto after_it = m_index != 0 + ? std::find_if( + m_elements.rbegin() + (m_elements.size() - m_index - 1) + 1, + m_elements.rend(), + predicate + ) + : m_elements.rend(); + + if (after_it != m_elements.rend()) + return std::distance(after_it, m_elements.rend()) - 1; + + auto before_it = std::find_if( + m_elements.rbegin(), + m_elements.rbegin() + (m_elements.size() - m_index - 1), + predicate + ); + + if (before_it != m_elements.rbegin() + (m_elements.size() - m_index - 1)) + return std::distance(before_it, m_elements.rend()) - 1; + + break; + } + } + + return std::nullopt; + } + + template<typename UnaryPredicate> + std::optional<Index> + next_index_with_condition_from( + Index index, + Direction direction, + UnaryPredicate predicate + ) const + { + if (index >= m_elements.size()) + return std::nullopt; + + switch (direction) { + case Direction::Forward: + { + auto after_it = std::find_if( + m_elements.begin() + index, + m_elements.end(), + predicate + ); + + if (after_it != m_elements.end()) + return std::distance(m_elements.begin(), after_it); + + auto before_it = std::find_if( + m_elements.begin(), + m_elements.begin() + index, + predicate + ); + + if (before_it != m_elements.begin() + index) + return std::distance(m_elements.begin(), before_it); + + break; + } + case Direction::Backward: + { + auto after_it = std::find_if( + m_elements.rbegin() + (m_elements.size() - index - 1), + m_elements.rend(), + predicate + ); + + if (after_it != m_elements.rend()) + return std::distance(m_elements.rbegin(), after_it); + + auto before_it = std::find_if( + m_elements.rbegin(), + m_elements.rbegin() + (m_elements.size() - index - 1), + predicate + ); + + if (before_it != m_elements.rbegin() + (m_elements.size() - index - 1)) + return std::distance(m_elements.rbegin(), before_it); + + break; + } + } + + return std::nullopt; + } + std::optional<Index> index_of_element(const T) const; std::optional<T> next_element(Direction) const; @@ -72,7 +197,8 @@ public: std::optional<T> element_at_back(T) const; template<typename UnaryPredicate> - std::optional<T> first_element_with_condition(UnaryPredicate predicate) + std::optional<T> + first_element_with_condition(UnaryPredicate predicate) { auto it = std::find_if( m_elements.begin(), @@ -83,7 +209,7 @@ public: if (it != m_elements.end()) return *it; - return {}; + return std::nullopt; } void activate_first(); @@ -92,7 +218,8 @@ public: void activate_element(T); template<typename UnaryPredicate> - void activate_for_condition(UnaryPredicate predicate) + void + activate_for_condition(UnaryPredicate predicate) { auto it = std::find_if( m_elements.begin(), @@ -110,7 +237,8 @@ public: bool remove_element(T); template<typename UnaryPredicate> - bool remove_for_condition(UnaryPredicate predicate) + bool + remove_for_condition(UnaryPredicate predicate) { auto it = std::find_if( m_elements.begin(), @@ -136,6 +264,75 @@ public: std::optional<T> cycle_active(Direction); std::optional<T> drag_active(Direction); + template<typename UnaryPredicate> + std::optional<T> + cycle_active_with_condition( + Direction direction, + UnaryPredicate predicate, + bool wraps + ) + { + std::optional<Index> index + = next_index_with_condition(direction, predicate); + + if (!index) + return std::nullopt; + + switch (direction) { + case Direction::Forward: + { + if (!wraps && *index <= active_index()) + return std::nullopt; + break; + } + case Direction::Backward: + { + if (!wraps && *index >= last_index()) + return std::nullopt; + break; + } + } + + push_active_to_stack(); + m_index = *index; + return active_element(); + } + + template<typename UnaryPredicate> + std::optional<T> + drag_active_with_condition( + Direction direction, + UnaryPredicate predicate, + bool wraps + ) + { + std::optional<Index> index + = next_index_with_condition(direction, predicate); + + if (!index) + return std::nullopt; + + switch (direction) { + case Direction::Forward: + { + if (!wraps && *index <= active_index()) + return std::nullopt; + break; + } + case Direction::Backward: + { + if (!wraps && *index >= last_index()) + return std::nullopt; + break; + } + } + + if (m_index != *index && m_index < m_elements.size() && *index < m_elements.size()) + std::iter_swap(m_elements.begin() + m_index, m_elements.begin() + *index); + + return cycle_active_with_condition(direction, predicate, wraps); + } + void insert_at_front(T); void insert_at_back(T); void insert_before_index(Index, T); @@ -184,12 +381,14 @@ public: return m_elements.cend(); } - T operator[](std::size_t index) + T + operator[](std::size_t index) { return m_elements[index]; } - const T operator[](std::size_t index) const + const T + operator[](std::size_t index) const { return m_elements[index]; } diff --git a/include/kranewl/input/key-bindings.hh b/include/kranewl/input/key-bindings.hh @@ -218,13 +218,13 @@ static const KeyBindings key_bindings = { }, { { XKB_KEY_j, MODKEY }, { - .action = CALL(cycle_focus(Direction::Forward)), + .action = CALL(cycle_track(Direction::Forward)), .repeatable = true } }, { { XKB_KEY_k, MODKEY }, { - .action = CALL(cycle_focus(Direction::Backward)), + .action = CALL(cycle_track(Direction::Backward)), .repeatable = true } }, diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh @@ -101,7 +101,9 @@ public: void abort_cursor_interactive(); void cycle_focus(Direction); + void cycle_track(Direction); void drag_focus(Direction); + void drag_track(Direction); void sync_focus(); void relayer_views(Workspace_ptr); @@ -236,7 +238,7 @@ private: View_ptr mp_focus; View_ptr mp_jumped_from; - SceneLayer m_track; + SceneLayer m_current_track; std::vector<std::tuple<SearchSelector_ptr, Rules>> m_default_rules; diff --git a/include/kranewl/workspace.hh b/include/kranewl/workspace.hh @@ -120,6 +120,29 @@ public: void cycle(Direction); void drag(Direction); + + template<typename UnaryPredicate> + void + cycle_with_condition( + Direction direction, + UnaryPredicate predicate + ) + { + m_views.cycle_active_with_condition(direction, predicate, layout_wraps()); + mp_active = m_views.active_element().value_or(nullptr); + } + + template<typename UnaryPredicate> + void + drag_with_condition( + Direction direction, + UnaryPredicate predicate + ) + { + m_views.drag_active_with_condition(direction, predicate, layout_wraps()); + mp_active = m_views.active_element().value_or(nullptr); + } + void reverse(); void rotate(Direction); void shuffle_main(Direction); diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc @@ -56,7 +56,7 @@ Model::Model(Config const& config) m_sticky_views{}, mp_focus(nullptr), mp_jumped_from(nullptr), - m_track(SceneLayer::SCENE_LAYER_TILE), + m_current_track(SceneLayer::SCENE_LAYER_TILE), m_key_bindings(Bindings::key_bindings), m_cursor_bindings(Bindings::cursor_bindings) { @@ -310,7 +310,7 @@ Model::focus_view(View_ptr view) view->set_urgent(false); mp_focus = view; - m_track = view->scene_layer(); + m_current_track = view->scene_layer(); if (mp_workspace->layout_is_persistent() || mp_workspace->layout_is_single()) apply_layout(mp_workspace); @@ -558,7 +558,7 @@ Model::relayer_views(Workspace_ptr workspace) if (mp_focus) { mp_focus->raise(); - m_track = mp_focus->scene_layer(); + m_current_track = mp_focus->scene_layer(); } } @@ -587,6 +587,17 @@ Model::cycle_focus(Direction direction) } void +Model::cycle_track(Direction direction) +{ + TRACE(); + + mp_workspace->cycle_with_condition(direction, [this](View_ptr view) { + return belongs_to_track(view); + }); + sync_focus(); +} + +void Model::drag_focus(Direction direction) { TRACE(); @@ -596,7 +607,21 @@ Model::drag_focus(Direction direction) mp_workspace->drag(direction); sync_focus(); + apply_layout(mp_workspace); +} + +void +Model::drag_track(Direction direction) +{ + TRACE(); + + if (mp_workspace->size() <= 1) + return; + mp_workspace->drag_with_condition(direction, [this](View_ptr view) { + return belongs_to_track(view); + }); + sync_focus(); apply_layout(mp_workspace); } @@ -610,7 +635,6 @@ Model::reverse_views() mp_workspace->reverse(); sync_focus(); - apply_layout(mp_workspace); } @@ -1366,6 +1390,9 @@ Model::set_floating_view(Toggle toggle, View_ptr view) } apply_layout(view->mp_workspace); + + if (view == mp_focus) + m_current_track = view->scene_layer(); } void @@ -1424,6 +1451,9 @@ Model::set_fullscreen_view(Toggle toggle, View_ptr view) Workspace_ptr workspace = view->mp_workspace; apply_layout(workspace); + + if (view == mp_focus) + m_current_track = view->scene_layer(); } void @@ -2074,7 +2104,7 @@ Model::initialize_view(View_ptr view, Workspace_ptr workspace) set_fullscreen_view(*rules.do_fullscreen ? Toggle::On : Toggle::Off, view); if (view == mp_focus) - m_track = view->scene_layer(); + m_current_track = view->scene_layer(); } XDGView_ptr @@ -2232,7 +2262,7 @@ Model::is_free(View_ptr view) const bool Model::belongs_to_track(View_ptr view) const { - return m_track == view->scene_layer(); + return m_current_track == view->scene_layer(); } void