diff --git a/example/main.cpp b/example/main.cpp index 2fd363d..942f5b8 100644 --- a/example/main.cpp +++ b/example/main.cpp @@ -1,12 +1,11 @@ #include #include -void Create(Window& window, int32_t monitor) +void Create(Window& window, const std::string& monitor) { auto mainWidget = Widget::Create(); mainWidget->SetText("Hello, World!"); - window = Window(monitor); window.SetMainWidget(std::move(mainWidget)); } diff --git a/src/AudioFlyin.cpp b/src/AudioFlyin.cpp index 094acc9..0d314ef 100644 --- a/src/AudioFlyin.cpp +++ b/src/AudioFlyin.cpp @@ -130,7 +130,7 @@ namespace AudioFlyin parent.AddChild(std::move(icon)); } - void Create(Window& window, UNUSED int32_t monitor, Type type) + void Create(Window& window, UNUSED const std::string& monitor, Type type) { DynCtx::win = &window; DynCtx::type = type; diff --git a/src/AudioFlyin.h b/src/AudioFlyin.h index 55389c1..2fe45b6 100644 --- a/src/AudioFlyin.h +++ b/src/AudioFlyin.h @@ -9,5 +9,5 @@ namespace AudioFlyin Speaker, Microphone }; - void Create(Window& window, int32_t monitor, Type type); + void Create(Window& window, const std::string& monitor, Type type); } diff --git a/src/Bar.cpp b/src/Bar.cpp index 90b9856..46502ae 100644 --- a/src/Bar.cpp +++ b/src/Bar.cpp @@ -43,7 +43,7 @@ namespace Bar return (Config::Get().location == 'L' || Config::Get().location == 'R') && Config::Get().iconsAlwaysUp; } - static int32_t monitorID; + static std::string monitor; namespace DynCtx { @@ -393,7 +393,7 @@ namespace Bar static std::vector workspaces; TimerResult UpdateWorkspaces(Box&) { - System::PollWorkspaces((uint32_t)monitorID, workspaces.size()); + System::PollWorkspaces(monitor, workspaces.size()); for (size_t i = 0; i < workspaces.size(); i++) { switch (System::GetWorkspaceStatus(i + 1)) @@ -1187,9 +1187,10 @@ namespace Bar "VRAM, GPU, RAM, CPU, Battery, Power"); } - void Create(Window& window, int32_t monitor) + void Create(Window& window, const std::string& monitorName) { - monitorID = monitor; + ASSERT(!window.GetName().empty(), "Error: The bar requires a specified monitor. Use 'gBar bar ' instead!"); + monitor = monitorName; auto mainWidget = Widget::Create(); mainWidget->SetOrientation(Utils::GetOrientation()); diff --git a/src/Bar.h b/src/Bar.h index 9a52f78..150db5b 100644 --- a/src/Bar.h +++ b/src/Bar.h @@ -4,5 +4,5 @@ namespace Bar { - void Create(Window& window, int32_t monitor); + void Create(Window& window, const std::string& monitor); } diff --git a/src/BluetoothDevices.cpp b/src/BluetoothDevices.cpp index 6425bd2..0ebdfec 100644 --- a/src/BluetoothDevices.cpp +++ b/src/BluetoothDevices.cpp @@ -286,7 +286,7 @@ namespace BluetoothDevices parentWidget.AddChild(std::move(bodyBox)); } - void Create(Window& window, UNUSED int32_t monitor) + void Create(Window& window, UNUSED const std::string& monitor) { DynCtx::win = &window; auto mainWidget = Widget::Create(); diff --git a/src/BluetoothDevices.h b/src/BluetoothDevices.h index dd01214..5392b18 100644 --- a/src/BluetoothDevices.h +++ b/src/BluetoothDevices.h @@ -4,5 +4,5 @@ namespace BluetoothDevices { - void Create(Window& window, int32_t monitor); + void Create(Window& window, const std::string& monitor); } diff --git a/src/Common.h b/src/Common.h index 3fd93b3..552ba48 100644 --- a/src/Common.h +++ b/src/Common.h @@ -190,12 +190,12 @@ inline Process OpenProcess(const std::string& command) #include "Window.h" #define DL_VERSION 1 -#define DEFINE_PLUGIN(fun) \ - extern "C" int32_t Plugin_GetVersion() \ - { \ - return DL_VERSION; \ - }; \ - extern "C" void Plugin_InvokeCreateFun(void* window, int32_t monitor) \ - { \ - fun(*(Window*)window, monitor); \ +#define DEFINE_PLUGIN(fun) \ + extern "C" int32_t Plugin_GetVersion() \ + { \ + return DL_VERSION; \ + }; \ + extern "C" void Plugin_InvokeCreateFun(void* window, void* monitor) \ + { \ + fun(*(Window*)window, *(const std::string&*)monitor); \ } diff --git a/src/Plugin.cpp b/src/Plugin.cpp index ed9a5e5..39a9060 100644 --- a/src/Plugin.cpp +++ b/src/Plugin.cpp @@ -5,7 +5,7 @@ #include -void Plugin::LoadWidgetFromPlugin(const std::string& pluginName, Window& window, int32_t monitor) +void Plugin::LoadWidgetFromPlugin(const std::string& pluginName, Window& window, const std::string& monitor) { std::string home = std::getenv("HOME"); std::array paths = {home + "/.local/lib/gBar", "/usr/local/lib/gBar", "/usr/lib/gBar"}; @@ -18,19 +18,19 @@ void Plugin::LoadWidgetFromPlugin(const std::string& pluginName, Window& window, if (dl) break; } - ASSERT(dl, "Error: Cannot find plugin \"" << pluginName << "\"!\n" - "Note: Did you mean to run \"gBar bar\" instead?"); + ASSERT(dl, "Error: Cannot find plugin \"" << pluginName + << "\"!\n" + "Note: Did you mean to run \"gBar bar\" instead?"); - typedef void (*PFN_InvokeCreateFun)(void*, int32_t); + typedef void (*PFN_InvokeCreateFun)(void*, void*); typedef int32_t (*PFN_GetVersion)(); auto getVersion = (PFN_GetVersion)dlsym(dl, "Plugin_GetVersion"); ASSERT(getVersion, "DL is not a valid gBar plugin!"); ASSERT(getVersion() == DL_VERSION, "Mismatching version, please recompile your plugin!"); - typedef void (*PFN_InvokeCreateFun)(void*, int32_t); auto invokeCreateFun = (PFN_InvokeCreateFun)dlsym(dl, "Plugin_InvokeCreateFun"); ASSERT(invokeCreateFun, "DL is not a valid gBar plugin!"); // Execute - invokeCreateFun(&window, monitor); + invokeCreateFun(&window, (void*)&monitor); } diff --git a/src/Plugin.h b/src/Plugin.h index 314d41d..cbf3ffa 100644 --- a/src/Plugin.h +++ b/src/Plugin.h @@ -4,5 +4,5 @@ namespace Plugin { - void LoadWidgetFromPlugin(const std::string& pluginName, Window& window, int32_t monitor); + void LoadWidgetFromPlugin(const std::string& pluginName, Window& window, const std::string& monitor); } diff --git a/src/System.cpp b/src/System.cpp index a9d8a97..c627840 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -485,7 +485,7 @@ namespace System } #ifdef WITH_WORKSPACES - void PollWorkspaces(uint32_t monitor, uint32_t numWorkspaces) + void PollWorkspaces(const std::string& monitor, uint32_t numWorkspaces) { Workspaces::PollStatus(monitor, numWorkspaces); } diff --git a/src/System.h b/src/System.h index af03a48..89f6b64 100644 --- a/src/System.h +++ b/src/System.h @@ -95,7 +95,7 @@ namespace System Current, Active }; - void PollWorkspaces(uint32_t monitor, uint32_t numWorkspaces); + void PollWorkspaces(const std::string& monitor, uint32_t numWorkspaces); WorkspaceStatus GetWorkspaceStatus(uint32_t workspace); void GotoWorkspace(uint32_t workspace); // direction: + or - diff --git a/src/Wayland.cpp b/src/Wayland.cpp index f28a843..484bf02 100644 --- a/src/Wayland.cpp +++ b/src/Wayland.cpp @@ -8,17 +8,15 @@ namespace Wayland { // There's probably a better way to avoid the LUTs - static std::unordered_map monitors; + static std::unordered_map monitors; static std::unordered_map workspaceGroups; static std::unordered_map workspaces; - static uint32_t curID = 0; - static wl_display* display; static wl_registry* registry; static zext_workspace_manager_v1* workspaceManager; - static bool registeredMonitors = false; + static bool registeredMonitor = false; static bool registeredGroup = false; static bool registeredWorkspace = false; static bool registeredWorkspaceInfo = false; @@ -87,22 +85,14 @@ namespace Wayland // Workspace Group callbacks static void OnWSGroupOutputEnter(void*, zext_workspace_group_handle_v1* group, wl_output* output) { - auto monitor = std::find_if(monitors.begin(), monitors.end(), - [&](const std::pair& mon) - { - return mon.second.output == output; - }); + auto monitor = monitors.find(output); ASSERT(monitor != monitors.end(), "Wayland: Registered WS group before monitor!"); LOG("Wayland: Added group to monitor"); monitor->second.workspaceGroup = group; } static void OnWSGroupOutputLeave(void*, zext_workspace_group_handle_v1*, wl_output* output) { - auto monitor = std::find_if(monitors.begin(), monitors.end(), - [&](const std::pair& mon) - { - return mon.second.output == output; - }); + auto monitor = monitors.find(output); ASSERT(monitor != monitors.end(), "Wayland: Registered WS group before monitor!"); LOG("Wayland: Added group to monitor"); monitor->second.workspaceGroup = nullptr; @@ -140,24 +130,22 @@ namespace Wayland // Output Callbacks // Very bloated, indeed static void OnOutputGeometry(void*, wl_output*, int32_t, int32_t, int32_t, int32_t, int32_t, const char*, const char*, int32_t) {} - static void OnOutputMode(void*, wl_output*, uint32_t, int32_t, int32_t, int32_t) {} - static void OnOutputDone(void*, wl_output*) {} + static void OnOutputMode(void*, wl_output* output, uint32_t, int32_t width, int32_t height, int32_t) + { + auto it = monitors.find(output); + ASSERT(it != monitors.end(), "Error: OnOutputMode called on unknown monitor"); + it->second.width = width; + it->second.height = height; + } + static void OnOutputDone(void*, wl_output* output) {} static void OnOutputScale(void*, wl_output*, int32_t) {} static void OnOutputName(void*, wl_output* output, const char* name) { - std::string nameStr = name; - auto it = monitors.find(nameStr); - if (it == monitors.end()) - { - LOG("Wayland: Registering monitor " << name << " at ID " << curID); - registeredMonitors = true; - Monitor mon = {nameStr, output, nullptr, curID++}; - monitors.try_emplace(nameStr, mon); - } - else - { - LOG("Wayland: Recovering monitor " << name << " at ID " << curID); - } + auto it = monitors.find(output); + ASSERT(it != monitors.end(), "Error: OnOutputName called on unknown monitor"); + it->second.name = name; + LOG("Wayland: Monitor at ID " << it->second.ID << " got name " << name); + registeredMonitor = true; } static void OnOutputDescription(void*, wl_output*, const char*) {} wl_output_listener outputListener = {OnOutputGeometry, OnOutputMode, OnOutputDone, OnOutputScale, OnOutputName, OnOutputDescription}; @@ -168,6 +156,10 @@ namespace Wayland if (strcmp(interface, "wl_output") == 0) { wl_output* output = (wl_output*)wl_registry_bind(registry, name, &wl_output_interface, 4); + Monitor mon = Monitor{"", name, 0, 0, nullptr, (uint32_t)monitors.size()}; + monitors.emplace(output, mon); + + LOG("Wayland: Register at ID " << mon.ID); wl_output_add_listener(output, &outputListener, nullptr); } if (strcmp(interface, "zext_workspace_manager_v1") == 0 && !Config::Get().useHyprlandIPC) @@ -176,7 +168,31 @@ namespace Wayland zext_workspace_manager_v1_add_listener(workspaceManager, &workspaceManagerListener, nullptr); } } - static void OnRegistryRemove(void*, wl_registry*, uint32_t) {} + static void OnRegistryRemove(void*, wl_registry*, uint32_t name) + { + auto it = std::find_if(monitors.begin(), monitors.end(), + [&](const std::pair& elem) + { + return elem.second.wlName == name; + }); + if (it != monitors.end()) + { + LOG("Wayland: Removing monitor " << it->second.name << " at ID " << it->second.ID); + // Monitor has been removed. Update the ids of the other accordingly + for (auto& mon : monitors) + { + if (mon.second.ID > it->second.ID) + { + mon.second.ID -= 1; + auto name = mon.second.name.empty() ? "" : mon.second.name; + LOG("Wayland: " << name << " got new ID " << mon.second.ID); + } + } + registeredMonitor = true; + monitors.erase(it); + } + } + wl_registry_listener registryListener = {OnRegistryAdd, OnRegistryRemove}; // Dispatch events. @@ -201,8 +217,8 @@ namespace Wayland wl_registry_add_listener(registry, ®istryListener, nullptr); wl_display_roundtrip(display); - WaitFor(registeredMonitors); - registeredMonitors = false; + WaitFor(registeredMonitor); + registeredMonitor = false; if (!workspaceManager && !Config::Get().useHyprlandIPC) { @@ -255,7 +271,6 @@ namespace Wayland registeredGroup = false; registeredWorkspace = false; registeredWorkspaceInfo = false; - return; } void Shutdown() @@ -264,7 +279,33 @@ namespace Wayland wl_display_disconnect(display); } - const std::unordered_map& GetMonitors() + std::string GtkMonitorIDToName(int32_t monitorID) + { + auto it = std::find_if(monitors.begin(), monitors.end(), + [&](const std::pair& el) + { + return el.second.ID == (uint32_t)monitorID; + }); + if (it == monitors.end()) + { + LOG("Wayland: No monitor registered with ID " << monitorID); + return ""; + } + return it->second.name; + } + int32_t NameToGtkMonitorID(const std::string& name) + { + auto it = std::find_if(monitors.begin(), monitors.end(), + [&](const std::pair& el) + { + return el.second.name == name; + }); + if (it == monitors.end()) + return -1; + return it->second.ID; + } + + const std::unordered_map& GetMonitors() { return monitors; } diff --git a/src/Wayland.h b/src/Wayland.h index a656bc9..9f92e22 100644 --- a/src/Wayland.h +++ b/src/Wayland.h @@ -9,8 +9,11 @@ namespace Wayland struct Monitor { std::string name; - wl_output* output; + uint32_t wlName; + int32_t width; + int32_t height; zext_workspace_group_handle_v1* workspaceGroup; + // The Gdk monitor index. This is only a hacky approximation, since there is no way to get the wl_output from a GdkMonitor uint32_t ID; }; @@ -29,9 +32,13 @@ namespace Wayland void Init(); void PollEvents(); - const std::unordered_map& GetMonitors(); + const std::unordered_map& GetMonitors(); const std::unordered_map& GetWorkspaceGroups(); const std::unordered_map& GetWorkspaces(); + // Returns the connector name of the monitor + std::string GtkMonitorIDToName(int32_t monitorID); + int32_t NameToGtkMonitorID(const std::string& name); + void Shutdown(); } diff --git a/src/Window.cpp b/src/Window.cpp index 4d7b3b8..2f52cf7 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -1,14 +1,15 @@ #include "Window.h" #include "Common.h" #include "CSS.h" +#include "Wayland.h" -#include -#include +#include #include #include -Window::Window(int32_t monitor) : m_MonitorID(monitor) {} +Window::Window(int32_t monitor) : m_MonitorName(Wayland::GtkMonitorIDToName(monitor)) {} +Window::Window(const std::string& monitor) : m_MonitorName(monitor) {} Window::~Window() { @@ -21,6 +22,8 @@ Window::~Window() void Window::Init(const std::string& overideConfigLocation) { + m_TargetMonitor = m_MonitorName; + gtk_init(NULL, NULL); // Style @@ -30,13 +33,14 @@ void Window::Init(const std::string& overideConfigLocation) GdkDisplay* defaultDisplay = gdk_display_get_default(); ASSERT(defaultDisplay != nullptr, "Cannot get display!"); - if (m_MonitorID != -1) + if (!m_MonitorName.empty()) { - m_Monitor = gdk_display_get_monitor(defaultDisplay, m_MonitorID); - ASSERT(m_Monitor, "Cannot get monitor!"); + m_Monitor = gdk_display_get_monitor(defaultDisplay, Wayland::NameToGtkMonitorID(m_MonitorName)); + ASSERT(m_Monitor, "Cannot get monitor \"" << m_MonitorName << "\"!"); } else { + LOG("Window: Requested monitor not found. Falling back to current monitor!") m_Monitor = gdk_display_get_primary_monitor(defaultDisplay); } @@ -55,12 +59,87 @@ void Window::Init(const std::string& overideConfigLocation) void Window::Run() { - ASSERT(m_MainWidget, "Main Widget not set!"); + Create(); + while (gtk_main_iteration()) + { + if (bHandleMonitorChanges) + { + // Flush the event loop + while (gtk_events_pending()) + { + if (!gtk_main_iteration()) + break; + } + LOG("Window: Handling monitor changes"); + bHandleMonitorChanges = false; + + if (m_MonitorName == m_TargetMonitor) + { + // Don't care + continue; + } + // Process Wayland + Wayland::PollEvents(); + + GdkDisplay* display = gdk_display_get_default(); + auto& mons = Wayland::GetMonitors(); + + // HACK: Discrepancies are mostly caused by the HEADLESS monitor. Assume that. + bool bGotHeadless = (size_t)gdk_display_get_n_monitors(display) != mons.size(); + if (bGotHeadless) + { + LOG("Window: Found discrepancy between GDK and Wayland!"); + } + + // Try to find our target monitor + auto it = std::find_if(mons.begin(), mons.end(), + [&](const std::pair& mon) + { + return mon.second.name == m_TargetMonitor; + }); + if (it != mons.end()) + { + // Found target monitor, snap back. + if (m_MainWidget) + Destroy(); + m_MonitorName = m_TargetMonitor; + m_Monitor = gdk_display_get_monitor(display, bGotHeadless ? it->second.ID + 1 : it->second.ID); + Create(); + continue; + } + + // We haven't yet created, check if we can. + if (m_MainWidget == nullptr) + { + // Find a non-headless monitor + auto it = std::find_if(mons.begin(), mons.end(), + [&](const std::pair& mon) + { + return mon.second.name.find("HEADLESS") == std::string::npos; + }); + if (it == mons.end()) + continue; + m_MonitorName = it->second.name; + m_Monitor = gdk_display_get_monitor(display, bGotHeadless ? it->second.ID + 1 : it->second.ID); + Create(); + continue; + } + } + } +} + +void Window::Create() +{ + LOG("Window: Create on monitor " << m_MonitorName); m_Window = (GtkWindow*)gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_layer_init_for_window(m_Window); + // Notify our main method, that we want to init + OnWidget(); + + ASSERT(m_MainWidget, "Main Widget not set!"); + switch (m_Layer) { case Layer::Top: gtk_layer_set_layer(m_Window, GTK_LAYER_SHELL_LAYER_TOP); break; @@ -94,13 +173,18 @@ void Window::Run() Widget::CreateAndAddWidget(m_MainWidget.get(), (GtkWidget*)m_Window); gtk_widget_show_all((GtkWidget*)m_Window); +} - gtk_main(); +void Window::Destroy() +{ + LOG("Window: Destroy"); + m_MainWidget = nullptr; + gtk_widget_destroy((GtkWidget*)m_Window); } void Window::Close() { - gtk_widget_hide((GtkWidget*)m_Window); + Destroy(); gtk_main_quit(); } @@ -159,42 +243,52 @@ void Window::SetMargin(Anchor anchor, int32_t margin) int Window::GetWidth() const { - GdkRectangle rect{}; + // gdk_monitor_get_geometry is really unreliable for some reason. + // Use our wayland backend instead + + /*GdkRectangle rect{}; gdk_monitor_get_geometry(m_Monitor, &rect); - return rect.width; + return rect.width;*/ + auto& mons = Wayland::GetMonitors(); + auto it = std::find_if(mons.begin(), mons.end(), + [&](const std::pair& mon) + { + return mon.second.name == m_MonitorName; + }); + ASSERT(it != mons.end(), "Window: Couldn't find monitor"); + return it->second.width; } int Window::GetHeight() const { - GdkRectangle rect{}; + /*GdkRectangle rect{}; gdk_monitor_get_geometry(m_Monitor, &rect); - return rect.height; + return rect.height;*/ + + auto& mons = Wayland::GetMonitors(); + auto it = std::find_if(mons.begin(), mons.end(), + [&](const std::pair& mon) + { + return mon.second.name == m_MonitorName; + }); + ASSERT(it != mons.end(), "Window: Couldn't find monitor"); + return it->second.width; } -void Window::MonitorAdded(GdkDisplay* display, GdkMonitor* mon) +void Window::MonitorAdded(GdkDisplay*, GdkMonitor*) { - LOG("Window: Monitor added: " << mon); - if (!m_Monitor) - { - LOG("Window: Activating window"); - gtk_layer_set_monitor(m_Window, mon); - m_Monitor = mon; - gtk_widget_show_all((GtkWidget*)m_Window); - } + bHandleMonitorChanges = true; } -void Window::MonitorRemoved(GdkDisplay* display, GdkMonitor* mon) +void Window::MonitorRemoved(GdkDisplay*, GdkMonitor* mon) { - LOG("Window: Monitor removed: " << mon); + bHandleMonitorChanges = true; + // Immediately react if (mon == m_Monitor) { - // Hide the window, so it doesn't get rendered on an invalid monitor - gtk_widget_hide((GtkWidget*)m_Window); - // Notify gtk layer shell and redisplay window - gtk_layer_set_monitor(m_Window, nullptr); - m_Monitor = gtk_layer_get_monitor(m_Window); - LOG("Window: New Monitor: " << m_Monitor); - if (m_Monitor) - gtk_widget_show_all((GtkWidget*)m_Window); + LOG("Window: Current monitor removed!") + m_Monitor = nullptr; + m_MonitorName = ""; + Destroy(); } } diff --git a/src/Window.h b/src/Window.h index e7914bd..0ce5d87 100644 --- a/src/Window.h +++ b/src/Window.h @@ -23,6 +23,7 @@ class Window public: Window() = default; Window(int32_t monitor); + Window(const std::string& monitor); Window(Window&& window) noexcept = default; Window& operator=(Window&& other) noexcept = default; ~Window(); @@ -35,14 +36,23 @@ public: void SetAnchor(Anchor anchor) { m_Anchor = anchor; } void SetMargin(Anchor anchor, int32_t margin); void SetExclusive(bool exclusive) { m_Exclusive = exclusive; } - void SetLayer(Layer layer) { m_Layer = layer;} + void SetLayer(Layer layer) { m_Layer = layer; } void SetMainWidget(std::unique_ptr&& mainWidget); int GetWidth() const; int GetHeight() const; + // Returns the connector name of the currnet monitor + std::string GetName() const { return m_MonitorName; } + + // Callback when the widget should be recreated + std::function OnWidget; + private: + void Create(); + void Destroy(); + void UpdateMargin(); void LoadCSS(GtkCssProvider* provider); @@ -60,6 +70,13 @@ private: bool m_Exclusive = true; Layer m_Layer = Layer::Top; - int32_t m_MonitorID; + // The monitor we are currently on. + std::string m_MonitorName; + + // The monitor we want to be on. + std::string m_TargetMonitor; + GdkMonitor* m_Monitor = nullptr; + + bool bHandleMonitorChanges = false; }; diff --git a/src/Workspaces.cpp b/src/Workspaces.cpp index 249b771..9f10f3b 100644 --- a/src/Workspaces.cpp +++ b/src/Workspaces.cpp @@ -12,19 +12,19 @@ namespace Workspaces using WaylandWorkspaceGroup = ::Wayland::WorkspaceGroup; using WaylandWorkspace = ::Wayland::Workspace; - static uint32_t lastPolledMonitor; - void PollStatus(uint32_t monitorID, uint32_t) + static std::string lastPolledMonitor; + void PollStatus(const std::string& monitor, uint32_t) { ::Wayland::PollEvents(); - lastPolledMonitor = monitorID; + lastPolledMonitor = monitor; } System::WorkspaceStatus GetStatus(uint32_t workspaceId) { auto& mons = ::Wayland::GetMonitors(); auto it = std::find_if(mons.begin(), mons.end(), - [&](const std::pair& mon) + [&](const std::pair& mon) { - return mon.second.ID == workspaceId; + return mon.second.name == lastPolledMonitor; }); if (it == mons.end()) { @@ -147,7 +147,7 @@ namespace Workspaces static std::vector workspaceStati; - void PollStatus(uint32_t monitorID, uint32_t numWorkspaces) + void PollStatus(const std::string& monitor, uint32_t numWorkspaces) { if (RuntimeConfig::Get().hasWorkspaces == false) { @@ -182,11 +182,11 @@ namespace Workspaces parseIdx = 0; while ((parseIdx = monitors.find("Monitor ", parseIdx)) != std::string::npos) { - // Goto ( and remove ID (=Advance 4 spaces, 1 for (, two for ID, one for space) - size_t begMonNum = monitors.find('(', parseIdx) + 4; - size_t endMonNum = monitors.find(')', begMonNum); + // Query monitor name + // Format: Monitor (ID ) + size_t begMonNum = monitors.find(' ', parseIdx) + 1; + size_t endMonNum = monitors.find(' ', begMonNum); std::string mon = monitors.substr(begMonNum, endMonNum - begMonNum); - int32_t monIdx = std::atoi(mon.c_str()); // Parse active workspace parseIdx = monitors.find("active workspace: ", parseIdx); @@ -205,7 +205,7 @@ namespace Workspaces if (wsId >= 1 && wsId <= (int32_t)numWorkspaces) { - if ((uint32_t)monIdx == monitorID) + if (mon == monitor) { if (focused) { @@ -248,16 +248,16 @@ namespace Workspaces #endif } - void PollStatus(uint32_t monitorID, uint32_t numWorkspaces) + void PollStatus(const std::string& monitor, uint32_t numWorkspaces) { #ifdef WITH_HYPRLAND if (Config::Get().useHyprlandIPC) { - Hyprland::PollStatus(monitorID, numWorkspaces); + Hyprland::PollStatus(monitor, numWorkspaces); return; } #endif - Wayland::PollStatus(monitorID, numWorkspaces); + Wayland::PollStatus(monitor, numWorkspaces); } System::WorkspaceStatus GetStatus(uint32_t workspaceId) diff --git a/src/Workspaces.h b/src/Workspaces.h index 6981667..884ad11 100644 --- a/src/Workspaces.h +++ b/src/Workspaces.h @@ -16,7 +16,7 @@ namespace Workspaces { void Init(); - void PollStatus(uint32_t monitorID, uint32_t numWorkspaces); + void PollStatus(const std::string& monitor, uint32_t numWorkspaces); System::WorkspaceStatus GetStatus(uint32_t workspaceId); diff --git a/src/gBar.cpp b/src/gBar.cpp index 16c1f09..ddeca96 100644 --- a/src/gBar.cpp +++ b/src/gBar.cpp @@ -16,7 +16,7 @@ const char* bluetoothTmpFilePath = "/tmp/gBar__bluetooth"; static bool tmpFileOpen = false; -void OpenAudioFlyin(Window& window, int32_t monitor, AudioFlyin::Type type) +void OpenAudioFlyin(Window& window, const std::string& monitor, AudioFlyin::Type type) { tmpFileOpen = true; if (access(audioTmpFilePath, F_OK) != 0) @@ -71,10 +71,57 @@ void PrintHelp() "\t[plugin] \tTries to open and run the plugin lib[plugin].so\n"); } +void CreateWidget(const std::string& widget, Window& window) +{ + if (widget == "bar") + { + Bar::Create(window, window.GetName()); + } + else if (widget == "audio") + { + OpenAudioFlyin(window, window.GetName(), AudioFlyin::Type::Speaker); + } + else if (widget == "mic") + { + OpenAudioFlyin(window, window.GetName(), AudioFlyin::Type::Microphone); + } +#ifdef WITH_BLUEZ + else if (widget == "bluetooth") + { + if (RuntimeConfig::Get().hasBlueZ) + { + if (access(bluetoothTmpFilePath, F_OK) != 0) + { + tmpFileOpen = true; + FILE* bluetoothTmpFile = fopen(bluetoothTmpFilePath, "w"); + BluetoothDevices::Create(window, window.GetName()); + fclose(bluetoothTmpFile); + } + else + { + // Already open, close + LOG("Bluetooth widget already open (/tmp/gBar__bluetooth exists)! Exiting..."); + exit(0); + } + } + else + { + LOG("Blutooth disabled, cannot open bluetooth widget!"); + exit(1); + } + } +#endif + else + { + Plugin::LoadWidgetFromPlugin(widget, window, window.GetName()); + } +} + int main(int argc, char** argv) { std::string widget; int32_t monitor = -1; + std::string monitorName; std::string overrideConfigLocation = ""; // Arg parsing @@ -83,20 +130,27 @@ int main(int argc, char** argv) std::string arg = argv[i]; if (arg.size() < 1 || arg[0] != '-') { - // This must be the widget selection + // This must be the widget selection. widget = arg; if (i + 1 < argc) { std::string mon = argv[i + 1]; - if (mon.size() < 1 || mon[0] != '-') + + // Check if a monitor was supplied + if (mon.empty() || mon[0] == '-') + continue; + + if (std::isdigit(mon[0])) { - // Next comes the monitor + // Monitor using ID monitor = std::stoi(mon); i += 1; } else { - // Not the monitor + // Monitor using connector name + monitorName = std::move(mon); + i += 1; continue; } } @@ -133,51 +187,21 @@ int main(int argc, char** argv) signal(SIGINT, CloseTmpFiles); System::Init(overrideConfigLocation); - Window window(monitor); - window.Init(overrideConfigLocation); - if (widget == "bar") + Window window; + if (monitor != -1) { - Bar::Create(window, monitor); + window = Window(monitor); } - else if (widget == "audio") - { - OpenAudioFlyin(window, monitor, AudioFlyin::Type::Speaker); - } - else if (widget == "mic") - { - OpenAudioFlyin(window, monitor, AudioFlyin::Type::Microphone); - } -#ifdef WITH_BLUEZ - else if (widget == "bluetooth") - { - if (RuntimeConfig::Get().hasBlueZ) - { - if (access(bluetoothTmpFilePath, F_OK) != 0) - { - tmpFileOpen = true; - FILE* bluetoothTmpFile = fopen(bluetoothTmpFilePath, "w"); - BluetoothDevices::Create(window, monitor); - fclose(bluetoothTmpFile); - } - else - { - // Already open, close - LOG("Bluetooth widget already open (/tmp/gBar__bluetooth exists)! Exiting..."); - exit(0); - } - } - else - { - LOG("Blutooth disabled, cannot open bluetooth widget!"); - exit(1); - } - } -#endif else { - Plugin::LoadWidgetFromPlugin(widget, window, monitor); + window = Window(monitorName); } + window.Init(overrideConfigLocation); + window.OnWidget = [&]() + { + CreateWidget(widget, window); + }; window.Run(); System::FreeResources();