--- a/src/follow-focus.cpp +++ b/src/follow-focus.cpp @@ -44,6 +44,9 @@ wayfire_view focus_view = nullptr; wf::wl_timer change_output_focus, change_view_focus; wf::pointf_t last_output_coords, last_view_coords; + wf::wl_idle_call workspace_focus_idle; + bool workspace_focus_pending = false; + wf::option_wrapper_t focus_on_workspace_change{"follow-focus/focus_on_workspace_change"}; wf::option_wrapper_t should_change_view{"follow-focus/change_view"}; wf::option_wrapper_t should_change_output{"follow-focus/change_output"}; @@ -117,7 +120,7 @@ }); } - void check_view() + void check_view(bool workspace_change = false) { change_view_focus.disconnect(); @@ -149,7 +152,7 @@ focus_view = view; } - if (wf::abs(coords - last_view_coords) < threshold) + if (!workspace_change && wf::abs(coords - last_view_coords) < threshold) { return; } @@ -163,11 +166,76 @@ change_view_focus.set_timeout(focus_delay, [=] () { + if (workspace_change) + { + auto view = wf::get_core().get_cursor_focus_view(); + if (!should_change_view || !focus_on_workspace_change || + output != wf::get_core().seat->get_active_output() || + !output->can_activate_plugin(wf::CAPABILITY_MANAGE_COMPOSITOR) || + !view || view != focus_view || view->get_output() != output) + { + return false; + } + } + change_view(); return false; // disconnect }); } + // A workspace switch can put a window under a stationary pointer. Wait + // until the switcher's animation/grab is finished, then use the normal + // follow-focus delay and raise policy without requiring pointer movement. + void schedule_workspace_focus() + { + workspace_focus_idle.run_once([=] () + { + if (!workspace_focus_pending) + { + return; + } + + if (!should_change_view || !focus_on_workspace_change || + output != wf::get_core().seat->get_active_output()) + { + workspace_focus_pending = false; + return; + } + + if (!output->can_activate_plugin(wf::CAPABILITY_MANAGE_COMPOSITOR)) + { + return; + } + + workspace_focus_pending = false; + auto view = wf::get_core().get_cursor_focus_view(); + if (view && view->get_output() == output) + { + check_view(true); + } + }); + } + + wf::signal::connection_t workspace_changed = + [=] (wf::workspace_changed_signal *ev) + { + if (ev->old_viewport != ev->new_viewport) + { + change_view_focus.disconnect(); + workspace_focus_pending = should_change_view && focus_on_workspace_change; + schedule_workspace_focus(); + } + }; + + wf::signal::connection_t plugin_changed = + [=] (wf::output_plugin_activated_changed_signal *ev) + { + if (!ev->activated && workspace_focus_pending) + { + schedule_workspace_focus(); + } + }; + wf::signal::connection_t> pointer_motion = [=] (wf::post_input_event_signal *ev) { @@ -188,10 +256,13 @@ { wf::get_core().connect(&pointer_motion); wf::get_core().connect(&pointer_motion_absolute); + output->connect(&workspace_changed); + output->connect(&plugin_changed); } void fini() override { + workspace_focus_idle.disconnect(); change_output_focus.disconnect(); change_view_focus.disconnect(); } --- a/metadata/follow-focus.xml +++ b/metadata/follow-focus.xml @@ -6,6 +6,11 @@ +