Skip to content

Commit

Permalink
hyprbars: Improve (touch + button) functionality (#265)
Browse files Browse the repository at this point in the history
Various miscellaneous improvements

---------

Co-authored-by: vaxerski <[email protected]>
  • Loading branch information
caffeine01 and vaxerski authored Jan 8, 2025
1 parent 25d0292 commit 948d70b
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 87 deletions.
2 changes: 1 addition & 1 deletion hyprbars/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ plugin {
Use the `hyprbars-button` keyword.

```ini
hyprbars-button = color, size, icon, on-click
hyprbars-button = bgcolor, size, icon, on-click, fgcolor
```

## Window rules
Expand Down
210 changes: 135 additions & 75 deletions hyprbars/barDeco.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <hyprland/src/desktop/Window.hpp>
#include <hyprland/src/helpers/MiscFunctions.hpp>
#include <hyprland/src/managers/SeatManager.hpp>
#include <hyprland/src/managers/input/InputManager.hpp>
#include <hyprland/src/render/Renderer.hpp>
#include <pango/pangocairo.h>

Expand All @@ -16,11 +17,19 @@ CHyprBar::CHyprBar(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow) {
const auto PMONITOR = pWindow->m_pMonitor.lock();
PMONITOR->scheduledRecalc = true;

//button events
m_pMouseButtonCallback = HyprlandAPI::registerCallbackDynamic(
PHANDLE, "mouseButton", [&](void* self, SCallbackInfo& info, std::any param) { onMouseDown(info, std::any_cast<IPointer::SButtonEvent>(param)); });

m_pMouseMoveCallback =
HyprlandAPI::registerCallbackDynamic(PHANDLE, "mouseMove", [&](void* self, SCallbackInfo& info, std::any param) { onMouseMove(std::any_cast<Vector2D>(param)); });
PHANDLE, "mouseButton", [&](void* self, SCallbackInfo& info, std::any param) { onMouseButton(info, std::any_cast<IPointer::SButtonEvent>(param)); });
m_pTouchDownCallback = HyprlandAPI::registerCallbackDynamic(
PHANDLE, "touchDown", [&](void* self, SCallbackInfo& info, std::any param) { onTouchDown(info, std::any_cast<ITouch::SDownEvent>(param)); });
m_pTouchUpCallback = HyprlandAPI::registerCallbackDynamic( //
PHANDLE, "touchUp", [&](void* self, SCallbackInfo& info, std::any param) { handleUpEvent(info); });

//move events
m_pTouchMoveCallback = HyprlandAPI::registerCallbackDynamic(
PHANDLE, "touchMove", [&](void* self, SCallbackInfo& info, std::any param) { onTouchMove(info, std::any_cast<ITouch::SMotionEvent>(param)); });
m_pMouseMoveCallback = HyprlandAPI::registerCallbackDynamic( //
PHANDLE, "mouseMove", [&](void* self, SCallbackInfo& info, std::any param) { onMouseMove(std::any_cast<Vector2D>(param)); });

m_pTextTex = makeShared<CTexture>();
m_pButtonsTex = makeShared<CTexture>();
Expand All @@ -29,6 +38,9 @@ CHyprBar::CHyprBar(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow) {
CHyprBar::~CHyprBar() {
damageEntire();
HyprlandAPI::unregisterCallback(PHANDLE, m_pMouseButtonCallback);
HyprlandAPI::unregisterCallback(PHANDLE, m_pTouchDownCallback);
HyprlandAPI::unregisterCallback(PHANDLE, m_pTouchUpCallback);
HyprlandAPI::unregisterCallback(PHANDLE, m_pTouchMoveCallback);
HyprlandAPI::unregisterCallback(PHANDLE, m_pMouseMoveCallback);
std::erase(g_pGlobalState->bars, this);
}
Expand Down Expand Up @@ -57,16 +69,61 @@ std::string CHyprBar::getDisplayName() {
return "Hyprbar";
}

void CHyprBar::onMouseDown(SCallbackInfo& info, IPointer::SButtonEvent e) {
bool CHyprBar::inputIsValid() {
if (!m_pWindow->m_pWorkspace->isVisible() || !g_pInputManager->m_dExclusiveLSes.empty() ||
(g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(m_pWindow->m_pWLSurface->resource())))
return;
return false;

const auto WINDOWATCURSOR = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);

if (WINDOWATCURSOR != m_pWindow && m_pWindow != g_pCompositor->m_pLastWindow)
return false;

return true;
}

void CHyprBar::onMouseButton(SCallbackInfo& info, IPointer::SButtonEvent e) {
if (!inputIsValid())
return;

if (e.state != WL_POINTER_BUTTON_STATE_PRESSED) {
handleUpEvent(info);
return;
}

handleDownEvent(info, std::nullopt);
}

void CHyprBar::onTouchDown(SCallbackInfo& info, ITouch::SDownEvent e) {
if (!inputIsValid())
return;

auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->boundOutput.empty() ? e.device->boundOutput : "");
PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor.lock();
g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true);

handleDownEvent(info, e);
}

void CHyprBar::onMouseMove(Vector2D coords) {
if (!m_bDragPending || m_bTouchEv)
return;

m_bDragPending = false;
handleMovement();
}

void CHyprBar::onTouchMove(SCallbackInfo& info, ITouch::SMotionEvent e) {
if (!m_bDragPending || !m_bTouchEv)
return;

g_pInputManager->mouseMoveUnified(e.timeMs);
handleMovement();
}

void CHyprBar::handleDownEvent(SCallbackInfo& info, std::optional<ITouch::SDownEvent> touchEvent) {
m_bTouchEv = touchEvent.has_value();

const auto PWINDOW = m_pWindow.lock();

const auto COORDS = cursorRelativeToBar();
Expand All @@ -81,44 +138,63 @@ void CHyprBar::onMouseDown(SCallbackInfo& info, IPointer::SButtonEvent e) {
if (!VECINRECT(COORDS, 0, 0, assignedBoxGlobal().w, **PHEIGHT - 1)) {

if (m_bDraggingThis) {
if (m_bTouchEv) {
ITouch::SDownEvent e = touchEvent.value();
g_pCompositor->warpCursorTo(Vector2D(e.pos.x, e.pos.y));
g_pInputManager->mouseMoveUnified(e.timeMs);
}
g_pKeybindManager->m_mDispatchers["mouse"]("0movewindow");
Debug::log(LOG, "[hyprbars] Dragging ended on {:x}", (uintptr_t)PWINDOW.get());
}

m_bDraggingThis = false;
m_bDragPending = false;
m_bTouchEv = false;
return;
}

if (e.state != WL_POINTER_BUTTON_STATE_PRESSED) {

if (m_bCancelledDown)
info.cancelled = true;
g_pCompositor->focusWindow(PWINDOW);

m_bCancelledDown = false;
if (PWINDOW->m_bIsFloating)
g_pCompositor->changeWindowZOrder(PWINDOW, true);

if (m_bDraggingThis) {
g_pKeybindManager->m_mDispatchers["mouse"]("0movewindow");
m_bDraggingThis = false;
info.cancelled = true;
m_bCancelledDown = true;

Debug::log(LOG, "[hyprbars] Dragging ended on {:x}", (uintptr_t)PWINDOW.get());
}
doButtonPress(PBARPADDING, PBARBUTTONPADDING, PHEIGHT, COORDS, BUTTONSRIGHT);

m_bDragPending = false;
m_bDragPending = true;
}

void CHyprBar::handleUpEvent(SCallbackInfo& info) {
if (m_pWindow.lock() != g_pCompositor->m_pLastWindow.lock())
return;
}

g_pCompositor->focusWindow(PWINDOW);
if (m_bCancelledDown)
info.cancelled = true;

if (PWINDOW->m_bIsFloating)
g_pCompositor->changeWindowZOrder(PWINDOW, true);
m_bCancelledDown = false;

info.cancelled = true;
m_bCancelledDown = true;
if (m_bDraggingThis) {
g_pKeybindManager->m_mDispatchers["mouse"]("0movewindow");
m_bDraggingThis = false;

Debug::log(LOG, "[hyprbars] Dragging ended on {:x}", (uintptr_t)m_pWindow.lock().get());
}

m_bDragPending = false;
m_bTouchEv = false;
}

// check if on a button
void CHyprBar::handleMovement() {
g_pKeybindManager->m_mDispatchers["mouse"]("1movewindow");
m_bDraggingThis = true;
Debug::log(LOG, "[hyprbars] Dragging initiated on {:x}", (uintptr_t)m_pWindow.lock().get());
return;
}

void CHyprBar::doButtonPress(long int* const* PBARPADDING, long int* const* PBARBUTTONPADDING, long int* const* PHEIGHT, Vector2D COORDS, const bool BUTTONSRIGHT) {
//check if on a button
float offset = **PBARPADDING;

for (auto& b : g_pGlobalState->buttons) {
Expand All @@ -133,20 +209,6 @@ void CHyprBar::onMouseDown(SCallbackInfo& info, IPointer::SButtonEvent e) {

offset += **PBARBUTTONPADDING + b.size;
}

m_bDragPending = true;
}

void CHyprBar::onMouseMove(Vector2D coords) {
if (m_bDragPending) {
m_bDragPending = false;
g_pKeybindManager->m_mDispatchers["mouse"]("1movewindow");
m_bDraggingThis = true;

Debug::log(LOG, "[hyprbars] Dragging initiated on {:x}", (uintptr_t)m_pWindow.lock().get());

return;
}
}

void CHyprBar::renderText(SP<CTexture> out, const std::string& text, const CHyprColor& color, const Vector2D& bufferSize, const float scale, const int fontSize) {
Expand Down Expand Up @@ -292,48 +354,53 @@ void CHyprBar::renderBarTitle(const Vector2D& bufferSize, const float scale) {
cairo_surface_destroy(CAIROSURFACE);
}

size_t CHyprBar::getVisibleButtonCount(long int* const* PBARBUTTONPADDING, long int* const* PBARPADDING, const Vector2D& bufferSize, const float scale) {
float availableSpace = bufferSize.x - **PBARPADDING * scale * 2;
size_t count = 0;

for (const auto& button : g_pGlobalState->buttons) {
const float buttonSpace = (button.size + **PBARBUTTONPADDING) * scale;
if (availableSpace >= buttonSpace) {
count++;
availableSpace -= buttonSpace;
} else
break;
}

return count;
}

void CHyprBar::renderBarButtons(const Vector2D& bufferSize, const float scale) {
static auto* const PBARBUTTONPADDING = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_button_padding")->getDataStaticPtr();
static auto* const PBARPADDING = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_padding")->getDataStaticPtr();
static auto* const PALIGNBUTTONS = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment")->getDataStaticPtr();

const auto scaledButtonsPad = **PBARBUTTONPADDING * scale;
const auto scaledBarPadding = **PBARPADDING * scale;
const bool BUTTONSRIGHT = std::string{*PALIGNBUTTONS} != "left";
const auto visibleCount = getVisibleButtonCount(PBARBUTTONPADDING, PBARPADDING, bufferSize, scale);

const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y);
const auto CAIRO = cairo_create(CAIROSURFACE);

static auto* const PALIGNBUTTONS = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment")->getDataStaticPtr();

const bool BUTTONSRIGHT = std::string{*PALIGNBUTTONS} != "left";

// clear the pixmap
cairo_save(CAIRO);
cairo_set_operator(CAIRO, CAIRO_OPERATOR_CLEAR);
cairo_paint(CAIRO);
cairo_restore(CAIRO);

// draw buttons
int offset = scaledBarPadding;

auto drawButton = [&](SHyprButton& button) -> void {
const auto scaledButtonSize = button.size * scale;

Vector2D currentPos =
Vector2D{BUTTONSRIGHT ? bufferSize.x - offset - scaledButtonSize / 2.0 : offset + scaledButtonSize / 2.0, (bufferSize.y - scaledButtonSize) / 2.0}.floor();
int offset = **PBARPADDING * scale;
for (size_t i = 0; i < visibleCount; ++i) {
const auto& button = g_pGlobalState->buttons[i];
const auto scaledButtonSize = button.size * scale;
const auto scaledButtonsPad = **PBARBUTTONPADDING * scale;

const int X = currentPos.x;
const int Y = currentPos.y;
const int RADIUS = static_cast<int>(std::ceil(scaledButtonSize / 2.0));
const auto pos = Vector2D{BUTTONSRIGHT ? bufferSize.x - offset - scaledButtonSize / 2.0 : offset + scaledButtonSize / 2.0, bufferSize.y / 2.0}.floor();

cairo_set_source_rgba(CAIRO, button.col.r, button.col.g, button.col.b, button.col.a);
cairo_arc(CAIRO, X, Y + RADIUS, RADIUS, 0, 2 * M_PI);
cairo_set_source_rgba(CAIRO, button.bgcol.r, button.bgcol.g, button.bgcol.b, button.bgcol.a);
cairo_arc(CAIRO, pos.x, pos.y, scaledButtonSize / 2, 0, 2 * M_PI);
cairo_fill(CAIRO);

offset += scaledButtonsPad + scaledButtonSize;
};

for (auto& b : g_pGlobalState->buttons) {
drawButton(b);
}

// copy the data to an OpenGL texture we have
Expand Down Expand Up @@ -361,37 +428,30 @@ void CHyprBar::renderBarButtonsText(CBox* barBox, const float scale, const float
static auto* const PALIGNBUTTONS = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment")->getDataStaticPtr();

const bool BUTTONSRIGHT = std::string{*PALIGNBUTTONS} != "left";
const auto visibleCount = getVisibleButtonCount(PBARBUTTONPADDING, PBARPADDING, Vector2D{barBox->w, barBox->h}, scale);

const auto scaledButtonsPad = **PBARBUTTONPADDING * scale;
const auto scaledBarPad = **PBARPADDING * scale;
int offset = scaledBarPad;
//

auto drawButton = [&](SHyprButton& button) -> void {
int offset = **PBARPADDING * scale;
for (size_t i = 0; i < visibleCount; ++i) {
auto& button = g_pGlobalState->buttons[i];
const auto scaledButtonSize = button.size * scale;
const auto scaledButtonsPad = **PBARBUTTONPADDING * scale;

if (button.iconTex->m_iTexID == 0 /* icon is not rendered */ && !button.icon.empty()) {
// render icon
const Vector2D BUFSIZE = {scaledButtonSize, scaledButtonSize};
auto fgcol = button.userfg ? button.fgcol : (button.bgcol.r + button.bgcol.g + button.bgcol.b < 1) ? CHyprColor(0xFFFFFFFF) : CHyprColor(0xFF000000);

const bool LIGHT = button.col.r + button.col.g + button.col.b < 1;

renderText(button.iconTex, button.icon, LIGHT ? CHyprColor(0xFFFFFFFF) : CHyprColor(0xFF000000), BUFSIZE, scale, button.size * 0.62);
renderText(button.iconTex, button.icon, fgcol, BUFSIZE, scale, button.size * 0.62);
}

if (button.iconTex->m_iTexID == 0)
return;
continue;

CBox pos = {barBox->x + (BUTTONSRIGHT ? barBox->width - offset - scaledButtonSize : offset), barBox->y + (barBox->height - scaledButtonSize) / 2.0, scaledButtonSize,
scaledButtonSize};

g_pHyprOpenGL->renderTexture(button.iconTex, &pos, a);

offset += scaledButtonsPad + scaledButtonSize;
};

for (auto& b : g_pGlobalState->buttons) {
drawButton(b);
}
}

Expand Down
26 changes: 24 additions & 2 deletions hyprbars/barDeco.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
#include <hyprland/src/render/decorations/IHyprWindowDecoration.hpp>
#include <hyprland/src/render/OpenGL.hpp>
#include <hyprland/src/devices/IPointer.hpp>
#include <hyprland/src/devices/ITouch.hpp>
#include "globals.hpp"

#define private public
#include <hyprland/src/managers/input/InputManager.hpp>
#undef private

class CHyprBar : public IHyprWindowDecoration {
public:
CHyprBar(PHLWINDOW);
Expand Down Expand Up @@ -60,21 +65,38 @@ class CHyprBar : public IHyprWindowDecoration {
void renderText(SP<CTexture> out, const std::string& text, const CHyprColor& color, const Vector2D& bufferSize, const float scale, const int fontSize);
void renderBarButtons(const Vector2D& bufferSize, const float scale);
void renderBarButtonsText(CBox* barBox, const float scale, const float a);
void onMouseDown(SCallbackInfo& info, IPointer::SButtonEvent e);

bool inputIsValid();
void onMouseButton(SCallbackInfo& info, IPointer::SButtonEvent e);
void onTouchDown(SCallbackInfo& info, ITouch::SDownEvent e);
void onMouseMove(Vector2D coords);
void onTouchMove(SCallbackInfo& info, ITouch::SMotionEvent e);

void handleDownEvent(SCallbackInfo& info, std::optional<ITouch::SDownEvent> touchEvent);
void handleUpEvent(SCallbackInfo& info);
void handleMovement();
void doButtonPress(long int* const* PBARPADDING, long int* const* PBARBUTTONPADDING, long int* const* PHEIGHT, Vector2D COORDS, bool BUTTONSRIGHT);

CBox assignedBoxGlobal();

SP<HOOK_CALLBACK_FN> m_pMouseButtonCallback;
SP<HOOK_CALLBACK_FN> m_pTouchDownCallback;
SP<HOOK_CALLBACK_FN> m_pTouchUpCallback;

SP<HOOK_CALLBACK_FN> m_pTouchMoveCallback;
SP<HOOK_CALLBACK_FN> m_pMouseMoveCallback;

std::string m_szLastTitle;

bool m_bDraggingThis = false;
bool m_bTouchEv = false;
bool m_bDragPending = false;
bool m_bCancelledDown = false;

// for dynamic updates
int m_iLastHeight = 0;
int m_iLastHeight = 0;

size_t getVisibleButtonCount(long int* const* PBARBUTTONPADDING, long int* const* PBARPADDING, const Vector2D& bufferSize, const float scale);

friend class CBarPassElement;
};
Loading

0 comments on commit 948d70b

Please sign in to comment.