diff --git a/src/Wayland.cpp b/src/Wayland.cpp index 8bfad9a..f28a843 100644 --- a/src/Wayland.cpp +++ b/src/Wayland.cpp @@ -8,7 +8,7 @@ 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; @@ -28,9 +28,16 @@ namespace Wayland // Workspace Callbacks static void OnWorkspaceName(void*, zext_workspace_handle_v1* workspace, const char* name) { - workspaces[workspace].id = std::stoul(name); - LOG("Workspace ID: " << workspaces[workspace].id); - registeredWorkspaceInfo = true; + try + { + workspaces[workspace].id = std::stoul(name); + LOG("Workspace ID: " << workspaces[workspace].id); + registeredWorkspaceInfo = true; + } + catch (const std::invalid_argument&) + { + LOG("Wayland: Invalid WS name: " << name); + } } static void OnWorkspaceGeometry(void*, zext_workspace_handle_v1*, wl_array*) {} static void OnWorkspaceState(void*, zext_workspace_handle_v1* ws, wl_array* arrState) @@ -67,6 +74,13 @@ namespace Wayland workspaces.erase(ws); LOG("Wayland: Removed workspace!"); + if (group.lastActiveWorkspace == ws) + { + if (group.workspaces.size()) + group.lastActiveWorkspace = group.workspaces[0]; + else + group.lastActiveWorkspace = nullptr; + } } zext_workspace_handle_v1_listener workspaceListener = {OnWorkspaceName, OnWorkspaceGeometry, OnWorkspaceState, OnWorkspaceRemove}; @@ -74,7 +88,7 @@ namespace Wayland 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) + [&](const std::pair& mon) { return mon.second.output == output; }); @@ -85,7 +99,7 @@ namespace Wayland 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) + [&](const std::pair& mon) { return mon.second.output == output; }); @@ -131,9 +145,19 @@ namespace Wayland static void OnOutputScale(void*, wl_output*, int32_t) {} static void OnOutputName(void*, wl_output* output, const char* name) { - LOG("Wayland: Registering monitor " << name << " at ID " << curID); - registeredMonitors = true; - monitors.try_emplace(curID++, Monitor{name, output, nullptr}); + 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); + } } static void OnOutputDescription(void*, wl_output*, const char*) {} wl_output_listener outputListener = {OnOutputGeometry, OnOutputMode, OnOutputDone, OnOutputScale, OnOutputName, OnOutputDescription}; @@ -198,7 +222,7 @@ namespace Wayland auto workspaceIt = std::find_if(workspaces.begin(), workspaces.end(), [&](const std::pair& ws) { - return ws.second.id == monitor.first + 1; + return ws.second.id == monitor.second.ID + 1; }); if (workspaceIt != workspaces.end()) { @@ -240,7 +264,7 @@ namespace Wayland wl_display_disconnect(display); } - const std::unordered_map& GetMonitors() + const std::unordered_map& GetMonitors() { return monitors; } diff --git a/src/Wayland.h b/src/Wayland.h index 1c2c18f..a656bc9 100644 --- a/src/Wayland.h +++ b/src/Wayland.h @@ -11,6 +11,7 @@ namespace Wayland std::string name; wl_output* output; zext_workspace_group_handle_v1* workspaceGroup; + uint32_t ID; }; struct Workspace @@ -28,7 +29,7 @@ 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(); diff --git a/src/Window.cpp b/src/Window.cpp index d21b096..4d7b3b8 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -39,6 +39,18 @@ void Window::Init(const std::string& overideConfigLocation) { m_Monitor = gdk_display_get_primary_monitor(defaultDisplay); } + + // Register monitor added/removed callbacks + auto monAdded = [](GdkDisplay* display, GdkMonitor* mon, void* window) + { + ((Window*)window)->MonitorAdded(display, mon); + }; + g_signal_connect(defaultDisplay, "monitor-added", G_CALLBACK(+monAdded), this); + auto monRemoved = [](GdkDisplay* display, GdkMonitor* mon, void* window) + { + ((Window*)window)->MonitorRemoved(display, mon); + }; + g_signal_connect(defaultDisplay, "monitor-removed", G_CALLBACK(+monRemoved), this); } void Window::Run() @@ -158,3 +170,31 @@ int Window::GetHeight() const gdk_monitor_get_geometry(m_Monitor, &rect); return rect.height; } + +void Window::MonitorAdded(GdkDisplay* display, GdkMonitor* mon) +{ + 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); + } +} + +void Window::MonitorRemoved(GdkDisplay* display, GdkMonitor* mon) +{ + LOG("Window: Monitor removed: " << mon); + 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); + } +} diff --git a/src/Window.h b/src/Window.h index e11fef4..e7914bd 100644 --- a/src/Window.h +++ b/src/Window.h @@ -41,11 +41,15 @@ public: int GetWidth() const; int GetHeight() const; + private: void UpdateMargin(); void LoadCSS(GtkCssProvider* provider); + void MonitorAdded(GdkDisplay* display, GdkMonitor* monitor); + void MonitorRemoved(GdkDisplay* display, GdkMonitor* monitor); + GtkWindow* m_Window = nullptr; GtkApplication* m_App = nullptr; diff --git a/src/Workspaces.cpp b/src/Workspaces.cpp index 83b72ee..249b771 100644 --- a/src/Workspaces.cpp +++ b/src/Workspaces.cpp @@ -20,12 +20,18 @@ namespace Workspaces } System::WorkspaceStatus GetStatus(uint32_t workspaceId) { - const WaylandMonitor& monitor = ::Wayland::GetMonitors().at(lastPolledMonitor); - if (!monitor.output) + auto& mons = ::Wayland::GetMonitors(); + auto it = std::find_if(mons.begin(), mons.end(), + [&](const std::pair& mon) + { + return mon.second.ID == workspaceId; + }); + if (it == mons.end()) { LOG("Polled monitor doesn't exist!"); return System::WorkspaceStatus::Dead; } + const ::Wayland::Monitor& monitor = it->second; auto& workspaces = ::Wayland::GetWorkspaces(); auto workspaceIt = std::find_if(workspaces.begin(), workspaces.end(), @@ -156,9 +162,10 @@ namespace Workspaces std::string workspaces = DispatchIPC("/workspaces"); while ((parseIdx = workspaces.find("workspace ID ", parseIdx)) != std::string::npos) { - // Goto ( - size_t begWSNum = workspaces.find('(', parseIdx) + 1; - size_t endWSNum = workspaces.find(')', begWSNum); + // Advance two spaces + size_t begWSNum = workspaces.find(' ', parseIdx) + 1; + begWSNum = workspaces.find(' ', begWSNum) + 1; + size_t endWSNum = workspaces.find(' ', begWSNum); std::string ws = workspaces.substr(begWSNum, endWSNum - begWSNum); int32_t wsId = std::atoi(ws.c_str());