Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Focus change plugin added workspace ignore flag and changed some logic in regards to cross-output functionality #222

Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions metadata/focus-change.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
<_long>enables moving focus between different outputs</_long>
<default>false</default>
</option>
<option name="cross-workspace" type="bool">
<_short>ignores workspace boundraries</_short>
<_long>enables moving focus between workspaces on the same output</_long>
<default>false</default>
</option>
<option name="raise-on-change" type="bool">
<_short>raise window on change</_short>
<_long>raise the newly focused window to the top</_long>
Expand Down
170 changes: 136 additions & 34 deletions src/focus-change.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <algorithm>
#include <cstdint>
#include <iterator>
#include <wayfire/bindings.hpp>
Expand All @@ -30,6 +31,7 @@
#include <wayfire/option-wrapper.hpp>
#include <wayfire/config/types.hpp>
#include <wayfire/seat.hpp>
#include <wayfire/toplevel-view.hpp>
#include <wayfire/view.hpp>
#include <wayfire/workspace-set.hpp>
#include <wayfire/bindings-repository.hpp>
Expand Down Expand Up @@ -57,51 +59,46 @@ class wayfire_focus_change_t : public wf::plugin_interface_t
grace_right{"focus-change/grace-right"},
grace_left{"focus-change/grace-left"};
wf::option_wrapper_t<bool> cross_outputs{"focus-change/cross-output"};
wf::option_wrapper_t<bool> cross_workspace{"focus-change/cross-workspace"};
wf::option_wrapper_t<bool> raise_on_change{"focus-change/raise-on-change"};
wf::option_wrapper_t<int> scan_height{"focus-change/scan-height"},
scan_width{"focus-change/scan-width"};


