Skip to content

Commit

Permalink
window_layouter: "pick_up" and "place_down" action
Browse files Browse the repository at this point in the history
The new 'action' attribute values can be used to realize the
keyboard-based assignement of windows to screens. The "pick_up" action
(on a key press) selects the focused window to be held at the current
position until the "place_down" action is issued (by a key release).
While the focused window is held, "screen" actions can be executed
taking the picked up window to the selected screen.

Issue #5390
  • Loading branch information
nfeske committed Jan 30, 2025
1 parent 9855dcb commit 4fff0f7
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 11 deletions.
13 changes: 12 additions & 1 deletion repos/gems/recipes/raw/motif_wm/layouter.config
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,23 @@
</release>
<release key="KEY_SCREEN" action="raise_window"/>
</press>
<press key="KEY_LEFTSHIFT">
<press key="KEY_LEFTSHIFT" action="pick_up">
<press key="KEY_TAB" action="prev_window">
<release key="KEY_TAB">
<release key="KEY_SCREEN" action="raise_window"/>
</release>
</press>
<press key="KEY_1" action="screen" target="screen_1"/>
<press key="KEY_2" action="screen" target="screen_2"/>
<press key="KEY_3" action="screen" target="screen_3"/>
<press key="KEY_4" action="screen" target="screen_4"/>
<press key="KEY_5" action="screen" target="screen_5"/>
<press key="KEY_6" action="screen" target="screen_6"/>
<press key="KEY_7" action="screen" target="screen_7"/>
<press key="KEY_8" action="screen" target="screen_8"/>
<press key="KEY_9" action="screen" target="screen_9"/>
<press key="KEY_0" action="screen" target="screen_0"/>
<release key="KEY_LEFTSHIFT" action="place_down"/>
</press>
<press key="KEY_ENTER" action="toggle_fullscreen"/>
<press key="KEY_1" action="screen" target="screen_1"/>
Expand Down
13 changes: 12 additions & 1 deletion repos/gems/recipes/raw/window_layouter/window_layouter.config
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,23 @@
</release>
<release key="KEY_SCREEN" action="raise_window"/>
</press>
<press key="KEY_LEFTSHIFT">
<press key="KEY_LEFTSHIFT" action="pick_up">
<press key="KEY_TAB" action="prev_window">
<release key="KEY_TAB">
<release key="KEY_SCREEN" action="raise_window"/>
</release>
</press>
<press key="KEY_1" action="screen" target="screen_1"/>
<press key="KEY_2" action="screen" target="screen_2"/>
<press key="KEY_3" action="screen" target="screen_3"/>
<press key="KEY_4" action="screen" target="screen_4"/>
<press key="KEY_5" action="screen" target="screen_5"/>
<press key="KEY_6" action="screen" target="screen_6"/>
<press key="KEY_7" action="screen" target="screen_7"/>
<press key="KEY_8" action="screen" target="screen_8"/>
<press key="KEY_9" action="screen" target="screen_9"/>
<press key="KEY_0" action="screen" target="screen_0"/>
<release key="KEY_LEFTSHIFT" action="place_down"/>
</press>
<press key="KEY_ENTER" action="toggle_fullscreen"/>
<press key="KEY_1" action="screen" target="screen_1"/>
Expand Down
4 changes: 3 additions & 1 deletion repos/gems/src/app/window_layouter/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace Window_layouter { class Command; }
struct Window_layouter::Command
{
enum Type { NONE, NEXT_WINDOW, PREV_WINDOW, RAISE_WINDOW, TOGGLE_FULLSCREEN,
NEXT_TAB, PREV_TAB, SCREEN, RELEASE_GRAB, };
NEXT_TAB, PREV_TAB, SCREEN, RELEASE_GRAB, PICK_UP, PLACE_DOWN };

Type type;
Target::Name target;
Expand All @@ -37,6 +37,8 @@ struct Window_layouter::Command
if (string == "toggle_fullscreen") return TOGGLE_FULLSCREEN;
if (string == "screen") return SCREEN;
if (string == "release_grab") return RELEASE_GRAB;
if (string == "pick_up") return PICK_UP;
if (string == "place_down") return PLACE_DOWN;

warning("cannot convert \"", string, "\" to action type");
return NONE;
Expand Down
47 changes: 43 additions & 4 deletions repos/gems/src/app/window_layouter/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct Window_layouter::Main : User_state::Action,
Timer::Connection _drop_timer { _env };

Drag _drag { };
Pick _pick { };

Signal_handler<Main> _drop_timer_handler {
_env.ep(), *this, &Main::_handle_drop_timer };
Expand Down Expand Up @@ -247,7 +248,7 @@ struct Window_layouter::Main : User_state::Action,
fn(from, to); }); });
}

void _retarget_window(Window_id id, Target const &from, Target const &to)
void _with_retargeted_window(Window_id id, Target const &to, auto const &fn)
{
_assign_list.for_each([&] (Assign &assign) {
Window *window_ptr = nullptr;
Expand All @@ -256,18 +257,44 @@ struct Window_layouter::Main : User_state::Action,
window_ptr = &member.window; });
if (window_ptr) {
assign.target_name = to.name;
window_ptr->warp(from.rect.at - to.rect.at);
fn(*window_ptr);
}
});
}

