add workspace clicks

This commit is contained in:
2025-12-10 02:49:17 +01:00
parent 45d932329a
commit a01bb7554b
5 changed files with 75 additions and 8 deletions

View File

@@ -48,6 +48,11 @@ class HyprlandService
const Monitor *getMonitorById(int id) const;
Monitor *getMonitorByIndex(std::size_t index);
const Monitor *getMonitorByIndex(std::size_t index) const;
// Switch to a workspace slot on a given monitor. If the workspace has an
// associated Hyprland workspace id (hyprId >= 0) that id will be used.
// Otherwise the slot and monitor name will be used to request creation
// / activation via `hyprctl`.
void switchToWorkspace(int monitorId, int slot);
private:
int m_fd = -1;

View File

@@ -47,19 +47,13 @@ void Bar::setup_ui()
main_box.set_end_widget(right_box);
main_box.set_valign(Gtk::Align::CENTER);
left_box.set_margin_start(12);
left_box.set_margin_end(12);
left_box.set_valign(Gtk::Align::CENTER);
// Don't expand the center box — keep it centered by alignment
center_box.set_hexpand(false);
center_box.set_margin_top(2);
center_box.set_margin_bottom(2);
center_box.set_valign(Gtk::Align::CENTER);
center_box.set_halign(Gtk::Align::CENTER);
right_box.set_margin_start(12);
right_box.set_margin_end(12);
right_box.set_valign(Gtk::Align::CENTER);
m_workspaceIndicator = Gtk::make_managed<WorkspaceIndicator>(m_hyprlandService, m_monitorId);
@@ -86,6 +80,9 @@ void Bar::load_css()
.workspace-pill-focused { background-color: rgba(255, 255, 255, 0.18); }
.workspace-pill-active { background-color: rgba(255, 255, 255, 0.25); }
.workspace-pill-urgent { background-color: #ff5555; color: #111; }
/* Hover effect: slightly brighten background and show pointer */
.workspace-pill:hover { background-color: rgba(255, 255, 255, 0.20); }
.workspace-pill:hover { cursor: pointer; } // TODO: cursors has to be set differently in GTK4?
.tray-icon { padding: 0; margin: 0; border: none; background: transparent; min-width: 0; min-height: 0; }
)");

View File

@@ -335,6 +335,54 @@ HyprlandService::Monitor *HyprlandService::getMonitorByIndex(std::size_t index)
return &it->second;
}
void HyprlandService::switchToWorkspace(int monitorId, int slot)
{
auto it = m_monitors.find(monitorId);
if (it == m_monitors.end())
{
std::cerr << "[Hyprland] switchToWorkspace: monitor " << monitorId << " not found\n";
return;
}
const auto &monitor = it->second;
auto wsIt = monitor.workspaceStates.find(slot);
std::string cmd;
if (wsIt != monitor.workspaceStates.end() && wsIt->second.hyprId >= 0)
{
// Use the Hyprland workspace id if available
cmd = "hyprctl dispatch workspace " + std::to_string(wsIt->second.hyprId);
}
else
{
// Fallback: ask Hyprland to switch/create a workspace on the monitor
// by using the slot number and the monitor name. Syntax: "<slot>:<monitor>"
// Example: hyprctl dispatch workspace 2:DP-1
// This may vary by Hyprland version; if it doesn't work on your system
// adjust the command accordingly.
std::string monName = monitor.name;
if (monName.empty())
{
// As a last resort, just try the slot number globally
cmd = "hyprctl dispatch workspace " + std::to_string(slot);
}
else
{
// Quote monitor name in case it contains spaces
cmd = "hyprctl dispatch workspace " + std::to_string(slot) + ":\"" + monName + "\"";
}
}
try
{
(void)SystemHelper::get_command_output(cmd.c_str());
}
catch (const std::exception &ex)
{
std::cerr << "[Hyprland] Failed to dispatch workspace command: " << ex.what() << " cmd=" << cmd << std::endl;
}
}
const HyprlandService::Monitor *HyprlandService::getMonitorByIndex(std::size_t index) const
{
if (index >= m_monitors.size())

View File

@@ -13,11 +13,9 @@ TrayIconWidget::TrayIconWidget(TrayService &service, std::string id)
set_focusable(false);
set_valign(Gtk::Align::CENTER);
set_halign(Gtk::Align::CENTER);
add_css_class("tray-icon");
m_picture.set_halign(Gtk::Align::CENTER);
m_picture.set_valign(Gtk::Align::CENTER);
m_picture.set_content_fit(Gtk::ContentFit::CONTAIN);
m_picture.set_can_shrink(true);
m_picture.set_size_request(20, 20);

View File

@@ -2,6 +2,8 @@
#include <exception>
#include <gtkmm/widget.h>
#include <gtkmm/gestureclick.h>
#include <gdk/gdk.h>
#include <sigc++/functors/mem_fun.h>
WorkspaceIndicator::WorkspaceIndicator(HyprlandService &service, int monitorId)
@@ -79,6 +81,23 @@ void WorkspaceIndicator::rebuild()
auto label = Gtk::make_managed<Gtk::Label>(display);
label->add_css_class("workspace-pill");
// Make the label clickable using a gesture click (primary button)
auto gesture = Gtk::GestureClick::create();
gesture->set_button(GDK_BUTTON_PRIMARY);
// Use a lambda to capture the workspace slot id
gesture->signal_released().connect([this, workspaceId](int /*n_press*/, double /*x*/, double /*y*/)
{
try
{
m_service.switchToWorkspace(m_monitorId, workspaceId);
}
catch (const std::exception &ex)
{
std::cerr << "[WorkspaceIndicator] switchToWorkspace failed: " << ex.what() << std::endl;
}
});
label->add_controller(gesture);
if (state != nullptr)
{
if (state->focused)