#include "services/hyprland.hpp" #include #include #include #include #include #include #include #include #include #include #include "helpers/hypr.hpp" #include "helpers/string.hpp" #include "gtkmm/box.h" HyprlandService::HyprlandService() { init(); bindSocket(); } void HyprlandService::init() { auto monitorDataJson = HyprctlHelper::getMonitorData(); auto onClick = sigc::mem_fun(*this, &HyprlandService::switchToWorkspace); for (const auto &item : monitorDataJson) { auto monitorPtr = std::make_shared(); std::string monitorName = item["name"].get(); int monitorId = item["id"].get(); monitorPtr->id = monitorId; monitorPtr->name = monitorName; monitorPtr->activeWorkspaceId = item["activeWorkspace"]["id"].get(); monitorPtr->focused = item["focused"].get(); this->monitors[monitorPtr->name] = monitorPtr; for (int i = 1; i <= NUM_WORKSPACES; i++) { std::shared_ptr state = std::make_shared(); int workspaceId = i + (NUM_WORKSPACES * monitorId); state->id = workspaceId; state->monitorName = monitorName; auto view = std::make_shared(workspaceId, std::to_string(i), onClick); auto workSpace = std::make_shared(); workSpace->state = state; workSpace->view = view; monitorPtr->monitorWorkspaces[workspaceId] = workSpace; this->workspaces[workspaceId] = workSpace; } } auto clientsDataJson = HyprctlHelper::getClientData(); for (const auto &client : clientsDataJson) { auto clientPtr = std::make_shared(); clientPtr->address = client["address"].get(); clientPtr->workspaceId = client["workspace"]["id"].get(); clientPtr->title = client["title"].get(); this->clients[clientPtr->address] = clientPtr; auto workspacePtr = workspaces[clientPtr->workspaceId]; workspacePtr->state->clients[clientPtr->address] = clientPtr; if (client.contains("urgent") && client["urgent"].get()) { workspacePtr->state->urgentClients.insert(clientPtr->address); } } auto workspaceDataJson = HyprctlHelper::getWorkspaceData(); for (const auto &workspace : workspaceDataJson) { auto workspacePtr = workspaces[workspace["id"].get()]; auto state = workspacePtr->state; state->id = workspace["id"].get(); state->monitorName = workspace["monitor"].get(); refreshIndicator(workspacePtr); } } void HyprlandService::bindSocket() { std::string socketPath = HyprSocketHelper::getHyprlandSocketPath(); socketFd = socket(AF_UNIX, SOCK_STREAM, 0); if (socketFd == -1) { std::cerr << "[Hyprland] Failed to create socket" << std::endl; return; } struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; std::strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1); if (connect(socketFd, reinterpret_cast(&addr), sizeof(addr)) == -1) { std::cerr << "[Hyprland] Failed to connect to " << socketPath << std::endl; close(socketFd); socketFd = -1; return; } GSource *source = g_unix_fd_source_new(socketFd, static_cast(G_IO_IN | G_IO_HUP | G_IO_ERR)); auto onSocketEvent = [](gint fd, GIOCondition , gpointer user_data) -> gboolean { HyprlandService *self = static_cast(user_data); auto messages = SocketHelper::parseSocketMessage(fd, ">>"); for (const auto &message : messages) { self->handleSocketMessage(message); } return G_SOURCE_CONTINUE; }; g_source_set_callback(source, reinterpret_cast(reinterpret_cast(+onSocketEvent)), this, nullptr); g_source_attach(source, g_main_context_default()); g_source_unref(source); } void HyprlandService::onWorkspaceChanged(int workspaceId) { auto newActive = workspaces[workspaceId]; auto state = newActive->state; auto monitorPtr = monitors[state->monitorName]; int oldActiveWorkspaceId = monitorPtr->activeWorkspaceId; auto oldActive = workspaces[oldActiveWorkspaceId]; monitorPtr->activeWorkspaceId = workspaceId; refreshIndicator(newActive); refreshIndicator(oldActive); } void HyprlandService::onFocusedMonitorChanged(std::string monitorData) { std::string monitorName = StringHelper::split(monitorData, ',')[0]; for (const auto &[_, monitorPtr] : monitors) { std::string itMonitorName = monitorPtr->name; if (itMonitorName == monitorName) { monitorPtr->focused = true; int activeWorkspaceId = monitorPtr->activeWorkspaceId; auto activeWorkspace = workspaces[activeWorkspaceId]; refreshIndicator(activeWorkspace); } else { monitorPtr->focused = false; int activeWorkspaceId = monitorPtr->activeWorkspaceId; auto activeWorkspace = workspaces[activeWorkspaceId]; refreshIndicator(activeWorkspace); } } } void HyprlandService::onMonitorRemoved(std::string monitorName) { auto monitorPtr = this->monitors[monitorName]; for (const auto &[wsId, wsPtr] : monitorPtr->monitorWorkspaces) { this->workspaces.erase(wsId); } monitorPtr->monitorWorkspaces.clear(); monitorPtr->bar->close(); this->monitors.erase(monitorName); } // void HyprlandService::onMonitorAdded(std::string monitorName) { // // this->signalMonitorAdded.emit(); // } void HyprlandService::onOpenWindow(std::string windowData) { auto parts = StringHelper::split(windowData, ','); std::string addr = "0x" + parts[0]; int workspaceId = std::stoi(parts[1]); std::string title = parts[2]; auto clientPtr = std::make_shared(); clientPtr->address = addr; clientPtr->workspaceId = workspaceId; clientPtr->title = title; this->clients[clientPtr->address] = clientPtr; auto workspacePtr = workspaces[clientPtr->workspaceId]; workspacePtr->state->clients[clientPtr->address] = clientPtr; refreshIndicator(workspacePtr); } void HyprlandService::onCloseWindow(std::string windowData) { auto parts = StringHelper::split(windowData, ','); std::string addr = "0x" + parts[0]; if (this->clients.find(addr) == this->clients.end()) { return; } auto clientPtr = this->clients[addr]; int workspaceId = clientPtr->workspaceId; auto workspacePtr = workspaces[workspaceId]; workspacePtr->state->clients.erase(addr); this->clients.erase(addr); refreshIndicator(workspacePtr); } void HyprlandService::handleSocketMessage(SocketHelper::SocketMessage message) { if (socketEventTypeMap.find(message.eventType) == socketEventTypeMap.end()) { return; } SocketEventType eventType = socketEventTypeMap[message.eventType]; std::string eventData = message.eventData; switch (eventType) { case FOCUSED_MONITOR: { onFocusedMonitorChanged(eventData); break; } case WORKSPACE_CHANGED: { this->onWorkspaceChanged(std::stoi(eventData)); break; } case OPEN_WINDOW: { this->onOpenWindow(eventData); break; } case CLOSE_WINDOW: { this->onCloseWindow(eventData); break; } case URGENT: { this->onUrgent(eventData); break; } case ACTIVE_WINDOW: { this->onActiveWindowChanged(eventData); break; } case MONITOR_REMOVED: { this->onMonitorRemoved(eventData); break; } } } void HyprlandService::onUrgent(std::string windowAddress) { std::string addr = "0x" + windowAddress; if (this->clients.find(addr) == this->clients.end()) { return; } auto clientPtr = this->clients[addr]; int workspaceId = clientPtr->workspaceId; auto workspacePtr = workspaces[workspaceId]; workspacePtr->state->urgentClients.insert(addr); refreshIndicator(workspacePtr); } void HyprlandService::onActiveWindowChanged(std::string windowAddress) { std::string addr = "0x" + windowAddress; if (this->clients.find(addr) == this->clients.end()) { return; } auto clientPtr = this->clients[addr]; int workspaceId = clientPtr->workspaceId; auto workspacePtr = workspaces[workspaceId]; workspacePtr->state->urgentClients.erase(addr); refreshIndicator(workspacePtr); } std::shared_ptr HyprlandService::getWorkspaceIndicatorsForMonitor(std::string monitorName) { auto box = std::make_shared(Gtk::Orientation::HORIZONTAL); auto monitor = monitors[monitorName]; for (const auto &[wsId, wsPair] : monitor->monitorWorkspaces) { box->append((Gtk::Box &)*wsPair->view); } return box; } void HyprlandService::switchToWorkspace(int workspaceId) { HyprctlHelper::dispatchWorkspace(workspaceId); } void HyprlandService::refreshIndicator(std::shared_ptr workspace) { auto view = workspace->view; auto state = workspace->state; auto monitorsPtr = monitors[state->monitorName]; bool isUrgent = !state->urgentClients.empty(); bool isEmpty = state->clients.empty(); bool isPreseneting = state->id == monitorsPtr->activeWorkspaceId; bool isFocused = monitorsPtr->focused && isPreseneting; if (isUrgent) { view->setIndicatorState(WorkspaceIndicator::URGENT); } else if (isFocused) { view->setIndicatorState(WorkspaceIndicator::FOCUSED); } else if (isPreseneting) { view->setIndicatorState(WorkspaceIndicator::PRESENTING); } else if (!isEmpty) { view->setIndicatorState(WorkspaceIndicator::ALIVE); } else { view->setIndicatorState(WorkspaceIndicator::EMPTY); } } void HyprlandService::addBar(std::shared_ptr bar, std::string monitorName) { this->monitors[monitorName]->bar = bar; }