mirror of
https://github.com/scorpion-26/gBar.git
synced 2024-11-22 11:12:49 +00:00
Don't crash on monitor remove
gBar no longer crashes when it's monitor is removed and is instead evacuated onto another monitor or the next monitor added. We don't change any monitor indices etc., which results in some glitchy results
This commit is contained in:
parent
097c3d97e7
commit
18170ab1c7
5 changed files with 93 additions and 17 deletions
|
@ -8,7 +8,7 @@
|
|||
namespace Wayland
|
||||
{
|
||||
// There's probably a better way to avoid the LUTs
|
||||
static std::unordered_map<uint32_t, Monitor> monitors;
|
||||
static std::unordered_map<std::string, Monitor> monitors;
|
||||
static std::unordered_map<zext_workspace_group_handle_v1*, WorkspaceGroup> workspaceGroups;
|
||||
static std::unordered_map<zext_workspace_handle_v1*, Workspace> 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<uint32_t, Monitor>& mon)
|
||||
[&](const std::pair<std::string, Monitor>& 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<uint32_t, Monitor>& mon)
|
||||
[&](const std::pair<std::string, Monitor>& 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<zext_workspace_handle_v1*, Workspace>& 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<uint32_t, Monitor>& GetMonitors()
|
||||
const std::unordered_map<std::string, Monitor>& GetMonitors()
|
||||
{
|
||||
return monitors;
|
||||
}
|
||||
|
|
|
@ -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<uint32_t, Monitor>& GetMonitors();
|
||||
const std::unordered_map<std::string, Monitor>& GetMonitors();
|
||||
const std::unordered_map<zext_workspace_group_handle_v1*, WorkspaceGroup>& GetWorkspaceGroups();
|
||||
const std::unordered_map<zext_workspace_handle_v1*, Workspace>& GetWorkspaces();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<std::string, ::Wayland::Monitor>& 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());
|
||||
|
|
Loading…
Reference in a new issue