Skip to content

Commit

Permalink
added focus change plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
hazelwiss committed Dec 15, 2023
1 parent ee4fc11 commit 91901e7
Show file tree
Hide file tree
Showing 3 changed files with 281 additions and 0 deletions.
62 changes: 62 additions & 0 deletions metadata/focus-change.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?xml version="1.0"?>
<wayfire>
<plugin name = "focus-change">
<_short>Focus Change</_short>
<category>Desktop</category>
<option name="up" type="key">
<_short>focus up</_short>
<_long>move focus to the closest window above</_long>
<default>&lt;super&gt; &lt;shift&gt; KEY_UP</default>
</option>
<option name="down" type="key">
<_short>focus down</_short>
<_long>move focus to the closest window below</_long>
<default>&lt;super&gt; &lt;shift&gt; KEY_DOWN</default>
</option>
<option name="right" type="key">
<_short>focus right</_short>
<_long>move focus to the closest window to the right</_long>
<default>&lt;super&gt; &lt;shift&gt; KEY_RIGHT</default>
</option>
<option name="left" type="key">
<_short>focus left</_short>
<_long>move focus to the closest window to the left</_long>
<default>&lt;super&gt; &lt;shift&gt; KEY_LEFT</default>
</option>
<option name="grace-up" type="int">
<_short>upwards grace in pixels</_short>
<_long>add an amount of pixel upwards in which windows will be ignored. Can be negative</_long>
<default>1</default>
</option>
<option name="grace-down" type="int">
<_short>downwards grace in pixels</_short>
<_long>add an amount of pixel downwards in which windows will be ignored. Can be negative</_long>
<default>1</default>
</option>
<option name="grace-right" type="int">
<_short>rightwards grace in pixels</_short>
<_long>add an amount of pixel to the right in which windows will be ignored. Can be negative</_long>
<default>1</default>
</option>
<option name="grace-left" type="int">
<_short>leftwards grace in pixels</_short>
<_long>add an amount of pixel to the left in which windows will be ignored. Can be negative</_long>
<default>1</default>
</option>
<option name="cross-output" type="bool">
<_short>ignores output boundraries</_short>
<_long>enables moving focus between different outputs</_long>
<default>false</default>
</option>
<option name="scan-height" type="int">
<_short>scan height</_short>
<_long>the height of the bounding box used to scan for windows to the left or right. If zero it will be the height of the view</_long>
<default>0</default>
</option>
<option name="scan-width" type="int">
<_short>scan width</_short>
<_long>the width of the bounding box used to scan for window above or below. If zero it will be the width of the view</_long>
<default>0</default>
</option>
</plugin>
</wayfire>
214 changes: 214 additions & 0 deletions src/focus-change.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2023 Scott Moreau
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
* EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <cstdint>
#include <iterator>
#include <wayfire/bindings.hpp>
#include <wayfire/config/option.hpp>
#include <wayfire/core.hpp>
#include <wayfire/nonstd/tracking-allocator.hpp>
#include <wayfire/plugin.hpp>
#include <wayfire/per-output-plugin.hpp>
#include <wayfire/option-wrapper.hpp>
#include <wayfire/config/types.hpp>
#include <wayfire/seat.hpp>
#include <wayfire/view.hpp>
#include <wayfire/workspace-set.hpp>
#include <wayfire/bindings-repository.hpp>

namespace focus_change
{
enum class orientation_t
{
UP,
DOWN,
RIGHT,
LEFT,
};

class wayfire_focus_change_t : public wf::plugin_interface_t
{
private:
wayfire_view focus_view = nullptr;

wf::option_wrapper_t<wf::keybinding_t> key_up{"focus-change/up"},
key_down{"focus-change/down"},
key_right{"focus-change/right"},
key_left{"focus-change/left"};
wf::option_wrapper_t<int32_t> grace_up{"focus-change/grace-up"},
grace_down{"focus-change/grace-down"},
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<int32_t> scan_height{"focus-change/scan-height"},
scan_width{"focus-change/scan-width"};


void change_focus(orientation_t orientation)
{
const auto cur_view = wf::get_core().seat->get_active_view();
const auto cur_output = cur_view->get_output();
const auto cur_bb = cur_view->get_bounding_box();
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::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();
}

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 int32_t cx = bb.x + bb.width / 2;
const int32_t cy = bb.y + bb.height / 2;

const int32_t scan_w_intrm = scan_width.value() > 0 ?
scan_width.value() : cur_bb.width;
const int32_t scan_h_intrm = scan_height.value() > 0 ?
scan_height.value() : cur_bb.height;

const int32_t scan_w = std::max(scan_w_intrm / 2, 1);
const int32_t scan_h = std::max(scan_h_intrm / 2, 1);

const int32_t scan_w_l = cur_cx - scan_w;
const int32_t scan_w_h = cur_cx + scan_w;

const int32_t scan_h_l = cur_cy - scan_h;
const int32_t scan_h_h = cur_cy + scan_h;

const int32_t bias_up = grace_up.value();
const int32_t bias_down = grace_down.value();
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;

bool contains = false;
int32_t distance = 0;
switch (orientation)
{
case orientation_t::UP:
contains = w_cond;
distance = cur_cy - cy - bias_up;
break;

case orientation_t::DOWN:
contains = w_cond;
distance = cy - cur_cy - bias_down;
break;

case orientation_t::RIGHT:
contains = h_cond;
distance = cx - cur_cx - bias_right;
break;

case orientation_t::LEFT:
contains = h_cond;
distance = cur_cx - cx - bias_left;
break;

default: /* unreachable */
;
}

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

if (new_focus != nullptr)
{
wf::get_core().seat->focus_view(new_focus->self());
}
}

wf::key_callback on_key_up = [=] (auto)
{
change_focus(orientation_t::UP);
return true;
};

wf::key_callback on_key_down = [=] (auto)
{
change_focus(orientation_t::DOWN);
return true;
};

wf::key_callback on_key_right = [=] (auto)
{
change_focus(orientation_t::RIGHT);
return true;
};

wf::key_callback on_key_left = [=] (auto)
{
change_focus(orientation_t::LEFT);
return true;
};

void rebind()
{
auto& core = wf::get_core();
core.bindings->add_key(key_up, &on_key_up);
core.bindings->add_key(key_down, &on_key_down);
core.bindings->add_key(key_right, &on_key_right);
core.bindings->add_key(key_left, &on_key_left);
}

public:
void init() override
{
rebind();
}

void fini() override
{
}
};

DECLARE_WAYFIRE_PLUGIN(wayfire_focus_change_t);
}
5 changes: 5 additions & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,8 @@ workspace_names = shared_module('workspace-names', 'workspace-names.cpp',
hinge = shared_module('hinge', 'hinge.cpp',
dependencies: [wayfire],
install: true, install_dir: join_paths(get_option('libdir'), 'wayfire'))

focus_change = shared_module('focus-change', 'focus-change.cpp',
dependencies: [wayfire],
install: true, install_dir: join_paths(get_option('libdir'), 'wayfire'))

0 comments on commit 91901e7

Please sign in to comment.