void change_focus(orientation_t orientation)
{
const bool should_pad_workspace = cross_outputs.value();
const auto cur_view = wf::get_core().seat->get_active_view();
const auto cur_output = cur_view->get_output();
const auto cur_lg = cur_output->get_layout_geometry();
const auto cur_bb = cur_view->get_bounding_box();
const int32_t cur_cx = cur_bb.x + cur_bb.width / 2 + (should_pad_workspace ? cur_lg.x : 0);
const int32_t cur_cy = cur_bb.y + cur_bb.height / 2 + (should_pad_workspace ? cur_lg.y : 0);
wf::view_interface_t *new_focus = nullptr;
const int32_t cur_cx = cur_bb.x + cur_bb.width / 2;
const int32_t cur_cy = cur_bb.y + cur_bb.height / 2;
wf::toplevel_view_interface_t *new_focus = nullptr;

auto iterating_output = std::vector<wayfire_toplevel_view>{};
if (cross_outputs.value())
{
auto outputs = wf::get_core().output_layout->get_outputs();
for (auto output : std::move(outputs))
{
auto vec = output->wset()->get_views();
iterating_output.insert(
iterating_output.end(),
std::make_move_iterator(vec.begin()),
std::make_move_iterator(vec.end()));
}
} else
{
iterating_output = cur_output->wset()->get_views();
}
const bool cross_ws = cross_workspace.value();
const auto workspace =
cross_ws ? std::optional<wf::point_t>{} : std::optional{cur_output->wset()->
get_current_workspace()};

int32_t closest_cur = INT32_MAX;
auto iterating_output = cur_output->wset()->get_views(0, workspace);
int32_t closest_cur = INT32_MAX;
for (auto&& view : std::move(iterating_output))
{
if (view->get_id() == cur_view->get_id())
{
continue;
}

const auto bb = view->get_bounding_box();
const auto lg = view->get_output()->get_layout_geometry();
const int32_t cx = bb.x + bb.width / 2 + (should_pad_workspace ? lg.x : 0);
const int32_t cy = bb.y + bb.height / 2 + (should_pad_workspace ? lg.y : 0);
const auto bb = view->get_bounding_box();
const auto lg = view->get_output()->get_layout_geometry();
const int32_t cxr = bb.width / 2;
const int32_t cyr = bb.height / 2;
const int32_t cx = bb.x + cxr;
const int32_t cy = bb.y + cyr;

if (!cross_ws && ((cx < 0) || (cx >= lg.width) || (cy < 0) || (cy >= lg.height)))
{
continue;
}

const int32_t scan_w_intrm = scan_width.value() > 0 ?
scan_width.value() : scan_width.value() < 0 ?
Expand All @@ -124,11 +121,11 @@ class wayfire_focus_change_t : public wf::plugin_interface_t
const int32_t bias_right = grace_right.value();
const int32_t bias_left = grace_left.value();

const bool w_cond = cx >= scan_w_l && cx <= scan_w_h;
const bool h_cond = cy >= scan_h_l && cy <= scan_h_h;
const bool w_cond = cx + cxr >= scan_w_l && cx - cxr <= scan_w_h;
const bool h_cond = cy + cyr >= scan_h_l && cy - cyr <= scan_h_h;

bool contains = false;
int32_t distance = 0;
int32_t distance = INT32_MAX;
switch (orientation)
{
case orientation_t::UP:
Expand All @@ -155,19 +152,124 @@ class wayfire_focus_change_t : public wf::plugin_interface_t
;
}

if ((distance >= 0) && contains)
if ((distance >= 0) && contains && (distance < closest_cur))
{
closest_cur = distance;
new_focus = view.get();
}
}

if ((new_focus == nullptr) && cross_outputs.value())
{
const auto pos = cur_output->get_layout_geometry();

auto outputs = wf::get_core().output_layout->get_outputs();
wf::output_t *output = nullptr;
int32_t closest_output = INT32_MAX;
for (auto op : outputs)
{
if (op->get_id() == cur_output->get_id())
{
continue;
}

const auto cmp_pos = op->get_layout_geometry();

const int32_t cx = cmp_pos.x + cmp_pos.width / 2;
const int32_t cy = cmp_pos.y + cmp_pos.height / 2;

const bool align_x = cx >= pos.x && cx < pos.x + pos.width;
const bool align_y = cy >= pos.y && cy < pos.y + pos.height;

int32_t distance = INT32_MAX;
bool cond = false;
switch (orientation)
{
case orientation_t::UP:
cond = align_x;
distance = pos.y - cmp_pos.y;
break;

case orientation_t::DOWN:
cond = align_x;
distance = cmp_pos.y - pos.y;
break;

case orientation_t::RIGHT:
cond = align_y;
distance = cmp_pos.x - pos.x;
break;

case orientation_t::LEFT:
cond = align_y;
distance = pos.x - cmp_pos.x;
break;

default: /* unreachable */
;
}

if (cond && (distance > 0) && (distance < closest_output))
{
closest_output = distance;
output = op;
}
}

if ((output != nullptr))
{
if (distance < closest_cur)
const auto cur_ws = output->wset()->get_current_workspace();

auto views = output->wset()->get_views(0, std::optional{cur_ws});
int32_t closest_cur = INT32_MAX;
for (auto&& view : std::move(views))
{
closest_cur = distance;
new_focus = view.get();
const auto bb = view.get()->get_bounding_box();
const auto cx = bb.x + bb.width / 2;
const auto cy = bb.y + bb.height / 2;
if ((cx < 0) || (cx >= pos.width) || (cy < 0) || (cy >= pos.height))
{
continue;
}

int32_t distance = INT32_MAX;
switch (orientation)
{
case orientation_t::UP:
distance = pos.height - cy;
break;

case orientation_t::DOWN:
distance = cy;
break;

case orientation_t::RIGHT:
distance = cx;
break;

case orientation_t::LEFT:
distance = pos.width - cx;
break;

default: /* unreachable */
;
}

if ((distance >= 0) && (distance < closest_cur))
{
closest_cur = distance;
new_focus = view.get();
}
}
}
}

if (new_focus != nullptr)
{
wf::get_core().seat->focus_output(new_focus->get_output());
auto op = new_focus->get_output();
const auto ws = op->wset()->get_view_main_workspace(new_focus);
op->wset()->set_workspace(ws);
wf::get_core().seat->focus_output(op);
wf::get_core().seat->focus_view(new_focus->self());
if (raise_on_change.value())
{
Expand Down
Loading