highlight urgent workspace

This commit is contained in:
2025-12-11 00:41:47 +01:00
parent 0a94acb8f4
commit e1eeb370da
9 changed files with 139 additions and 19 deletions

View File

@@ -34,6 +34,7 @@ target_sources(bar_lib
src/app.cpp src/app.cpp
src/bar/bar.cpp src/bar/bar.cpp
src/widgets/clock.cpp src/widgets/clock.cpp
src/widgets/date.cpp
src/widgets/workspaceIndicator.cpp src/widgets/workspaceIndicator.cpp
src/widgets/volumeWidget.cpp src/widgets/volumeWidget.cpp
src/widgets/webWidget.cpp src/widgets/webWidget.cpp
@@ -52,6 +53,7 @@ target_link_libraries(bar bar_lib ${GTKMM_LIBRARIES} ${LAYERSHELL_LIBRARIES} ${W
# Copy `resources/bar.css` into the build directory when it changes # Copy `resources/bar.css` into the build directory when it changes
set(RES_SRC "${CMAKE_CURRENT_SOURCE_DIR}/resources/bar.css") set(RES_SRC "${CMAKE_CURRENT_SOURCE_DIR}/resources/bar.css")
set(RES_DST "${CMAKE_CURRENT_BINARY_DIR}/resources/bar.css") set(RES_DST "${CMAKE_CURRENT_BINARY_DIR}/resources/bar.css")
set(USER_CONFIG_CSS "$ENV{HOME}/.config/bar/bar.css")
add_custom_command( add_custom_command(
OUTPUT ${RES_DST} OUTPUT ${RES_DST}
@@ -62,5 +64,14 @@ add_custom_command(
VERBATIM VERBATIM
) )
add_custom_target(copy_resources ALL DEPENDS ${RES_DST}) add_custom_command(
OUTPUT ${USER_CONFIG_CSS}
COMMAND ${CMAKE_COMMAND} -E make_directory "$ENV{HOME}/.config/bar"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${RES_SRC}" "${USER_CONFIG_CSS}"
DEPENDS "${RES_SRC}"
COMMENT "Copy resources/bar.css to ~/.config/bar/bar.css"
VERBATIM
)
add_custom_target(copy_resources ALL DEPENDS ${RES_DST} ${USER_CONFIG_CSS})
add_dependencies(bar copy_resources) add_dependencies(bar copy_resources)

View File

@@ -6,6 +6,7 @@
#include "services/hyprland.hpp" #include "services/hyprland.hpp"
#include "services/tray.hpp" #include "services/tray.hpp"
#include "widgets/clock.hpp" #include "widgets/clock.hpp"
#include "widgets/date.hpp"
#include "widgets/tray.hpp" #include "widgets/tray.hpp"
#include "widgets/webWidget.hpp" #include "widgets/webWidget.hpp"
#include "widgets/workspaceIndicator.hpp" #include "widgets/workspaceIndicator.hpp"
@@ -23,6 +24,7 @@ class Bar : public Gtk::Window {
private: private:
Clock clock; Clock clock;
Date date;
WebWidget homeAssistant {"HA", "Home Assistant", WebWidget homeAssistant {"HA", "Home Assistant",
"https://home.rivercry.com"}; "https://home.rivercry.com"};
TrayService &trayService; TrayService &trayService;

View File

@@ -1,3 +1,5 @@
#pragma once
class IUpdatable { class IUpdatable {
public: public:
virtual ~IUpdatable() = default; virtual ~IUpdatable() = default;

View File

@@ -61,6 +61,7 @@ class HyprlandService {
std::string get_socket_path(); std::string get_socket_path();
void refresh_monitors(); void refresh_monitors();
void refresh_workspaces(); void refresh_workspaces();
void handle_urgent_window(std::string windowAddress);
}; };
inline void HyprlandService::printMonitor(const Monitor &mon) const { inline void HyprlandService::printMonitor(const Monitor &mon) const {

12
include/widgets/date.hpp Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <gtk4-layer-shell/gtk4-layer-shell.h>
#include <gtkmm.h>
#include <gtkmm/label.h>
#include "interface/updateable.ipp"
class Date : public Gtk::Label, public IUpdatable {
public:
bool onUpdate();
};

View File

@@ -1,11 +1,13 @@
#include "bar/bar.hpp" #include "bar/bar.hpp"
#include "gtk/gtk.h" #include "gtk/gtk.h"
#include "widgets/date.hpp"
#include "widgets/spacer.hpp" #include "widgets/spacer.hpp"
#include "widgets/volumeWidget.hpp" #include "widgets/volumeWidget.hpp"
#include "widgets/workspaceIndicator.hpp" #include "widgets/workspaceIndicator.hpp"
#include "helpers/systemHelper.hpp" #include "helpers/systemHelper.hpp"
#include <filesystem>
#include <gtkmm/enums.h> #include <gtkmm/enums.h>
#include <gtkmm/label.h> #include <gtkmm/label.h>
#include <gtkmm/window.h> #include <gtkmm/window.h>
@@ -33,6 +35,9 @@ Bar::Bar(GdkMonitor *monitor, HyprlandService &hyprlandService,
set_child(main_box); set_child(main_box);
this->volumeWidget = Gtk::make_managed<VolumeWidget>();
load_css(); load_css();
setup_ui(); setup_ui();
@@ -41,6 +46,13 @@ Bar::Bar(GdkMonitor *monitor, HyprlandService &hyprlandService,
Glib::signal_timeout().connect(sigc::mem_fun(clock, &Clock::onUpdate), Glib::signal_timeout().connect(sigc::mem_fun(clock, &Clock::onUpdate),
1000); 1000);
date.onUpdate();
Glib::signal_timeout().connect(sigc::mem_fun(date, &Date::onUpdate),
1000);
} }
void Bar::setup_ui() { void Bar::setup_ui() {
@@ -65,14 +77,11 @@ void Bar::setup_ui() {
left_box.append(*workspaceIndicator); left_box.append(*workspaceIndicator);
clock.set_name("clock-label"); clock.set_name("clock-label");
clock.set_hexpand(false); center_box.append(this->date);
clock.set_halign(Gtk::Align::CENTER);
clock.set_valign(Gtk::Align::CENTER);
center_box.append(clock);
center_box.append(*(new Spacer())); center_box.append(*(new Spacer()));
center_box.append(this->clock);
volumeWidget = Gtk::make_managed<VolumeWidget>(); center_box.append(*(new Spacer()));
center_box.append(*volumeWidget); center_box.append(*this->volumeWidget);
trayWidget = Gtk::make_managed<TrayWidget>(trayService); trayWidget = Gtk::make_managed<TrayWidget>(trayService);
@@ -83,8 +92,17 @@ void Bar::setup_ui() {
void Bar::load_css() { void Bar::load_css() {
auto css_provider = Gtk::CssProvider::create(); auto css_provider = Gtk::CssProvider::create();
std::string css_path = "resources/bar.css";
const char* home = std::getenv("HOME");
if (home) {
std::filesystem::path config_path = std::filesystem::path(home) / ".config/bar/bar.css";
if (std::filesystem::exists(config_path)) {
css_path = config_path.string();
}
}
const std::string css = const std::string css =
SystemHelper::read_file_to_string("resources/bar.css"); SystemHelper::read_file_to_string(css_path);
css_provider->load_from_data(css); css_provider->load_from_data(css);
Gtk::StyleContext::add_provider_for_display( Gtk::StyleContext::add_provider_for_display(

View File

@@ -17,6 +17,7 @@
namespace { namespace {
const char *kMonitorCommand = "hyprctl monitors -j"; const char *kMonitorCommand = "hyprctl monitors -j";
const char *kWorkspaceCommand = "hyprctl workspaces -j"; const char *kWorkspaceCommand = "hyprctl workspaces -j";
const char *kClientsCommand = "hyprctl clients -j";
bool is_workspace_event(const std::string &event) { bool is_workspace_event(const std::string &event) {
return event.find("workspace") != std::string::npos; return event.find("workspace") != std::string::npos;
@@ -32,8 +33,11 @@ HyprlandService::~HyprlandService() {
} }
} }
void HyprlandService::on_hyprland_event(std::string event, void HyprlandService::on_hyprland_event(std::string event, std::string data) {
std::string /*data*/) { if (event == "urgent") {
handle_urgent_window(data);
}
if (is_workspace_event(event) || event == "focusedmon" || if (is_workspace_event(event) || event == "focusedmon" ||
event == "monitoradded" || event == "monitorremoved") { event == "monitoradded" || event == "monitorremoved") {
refresh_monitors(); refresh_monitors();
@@ -326,4 +330,58 @@ HyprlandService::getMonitorByIndex(std::size_t index) const {
auto it = monitors.begin(); auto it = monitors.begin();
std::advance(it, static_cast<long>(index)); std::advance(it, static_cast<long>(index));
return &it->second; return &it->second;
}
void HyprlandService::handle_urgent_window(std::string windowAddress) {
std::string output;
try {
output = SystemHelper::get_command_output(kClientsCommand);
} catch (const std::exception &ex) {
std::cerr << "[Hyprland] Failed to query clients: " << ex.what()
<< std::endl;
return;
}
auto clientsJson = nlohmann::json::parse(output, nullptr, false);
if (!clientsJson.is_array()) {
return;
}
int workspaceId = -1;
for (const auto &client : clientsJson) {
if (!client.is_object())
continue;
std::string addr = client.value("address", "");
if (addr == "0x" + windowAddress) {
if (client.contains("workspace") &&
client["workspace"].is_object()) {
workspaceId = client["workspace"].value("id", -1);
}
break;
}
}
if (workspaceId == -1) {
return;
}
for (auto &pair : monitors) {
auto &monitor = pair.second;
bool changed = false;
for (auto &wsPair : monitor.workspaceStates) {
if (wsPair.second.hyprId == workspaceId) {
if (!wsPair.second.urgent) {
wsPair.second.urgent = true;
changed = true;
}
}
}
if (changed) {
workspaceStateChanged.emit(monitor.id);
}
}
} }

16
src/widgets/date.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include "widgets/date.hpp"
#include <chrono>
#include <iomanip>
bool Date::onUpdate() {
auto now =
std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::stringstream ss;
ss << std::put_time(std::localtime(&now), "%a, %d.%m.%Y");
set_text(ss.str());
return true;
}

View File

@@ -31,7 +31,7 @@ WorkspaceIndicator::~WorkspaceIndicator() {
} }
void WorkspaceIndicator::on_workspace_update(int monitorId) { void WorkspaceIndicator::on_workspace_update(int monitorId) {
if (monitorId != monitorId && monitorId != -1) { if (this->monitorId != monitorId && monitorId != -1) {
return; return;
} }
@@ -81,13 +81,13 @@ void WorkspaceIndicator::rebuild() {
label->add_controller(gesture); label->add_controller(gesture);
if (state != nullptr) { if (state != nullptr) {
if (state->focused) { if (state->urgent != true) {
label->add_css_class("workspace-pill-focused"); if (state->focused) {
} else if (state->active) { label->add_css_class("workspace-pill-focused");
label->add_css_class("workspace-pill-active"); } else if (state->active) {
} label->add_css_class("workspace-pill-active");
}
if (state->urgent) { } else {
label->add_css_class("workspace-pill-urgent"); label->add_css_class("workspace-pill-urgent");
} }
} }