Skip to content

Commit a2906b3

Browse files
committed
Survive monitors being replaced, and report a primary one on Wayland
Display kept a bare GdkMonitor pointer. A GdkMonitor belongs to its GdkDisplay and is dropped and recreated on hotplug and whenever the compositor powers the outputs off and on, which left cached Display objects pointing at freed memory: GDK_IS_MONITOR assertions then fired on every getter (hundreds in a single run after the screen had blanked). Clear the pointer through a weak pointer so the getters fall back to their defaults, and make IsPrimary() use the first monitor when the display has no primary one, as it never does on Wayland.
1 parent 3f24428 commit a2906b3

1 file changed

Lines changed: 25 additions & 4 deletions

File tree

src/platform/linux/display_linux.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,32 @@ namespace nativeapi {
99
class Display::Impl {
1010
public:
1111
Impl() = default;
12-
Impl(GdkMonitor* monitor) : gdk_monitor_(monitor) {}
12+
Impl(GdkMonitor* monitor) { SetMonitor(monitor); }
13+
14+
~Impl() {
15+
if (gdk_monitor_) {
16+
g_object_remove_weak_pointer(G_OBJECT(gdk_monitor_), (gpointer*)&gdk_monitor_);
17+
}
18+
}
19+
20+
// A GdkMonitor is owned by its GdkDisplay, which drops and recreates monitors
21+
// on hotplug and whenever the compositor turns the outputs off and on again.
22+
// Let GDK clear the pointer so the getters below report defaults instead of
23+
// reading freed memory.
24+
void SetMonitor(GdkMonitor* monitor) {
25+
if (!monitor) {
26+
return;
27+
}
28+
gdk_monitor_ = monitor;
29+
g_object_add_weak_pointer(G_OBJECT(gdk_monitor_), (gpointer*)&gdk_monitor_);
30+
}
1331

1432
const DisplayId id_ = IdAllocator::Allocate<Display>();
1533
GdkMonitor* gdk_monitor_ = nullptr;
1634
};
1735

1836
Display::Display(void* display) : pimpl_(std::make_unique<Impl>()) {
19-
if (display) {
20-
pimpl_->gdk_monitor_ = (GdkMonitor*)display;
21-
}
37+
pimpl_->SetMonitor((GdkMonitor*)display);
2238
}
2339

2440
Display::~Display() = default;
@@ -75,6 +91,11 @@ bool Display::IsPrimary() const {
7591
return false;
7692
GdkDisplay* display = gdk_monitor_get_display(pimpl_->gdk_monitor_);
7793
GdkMonitor* primary = gdk_display_get_primary_monitor(display);
94+
if (!primary) {
95+
// Wayland has no notion of a primary monitor; match the first-monitor
96+
// convention DisplayManager::EnumerateNativeDisplays() uses.
97+
primary = gdk_display_get_monitor(display, 0);
98+
}
7899
return primary == pimpl_->gdk_monitor_;
79100
}
80101

0 commit comments

Comments
 (0)