Bug 1732682 [Wayland] Get screen sizes from workarea on KDE/Sway r=rmader

- Use gdk_screen_get_monitor_workarea() on KDE/Sway to get screen sizes as it's reported correctly there.
- Remove unused code.

Differential Revision: https://phabricator.services.mozilla.com/D127261
This commit is contained in:
stransky 2021-10-04 12:13:38 +00:00
parent 44f80d4fa7
commit bf7116a05c
2 changed files with 31 additions and 84 deletions

View File

@ -129,30 +129,43 @@ static uint32_t GetGTKPixelDepth() {
return gdk_visual_get_depth(visual);
}
static bool IsGNOMECompositor() {
const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP");
return currentDesktop && strstr(currentDesktop, "GNOME") != nullptr;
}
static already_AddRefed<Screen> MakeScreenGtk(GdkScreen* aScreen,
gint aMonitorNum) {
GdkRectangle monitor;
GdkRectangle workarea;
gdk_screen_get_monitor_geometry(aScreen, aMonitorNum, &monitor);
gdk_screen_get_monitor_workarea(aScreen, aMonitorNum, &workarea);
gint gdkScaleFactor = ScreenHelperGTK::GetGTKMonitorScaleFactor(aMonitorNum);
// gdk_screen_get_monitor_geometry / workarea returns application pixels
// (desktop pixels), so we need to convert it to device pixels with
// gdkScaleFactor on X11.
// GNOME/Wayland reports scales differently (Bug 1732682).
gint geometryScaleFactor = 1;
if (GdkIsX11Display()) {
if (GdkIsX11Display() || (GdkIsWaylandDisplay() && !IsGNOMECompositor())) {
geometryScaleFactor = gdkScaleFactor;
}
LayoutDeviceIntRect rect(monitor.x * geometryScaleFactor,
monitor.y * geometryScaleFactor,
monitor.width * geometryScaleFactor,
monitor.height * geometryScaleFactor);
LayoutDeviceIntRect rect;
GdkRectangle workarea;
gdk_screen_get_monitor_workarea(aScreen, aMonitorNum, &workarea);
LayoutDeviceIntRect availRect(workarea.x * geometryScaleFactor,
workarea.y * geometryScaleFactor,
workarea.width * geometryScaleFactor,
workarea.height * geometryScaleFactor);
if (GdkIsX11Display()) {
GdkRectangle monitor;
gdk_screen_get_monitor_geometry(aScreen, aMonitorNum, &monitor);
rect = LayoutDeviceIntRect(monitor.x * geometryScaleFactor,
monitor.y * geometryScaleFactor,
monitor.width * geometryScaleFactor,
monitor.height * geometryScaleFactor);
} else {
// We use Gtk workarea on Wayland as it matches our needs (Bug 1732682).
rect = availRect;
}
uint32_t pixelDepth = GetGTKPixelDepth();
@ -173,11 +186,11 @@ static already_AddRefed<Screen> MakeScreenGtk(GdkScreen* aScreen,
dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT);
}
MOZ_LOG(sScreenLog, LogLevel::Debug,
("New screen [%d %d %d %d (%d %d %d %d) %d %f %f %f]", rect.x, rect.y,
rect.width, rect.height, availRect.x, availRect.y, availRect.width,
availRect.height, pixelDepth, contentsScale.scale,
defaultCssScale.scale, dpi));
LOG_SCREEN(
("New monitor %d size [%d,%d -> %d x %d] depth %d scale %f CssScale %f "
"DPI %f ]",
aMonitorNum, rect.x, rect.y, rect.width, rect.height, pixelDepth,
contentsScale.scale, defaultCssScale.scale, dpi));
RefPtr<Screen> screen = new Screen(rect, availRect, pixelDepth, pixelDepth,
contentsScale, defaultCssScale, dpi);
return screen.forget();
@ -315,57 +328,12 @@ static bool GdkMonitorGetWorkarea(GdkMonitor* monitor, GdkRectangle* workarea) {
return true;
}
bool ScreenGetterWayland::MonitorUsesNonIntegerScale(int aMonitor) {
static auto s_gdk_display_get_n_monitors =
(int (*)(GdkDisplay*))dlsym(RTLD_DEFAULT, "gdk_display_get_n_monitors");
static auto s_gdk_display_get_monitor = (GdkMonitor * (*)(GdkDisplay*, int))
dlsym(RTLD_DEFAULT, "gdk_display_get_monitor");
if (!s_gdk_display_get_n_monitors || !s_gdk_display_get_monitor) {
return false;
}
int monitorNum = s_gdk_display_get_n_monitors(gdk_display_get_default());
for (int m = 0; m < monitorNum; m++) {
GdkMonitor* gdkMonitor =
s_gdk_display_get_monitor(gdk_display_get_default(), m);
if (!gdkMonitor) {
return false;
}
GdkRectangle workArea;
if (!GdkMonitorGetWorkarea(gdkMonitor, &workArea)) {
return false;
}
LOG_SCREEN(("Monitor %d Gtk workarea size %d x %d", m, workArea.width,
workArea.height));
LOG_SCREEN(("Monitor %d wl_output size %d x %d", aMonitor,
mMonitors[aMonitor].width, mMonitors[aMonitor].height));
if (mMonitors[aMonitor].x == workArea.x &&
mMonitors[aMonitor].y == workArea.y) {
// When non-integer scale is used, wl_output reports framebuffer size
// but Gtk reports downscaled logical size.
return workArea.width < mMonitors[aMonitor].width &&
workArea.height < mMonitors[aMonitor].height;
}
}
return false;
}
already_AddRefed<Screen> ScreenGetterWayland::MakeScreenWayland(gint aMonitor) {
MonitorConfig monitor = mMonitors[aMonitor];
// On GNOME/Mutter we use results from wl_output directly
LayoutDeviceIntRect rect(monitor.x, monitor.y, monitor.width, monitor.height);
// Non integer scales are downscaled from upper scales so report screen sizes
// as bigger ones.
if (MonitorUsesNonIntegerScale(aMonitor)) {
LOG_SCREEN(("Monitor %d uses non-integer scale", aMonitor));
rect.width *= monitor.scale;
rect.height *= monitor.scale;
}
uint32_t pixelDepth = GetGTKPixelDepth();
// Use per-monitor scaling factor in gtk/wayland, or 1.0 otherwise.
@ -438,7 +406,7 @@ int ScreenGetterWayland::GetMonitorForWindow(nsWindow* aWindow) {
}
for (unsigned int i = 0; i < mMonitors.Length(); i++) {
// Although Gtk/Mutter are very creative in reporting various screens sizes
// Although Gtk/Mutter is very creative in reporting various screens sizes
// we can rely on Gtk work area start position to match wl_output.
if (mMonitors[i].x == workArea.x && mMonitors[i].y == workArea.y) {
LOG_SCREEN((" monitor %d values %d %d -> %d x %d", i, mMonitors[i].x,
@ -461,29 +429,12 @@ RefPtr<nsIScreen> ScreenGetterWayland::GetScreenForWindow(nsWindow* aWindow) {
}
return mScreenList[monitor];
}
void ScreenGetterWayland::GetScreenRectForWindow(nsWindow* aWindow,
GdkRectangle* aRect) {
int monitor = GetMonitorForWindow(aWindow);
if (monitor < 0) {
// fallback to first monitor
monitor = 0;
}
aRect->x = aRect->y = 0;
aRect->width = mMonitors[monitor].width;
aRect->height = mMonitors[monitor].height;
}
#endif
RefPtr<nsIScreen> ScreenHelperGTK::GetScreenForWindow(nsWindow* aWindow) {
return gScreenGetter->GetScreenForWindow(aWindow);
}
void ScreenHelperGTK::GetScreenRectForWindow(nsWindow* aWindow,
GdkRectangle* aRect) {
gScreenGetter->GetScreenRectForWindow(aWindow, aRect);
}
gint ScreenHelperGTK::GetGTKMonitorScaleFactor(gint aMonitorNum) {
GdkScreen* screen = gdk_screen_get_default();
return gdk_screen_get_monitor_scale_factor(screen, aMonitorNum);
@ -494,9 +445,8 @@ ScreenHelperGTK::ScreenHelperGTK() {
// Use ScreenGetterWayland on Gnome/Mutter only. It uses additional wl_output
// to track screen size changes (which are wrongly reported by mutter)
// and causes issues on Sway (Bug 1730476).
const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP");
if (GdkIsWaylandDisplay() && currentDesktop &&
strstr(currentDesktop, "GNOME")) {
// https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/3941
if (GdkIsWaylandDisplay() && IsGNOMECompositor()) {
gScreenGetter = mozilla::MakeUnique<ScreenGetterWayland>();
}
#endif

View File

@ -31,7 +31,6 @@ class ScreenGetter {
virtual RefPtr<nsIScreen> GetScreenForWindow(nsWindow* aWindow) {
return nullptr;
}
virtual void GetScreenRectForWindow(nsWindow* aWindow, GdkRectangle* aRect){};
};
class ScreenGetterGtk : public ScreenGetter {
@ -84,7 +83,6 @@ class ScreenGetterWayland : public ScreenGetter {
already_AddRefed<Screen> MakeScreenWayland(gint aMonitor);
RefPtr<nsIScreen> GetScreenForWindow(nsWindow* aWindow);
void GetScreenRectForWindow(nsWindow* aWindow, GdkRectangle* aRect);
// For internal use from signal callback functions
void RefreshScreens();
@ -107,7 +105,6 @@ class ScreenHelperGTK final : public ScreenManager::Helper {
static gint GetGTKMonitorScaleFactor(gint aMonitorNum = 0);
static RefPtr<nsIScreen> GetScreenForWindow(nsWindow* aWindow);
static void GetScreenRectForWindow(nsWindow* aWindow, GdkRectangle* aRect);
};
} // namespace widget