Loading widget/gtk/ScreenHelperGTK.cpp +83 −24 Original line number Diff line number Diff line Loading @@ -129,14 +129,11 @@ 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); Loading @@ -148,12 +145,11 @@ static already_AddRefed<Screen> MakeScreenGtk(GdkScreen* aScreen, geometryScaleFactor = gdkScaleFactor; } // GNOME reports scales differently (Bug 1730476). if (GdkIsWaylandDisplay() && !IsGNOMECompositor()) { geometryScaleFactor = gdkScaleFactor; } LayoutDeviceIntRect rect(workarea.x * geometryScaleFactor, LayoutDeviceIntRect rect(monitor.x * geometryScaleFactor, monitor.y * geometryScaleFactor, monitor.width * geometryScaleFactor, monitor.height * geometryScaleFactor); LayoutDeviceIntRect availRect(workarea.x * geometryScaleFactor, workarea.y * geometryScaleFactor, workarea.width * geometryScaleFactor, workarea.height * geometryScaleFactor); Loading @@ -177,12 +173,12 @@ static already_AddRefed<Screen> MakeScreenGtk(GdkScreen* aScreen, dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT); } 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, rect, pixelDepth, pixelDepth, 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)); RefPtr<Screen> screen = new Screen(rect, availRect, pixelDepth, pixelDepth, contentsScale, defaultCssScale, dpi); return screen.forget(); } Loading Loading @@ -319,12 +315,57 @@ 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. Loading Loading @@ -397,7 +438,7 @@ int ScreenGetterWayland::GetMonitorForWindow(nsWindow* aWindow) { } for (unsigned int i = 0; i < mMonitors.Length(); i++) { // Although Gtk/Mutter is very creative in reporting various screens sizes // Although Gtk/Mutter are 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, Loading @@ -420,12 +461,29 @@ 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); Loading @@ -436,8 +494,9 @@ 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). // https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/3941 if (GdkIsWaylandDisplay() && IsGNOMECompositor()) { const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP"); if (GdkIsWaylandDisplay() && currentDesktop && strstr(currentDesktop, "GNOME")) { gScreenGetter = mozilla::MakeUnique<ScreenGetterWayland>(); } #endif Loading widget/gtk/ScreenHelperGTK.h +3 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ class ScreenGetter { virtual RefPtr<nsIScreen> GetScreenForWindow(nsWindow* aWindow) { return nullptr; } virtual void GetScreenRectForWindow(nsWindow* aWindow, GdkRectangle* aRect){}; }; class ScreenGetterGtk : public ScreenGetter { Loading Loading @@ -83,6 +84,7 @@ 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(); Loading @@ -105,6 +107,7 @@ 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 Loading Loading
widget/gtk/ScreenHelperGTK.cpp +83 −24 Original line number Diff line number Diff line Loading @@ -129,14 +129,11 @@ 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); Loading @@ -148,12 +145,11 @@ static already_AddRefed<Screen> MakeScreenGtk(GdkScreen* aScreen, geometryScaleFactor = gdkScaleFactor; } // GNOME reports scales differently (Bug 1730476). if (GdkIsWaylandDisplay() && !IsGNOMECompositor()) { geometryScaleFactor = gdkScaleFactor; } LayoutDeviceIntRect rect(workarea.x * geometryScaleFactor, LayoutDeviceIntRect rect(monitor.x * geometryScaleFactor, monitor.y * geometryScaleFactor, monitor.width * geometryScaleFactor, monitor.height * geometryScaleFactor); LayoutDeviceIntRect availRect(workarea.x * geometryScaleFactor, workarea.y * geometryScaleFactor, workarea.width * geometryScaleFactor, workarea.height * geometryScaleFactor); Loading @@ -177,12 +173,12 @@ static already_AddRefed<Screen> MakeScreenGtk(GdkScreen* aScreen, dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT); } 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, rect, pixelDepth, pixelDepth, 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)); RefPtr<Screen> screen = new Screen(rect, availRect, pixelDepth, pixelDepth, contentsScale, defaultCssScale, dpi); return screen.forget(); } Loading Loading @@ -319,12 +315,57 @@ 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. Loading Loading @@ -397,7 +438,7 @@ int ScreenGetterWayland::GetMonitorForWindow(nsWindow* aWindow) { } for (unsigned int i = 0; i < mMonitors.Length(); i++) { // Although Gtk/Mutter is very creative in reporting various screens sizes // Although Gtk/Mutter are 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, Loading @@ -420,12 +461,29 @@ 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); Loading @@ -436,8 +494,9 @@ 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). // https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/3941 if (GdkIsWaylandDisplay() && IsGNOMECompositor()) { const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP"); if (GdkIsWaylandDisplay() && currentDesktop && strstr(currentDesktop, "GNOME")) { gScreenGetter = mozilla::MakeUnique<ScreenGetterWayland>(); } #endif Loading
widget/gtk/ScreenHelperGTK.h +3 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ class ScreenGetter { virtual RefPtr<nsIScreen> GetScreenForWindow(nsWindow* aWindow) { return nullptr; } virtual void GetScreenRectForWindow(nsWindow* aWindow, GdkRectangle* aRect){}; }; class ScreenGetterGtk : public ScreenGetter { Loading Loading @@ -83,6 +84,7 @@ 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(); Loading @@ -105,6 +107,7 @@ 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 Loading