void _retarget_window(Window_id id, Target const &to)
{
_with_retargeted_window(id, to, [&] (Window &) { });
}

void _retarget_and_warp_window(Window_id id, Target const &from, Target const &to)
{
_with_retargeted_window(id, to, [&] (Window &window) {
window.warp(from.rect.at - to.rect.at); });
}

void screen(Target::Name const &name) override
{
auto with_visible_geometry = [&] (Rect orig, Area target_area, auto const &fn)
{
Area const overlap = Rect::intersect(orig, { { }, target_area }).area;
bool const visible = (overlap.w > 50) && (overlap.h > 50);

fn(visible ? orig : Rect { { }, orig.area });
};

/* change screen under picked window */
if (_pick.picked)
_with_target_change(_pick.window_id, name, [&] (Target const &, Target const &to) {
_with_retargeted_window(_pick.window_id, to, [&] (Window &window) {
with_visible_geometry(_pick.orig_geometry, to.rect.area, [&] (Rect rect) {
window.outer_geometry(rect); }); }); });

/* change of screen under the dragged window */
if (_drag.dragging())
_with_target_change(_drag.window_id, name, [&] (Target const &from, Target const &to) {
if (from.rect == to.rect)
_retarget_window(_drag.window_id, from, to); });
_retarget_window(_drag.window_id, to); });

/* repeated activation of screen moves focus to the screen */
bool already_visible = false;
Expand All @@ -287,6 +314,18 @@ struct Window_layouter::Main : User_state::Action,
_gen_rules_with_frontmost_screen(name);
}

void pick_up(Window_id id) override
{
_window_list.with_window(id, [&] (Window const &window) {
_pick = { .picked = true,
.window_id = id,
.orig_geometry = window.outer_geometry() };
to_front(id);
});
}

void place_down() override { _pick = { }; }

void drag(Window_id id, Window::Element element, Point clicked, Point curr) override
{
if (_drag.state == Drag::State::SETTLING)
Expand Down Expand Up @@ -362,7 +401,7 @@ struct Window_layouter::Main : User_state::Action,
_target_list.with_target_at(curr, [&] (Target const &pointed) {
_drag = { Drag::State::SETTLING, moving, id, curr, pointed.rect };
_with_target_change(id, pointed.name, [&] (Target const &from, Target const &to) {
_retarget_window(id, from, to); });
_retarget_and_warp_window(id, from, to); });
});
}

Expand Down
7 changes: 7 additions & 0 deletions repos/gems/src/app/window_layouter/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ namespace Window_layouter {
return dragging() && id == window_id && moving;
}
};

struct Pick
{
bool picked;
Window_id window_id;
Rect orig_geometry;
};
}

#endif /* _TYPES_H_ */
27 changes: 23 additions & 4 deletions repos/gems/src/app/window_layouter/user_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Window_layouter::User_state
virtual void to_front(Window_id) = 0;
virtual void drag(Window_id, Window::Element, Point clicked, Point curr) = 0;
virtual void finalize_drag(Window_id, Window::Element, Point clicked, Point final) = 0;
virtual void pick_up(Window_id) = 0;
virtual void place_down() = 0;
virtual void screen(Target::Name const &) = 0;
};

Expand Down Expand Up @@ -76,6 +78,8 @@ class Window_layouter::User_state
*/
bool _drag_init_done = false;

bool _picked_up = false;

/*
* Pointer position at the beginning of a drag operation
*/
Expand Down Expand Up @@ -168,7 +172,7 @@ class Window_layouter::User_state

void hover(Window_id window_id, Window::Element element)
{
Window_id const last_hovered_window_id = _hovered_window_id;
Window_id const orig_hovered_window_id = _hovered_window_id;

_hovered_window_id = window_id;
_hovered_element = element;
Expand All @@ -192,10 +196,11 @@ class Window_layouter::User_state
_initiate_drag(_hovered_window_id, _hovered_element);

/*
* Let focus follows the pointer
* Let focus follows the pointer, except while dragging or when
* the focused window is currently picked up.
*/
if (!_drag_state && _hovered_window_id.valid()
&& _hovered_window_id != last_hovered_window_id) {
if (!_drag_state && !_picked_up && _hovered_window_id.valid()
&& _hovered_window_id != orig_hovered_window_id) {

_focused_window_id = _hovered_window_id;
_focus_history.focus(_focused_window_id);
Expand Down Expand Up @@ -329,6 +334,20 @@ void Window_layouter::User_state::_handle_event(Input::Event const &e,
_action.release_grab();
return;

case Command::PICK_UP:
if (_focused_window_id.value) {
_picked_up = true;
_action.pick_up(_focused_window_id);
}
return;

case Command::PLACE_DOWN:
if (_picked_up) {
_action.place_down();
_picked_up = false;
}
return;

default:
warning("command ", (int)command.type, " unhanded");
}
Expand Down

0 comments on commit 4fff0f7

Please sign in to comment.