diff --git a/include/factory.hpp b/include/factory.hpp index 47ef530b..dc93cfc3 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -1,5 +1,7 @@ #pragma once +#define HAVE_HYPR + #include #ifdef HAVE_LIBDATE #include "modules/clock.hpp" @@ -25,6 +27,9 @@ #include "modules/hyprland/backend.hpp" #include "modules/hyprland/window.hpp" #endif +#ifdef HAVE_HYPR +#include "modules/hypr/window.hpp" +#endif #if defined(__linux__) && !defined(NO_FILESYSTEM) #include "modules/battery.hpp" #endif diff --git a/include/modules/hypr/ipc.hpp b/include/modules/hypr/ipc.hpp new file mode 100644 index 00000000..0cf061af --- /dev/null +++ b/include/modules/hypr/ipc.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "bar.hpp" +#include "client.hpp" + +namespace waybar::modules::hypr { + + std::string makeRequest(std::string); + +} // namespace waybar::modules::hypr diff --git a/include/modules/hypr/window.hpp b/include/modules/hypr/window.hpp new file mode 100644 index 00000000..83f8650d --- /dev/null +++ b/include/modules/hypr/window.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include "ALabel.hpp" +#include "util/sleeper_thread.hpp" +#include "util/format.hpp" +#include "ipc.hpp" + +namespace waybar::modules::hypr { + +class Window : public ALabel { + public: + Window(const std::string&, const Json::Value&); + ~Window() = default; + auto update() -> void; + + private: + util::SleeperThread thread_; +}; + +} // namespace waybar::modules::hypr diff --git a/man/waybar-hyprland-window.5.scd b/man/waybar-hyprland-window.5.scd new file mode 100644 index 00000000..4be137d0 --- /dev/null +++ b/man/waybar-hyprland-window.5.scd @@ -0,0 +1,31 @@ +waybar-hyprland-window(5) + +# NAME + +waybar - hyprland window module + +# DESCRIPTION + +The *window* module displays the title of the currently focused window in Hyprland. + +# CONFIGURATION + +Addressed by *hyprland/window* + +*format*: ++ + typeof: string ++ + default: {} ++ + The format, how information should be displayed. On {} the current window title is displayed. + + +# EXAMPLES + +``` +"hyprland/window": { + "format": "{}" +} +``` + +# STYLE + +- *#window* diff --git a/meson.build b/meson.build index 3c320068..47ee9776 100644 --- a/meson.build +++ b/meson.build @@ -187,6 +187,12 @@ src_files += [ 'src/modules/sway/workspaces.cpp' ] +add_project_arguments('-DHAVE_HYPR', language: 'cpp') +src_files += [ + 'src/modules/hypr/ipc.cpp', + 'src/modules/hypr/window.cpp', +] + if true add_project_arguments('-DHAVE_WLR', language: 'cpp') src_files += 'src/modules/wlr/taskbar.cpp' diff --git a/src/factory.cpp b/src/factory.cpp index 6df69d5c..907f09a0 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -61,6 +61,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { if (ref == "hyprland/window") { return new waybar::modules::hyprland::Window(id, bar_, config_[name]); } +#endif +#ifdef HAVE_HYPR + if (ref == "hypr/window") { + return new waybar::modules::hypr::Window(id, config_[name]); + } #endif if (ref == "idle_inhibitor") { return new waybar::modules::IdleInhibitor(id, bar_, config_[name]); diff --git a/src/modules/hypr/ipc.cpp b/src/modules/hypr/ipc.cpp new file mode 100644 index 00000000..40488eca --- /dev/null +++ b/src/modules/hypr/ipc.cpp @@ -0,0 +1,86 @@ +#include "modules/hypr/ipc.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util/string.hpp" + +std::string waybar::modules::hypr::makeRequest(std::string req) { + const auto SERVERSOCKET = socket(AF_INET, SOCK_STREAM, 0); + + if (SERVERSOCKET < 0) { + spdlog::error("[Hypr IPC] Couldn't open a socket."); + return ""; + } + + const auto SERVER = gethostbyname("localhost"); + + if (!SERVER) { + spdlog::error("[Hypr IPC] Couldn't get localhost."); + return ""; + } + + sockaddr_in serverAddress = {0}; + serverAddress.sin_family = AF_INET; + bcopy((char*)SERVER->h_addr, (char*)&serverAddress.sin_addr.s_addr, SERVER->h_length); + + std::ifstream socketPortStream; + socketPortStream.open("/tmp/hypr/.socket"); + + if (!socketPortStream.good()) { + spdlog::error("[Hypr IPC] No socket file. Is Hyprland running?"); + return ""; + } + + std::string port = ""; + std::getline(socketPortStream, port); + socketPortStream.close(); + + int portInt = 0; + try { + portInt = std::stoi(port.c_str()); + } catch (...) { + spdlog::error("[Hypr IPC] Port not an int?!"); + return ""; + } + + if (portInt == 0) { + spdlog::error("[Hypr IPC] Port 0. Aborting."); + return ""; + } + + serverAddress.sin_port = portInt; + + if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, sizeof(serverAddress)) < 0) { + spdlog::error("[Hypr IPC] Couldn't connect to port {} , is Hyprland running?", port); + return ""; + } + + auto sizeWritten = write(SERVERSOCKET, req.c_str(), req.length()); + + if (sizeWritten < 0) { + spdlog::error("[Hypr IPC] Couldn't write to the socket."); + return ""; + } + + char buffer[8192] = {0}; + + sizeWritten = read(SERVERSOCKET, buffer, 8192); + + if (sizeWritten < 0) { + spdlog::error("[Hypr IPC] Couldn't cread from the socket."); + return ""; + } + + close(SERVERSOCKET); + + return std::string(buffer); +} \ No newline at end of file diff --git a/src/modules/hypr/window.cpp b/src/modules/hypr/window.cpp new file mode 100644 index 00000000..ca224fc9 --- /dev/null +++ b/src/modules/hypr/window.cpp @@ -0,0 +1,27 @@ +#include "modules/hypr/window.hpp" +#include "modules/hypr/ipc.hpp" + +using namespace waybar::util; + +waybar::modules::hypr::Window::Window(const std::string& id, const Json::Value& config) : ALabel(config, "window", id, "{window}", 0.5f) { + thread_ = [this] { + dp.emit(); + thread_.sleep_for(interval_); + }; +} + +auto waybar::modules::hypr::Window::update() -> void { + auto format = format_; + + std::string windowName = waybar::modules::hypr::makeRequest("activewindow"); + + if (windowName != "") + windowName = windowName.substr(windowName.find_first_of('>') + 2, windowName.find_first_of('\n') - windowName.find_first_of('>') - 3); + + event_box_.show(); + label_.set_markup(fmt::format(format, + fmt::arg("window", windowName))); + + // Call parent update + ALabel::update(); +}