Bug 1252408 - nsScreenMangerGtk should use GTK API instead of Xinerama. r?karlt
Curent code by Xinerama doesn't get vaild workarea size if using dual monitor. GTK3 has APIs to get workarea size and current screen size per monitor. So we should use it instead of Xinerama. Even if GTK2, it can get current screen size per monitor by GTK APIs.
MozReview-Commit-ID: 1uK3l3C5oT9
--- a/widget/gtk/mozgtk/mozgtk.c
+++ b/widget/gtk/mozgtk/mozgtk.c
@@ -54,16 +54,17 @@ STUB(gdk_property_get)
STUB(gdk_screen_get_default)
STUB(gdk_screen_get_display)
STUB(gdk_screen_get_font_options)
STUB(gdk_screen_get_height)
STUB(gdk_screen_get_height_mm)
STUB(gdk_screen_get_monitor_at_window)
STUB(gdk_screen_get_monitor_geometry)
STUB(gdk_screen_get_number)
+STUB(gdk_screen_get_n_monitors)
STUB(gdk_screen_get_resolution)
STUB(gdk_screen_get_rgba_visual)
STUB(gdk_screen_get_root_window)
STUB(gdk_screen_get_system_visual)
STUB(gdk_screen_get_width)
STUB(gdk_screen_height)
STUB(gdk_screen_is_composited)
STUB(gdk_screen_width)
@@ -509,16 +510,18 @@ STUB(gtk_window_unmaximize)
#ifdef GTK3_SYMBOLS
STUB(gdk_device_get_source)
STUB(gdk_device_manager_get_client_pointer)
STUB(gdk_disable_multidevice)
STUB(gdk_device_manager_list_devices)
STUB(gdk_display_get_device_manager)
STUB(gdk_error_trap_pop_ignored)
STUB(gdk_event_get_source_device)
+STUB(gdk_screen_get_monitor_workarea)
+STUB(gdk_screen_get_primary_monitor)
STUB(gdk_window_get_type)
STUB(gdk_x11_window_get_xid)
STUB(gdk_x11_display_get_type)
STUB(gtk_cairo_should_draw_window)
STUB(gtk_cairo_transform_to_window)
STUB(gtk_combo_box_text_append)
STUB(gtk_drag_set_icon_surface)
STUB(gtk_get_major_version)
--- a/widget/gtk/nsScreenGtk.cpp
+++ b/widget/gtk/nsScreenGtk.cpp
@@ -13,18 +13,17 @@
#include <gtk/gtk.h>
#include <dlfcn.h>
#include "gfxPlatformGtk.h"
static uint32_t sScreenId = 0;
nsScreenGtk :: nsScreenGtk ( )
- : mScreenNum(0),
- mRect(0, 0, 0, 0),
+ : mRect(0, 0, 0, 0),
mAvailRect(0, 0, 0, 0),
mId(++sScreenId)
{
}
nsScreenGtk :: ~nsScreenGtk()
{
@@ -60,27 +59,27 @@ nsScreenGtk :: GetAvailRect(int32_t *out
*outWidth = mAvailRect.width;
*outHeight = mAvailRect.height;
return NS_OK;
} // GetAvailRect
gint
-nsScreenGtk :: GetGtkMonitorScaleFactor()
+nsScreenGtk :: GetGtkMonitorScaleFactor(gint aNum)
{
#if (MOZ_WIDGET_GTK >= 3)
// Since GDK 3.10
static auto sGdkScreenGetMonitorScaleFactorPtr = (gint (*)(GdkScreen*, gint))
dlsym(RTLD_DEFAULT, "gdk_screen_get_monitor_scale_factor");
if (sGdkScreenGetMonitorScaleFactorPtr) {
// FIXME: In the future, we'll want to fix this for GTK on Wayland which
// supports a variable scale factor per display.
GdkScreen *screen = gdk_screen_get_default();
- return sGdkScreenGetMonitorScaleFactorPtr(screen, 0);
+ return sGdkScreenGetMonitorScaleFactorPtr(screen, aNum);
}
#endif
return 1;
}
double
nsScreenGtk :: GetDPIScale()
{
@@ -186,20 +185,33 @@ nsScreenGtk :: Init (GdkWindow *aRootWin
mAvailRect.IntersectRect(mAvailRect, workarea);
}
}
g_free (workareas);
#endif
}
-#ifdef MOZ_X11
void
-nsScreenGtk :: Init (XineramaScreenInfo *aScreenInfo)
+nsScreenGtk :: Init (GdkScreen *aScreen, gint aIndex, gint aTotal)
{
- nsIntRect xineRect(aScreenInfo->x_org, aScreenInfo->y_org,
- aScreenInfo->width, aScreenInfo->height);
+#if (MOZ_WIDGET_GTK == 2)
+ // GTK 3.4 early doesn't have gdk_screen_get_monitor_workarea
+ if (aTotal == 1) {
+ Init(gdk_screen_get_root_window(aScreen));
+ return;
+ }
+#endif
- mScreenNum = aScreenInfo->screen_number;
+ GdkRectangle rect;
+ gint scale = nsScreenGtk::GetGtkMonitorScaleFactor(aIndex);
+ gdk_screen_get_monitor_geometry(aScreen, aIndex, &rect);
+ mRect = nsIntRect(rect.x * scale, rect.y * scale,
+ rect.width * scale, rect.height * scale);
- mAvailRect = mRect = xineRect;
+#if (MOZ_WIDGET_GTK == 3)
+ gdk_screen_get_monitor_workarea(aScreen, aIndex, &rect);
+ mAvailRect = nsIntRect(rect.x * scale, rect.y * scale,
+ rect.width * scale, rect.height * scale);
+#else
+ mAvailRect = mRect;
+#endif
}
-#endif
--- a/widget/gtk/nsScreenGtk.h
+++ b/widget/gtk/nsScreenGtk.h
@@ -4,28 +4,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsScreenGtk_h___
#define nsScreenGtk_h___
#include "nsBaseScreen.h"
#include "nsRect.h"
#include "gdk/gdk.h"
-#ifdef MOZ_X11
-#include <X11/Xlib.h>
-
-// from Xinerama.h
-typedef struct {
- int screen_number;
- short x_org;
- short y_org;
- short width;
- short height;
-} XineramaScreenInfo;
-#endif /* MOZ_X11 */
//------------------------------------------------------------------------
class nsScreenGtk : public nsBaseScreen
{
public:
nsScreenGtk();
~nsScreenGtk();
@@ -34,24 +22,22 @@ public:
NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop,
int32_t* aWidth, int32_t* aHeight) override;
NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop,
int32_t* aWidth, int32_t* aHeight) override;
NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) override;
NS_IMETHOD GetColorDepth(int32_t* aColorDepth) override;
NS_IMETHOD GetDefaultCSSScaleFactor(double* aScaleFactor) override;
- void Init(GdkWindow *aRootWindow);
-#ifdef MOZ_X11
- void Init(XineramaScreenInfo *aScreenInfo);
-#endif /* MOZ_X11 */
+ void Init(GdkScreen *aScreen, gint aIndex, gint aTotal);
- static gint GetGtkMonitorScaleFactor();
+ static gint GetGtkMonitorScaleFactor(gint aNum = 0);
static double GetDPIScale();
private:
- uint32_t mScreenNum;
+ void Init(GdkWindow *aRootWindow);
+
nsIntRect mRect;
nsIntRect mAvailRect;
uint32_t mId;
};
#endif // nsScreenGtk_h___
--- a/widget/gtk/nsScreenManagerGtk.cpp
+++ b/widget/gtk/nsScreenManagerGtk.cpp
@@ -5,23 +5,18 @@
#include "nsScreenManagerGtk.h"
#include "nsScreenGtk.h"
#include "nsIComponentManager.h"
#include "nsRect.h"
#include "nsAutoPtr.h"
#include "nsGtkUtils.h"
-#define SCREEN_MANAGER_LIBRARY_LOAD_FAILED ((PRLibrary*)1)
-
#ifdef MOZ_X11
#include <gdk/gdkx.h>
-// prototypes from Xinerama.h
-typedef Bool (*_XnrmIsActive_fn)(Display *dpy);
-typedef XineramaScreenInfo* (*_XnrmQueryScreens_fn)(Display *dpy, int *number);
#endif
#include <gtk/gtk.h>
void
monitors_changed(GdkScreen* aScreen, gpointer aClosure)
{
nsScreenManagerGtk *manager = static_cast<nsScreenManagerGtk*>(aClosure);
@@ -50,19 +45,20 @@ root_window_event_filter(GdkXEvent *aGdk
break;
}
#endif
return GDK_FILTER_CONTINUE;
}
nsScreenManagerGtk :: nsScreenManagerGtk ( )
- : mXineramalib(nullptr)
- , mRootWindow(nullptr)
+ : mRootWindow(nullptr)
+#ifdef MOZ_X11
, mNetWorkareaAtom(0)
+#endif
{
// nothing else to do. I guess we could cache a bunch of information
// here, but we want to ask the device at runtime in case anything
// has changed.
}
nsScreenManagerGtk :: ~nsScreenManagerGtk()
@@ -121,93 +117,36 @@ nsScreenManagerGtk :: EnsureInit()
#endif
return Init();
}
nsresult
nsScreenManagerGtk :: Init()
{
-#ifdef MOZ_X11
- XineramaScreenInfo *screenInfo = nullptr;
- int numScreens;
+ GdkScreen* gdkScreen = gdk_screen_get_default();
- bool useXinerama = GDK_IS_X11_DISPLAY(gdk_display_get_default());
-
- if (useXinerama && !mXineramalib) {
- mXineramalib = PR_LoadLibrary("libXinerama.so.1");
- if (!mXineramalib) {
- mXineramalib = SCREEN_MANAGER_LIBRARY_LOAD_FAILED;
+ gint numScreens = gdk_screen_get_n_monitors(gdkScreen);
+ for (gint i = 0; i < numScreens; i++) {
+ RefPtr<nsScreenGtk> screen;
+ if (mCachedScreenArray.Count() > i) {
+ screen = static_cast<nsScreenGtk*>(mCachedScreenArray[i]);
+ } else {
+ screen = new nsScreenGtk();
+ mCachedScreenArray.AppendObject(screen);
}
- }
- if (mXineramalib && mXineramalib != SCREEN_MANAGER_LIBRARY_LOAD_FAILED) {
- _XnrmIsActive_fn _XnrmIsActive = (_XnrmIsActive_fn)
- PR_FindFunctionSymbol(mXineramalib, "XineramaIsActive");
-
- _XnrmQueryScreens_fn _XnrmQueryScreens = (_XnrmQueryScreens_fn)
- PR_FindFunctionSymbol(mXineramalib, "XineramaQueryScreens");
-
- // get the number of screens via xinerama
- Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
- if (_XnrmIsActive && _XnrmQueryScreens && _XnrmIsActive(display)) {
- screenInfo = _XnrmQueryScreens(display, &numScreens);
- }
+ // initialize this screen object
+ screen->Init(gdkScreen, i, numScreens);
}
- // screenInfo == nullptr if either Xinerama couldn't be loaded or
- // isn't running on the current display
- if (!screenInfo || numScreens == 1) {
- numScreens = 1;
-#endif
- RefPtr<nsScreenGtk> screen;
-
- if (mCachedScreenArray.Count() > 0) {
- screen = static_cast<nsScreenGtk*>(mCachedScreenArray[0]);
- } else {
- screen = new nsScreenGtk();
- if (!screen || !mCachedScreenArray.AppendObject(screen)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- }
-
- screen->Init(mRootWindow);
-#ifdef MOZ_X11
- }
- // If Xinerama is enabled and there's more than one screen, fill
- // in the info for all of the screens. If that's not the case
- // then nsScreenGTK() defaults to the screen width + height
- else {
-#ifdef DEBUG
- printf("Xinerama superpowers activated for %d screens!\n", numScreens);
-#endif
- for (int i = 0; i < numScreens; ++i) {
- RefPtr<nsScreenGtk> screen;
- if (mCachedScreenArray.Count() > i) {
- screen = static_cast<nsScreenGtk*>(mCachedScreenArray[i]);
- } else {
- screen = new nsScreenGtk();
- if (!screen || !mCachedScreenArray.AppendObject(screen)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- }
-
- // initialize this screen object
- screen->Init(&screenInfo[i]);
- }
- }
// Remove any screens that are no longer present.
while (mCachedScreenArray.Count() > numScreens) {
mCachedScreenArray.RemoveObjectAt(mCachedScreenArray.Count() - 1);
}
- if (screenInfo) {
- XFree(screenInfo);
- }
-#endif
-
return NS_OK;
}
NS_IMETHODIMP
nsScreenManagerGtk :: ScreenForId ( uint32_t aId, nsIScreen **outScreen )
{
*outScreen = nullptr;
@@ -292,20 +231,26 @@ NS_IMETHODIMP
nsScreenManagerGtk :: GetPrimaryScreen(nsIScreen * *aPrimaryScreen)
{
nsresult rv;
rv = EnsureInit();
if (NS_FAILED(rv)) {
NS_ERROR("nsScreenManagerGtk::EnsureInit() failed from GetPrimaryScreen");
return rv;
}
+#if (MOZ_WIDGET_GTK == 3)
+ // gdk_screen_get_primary_monitor is GTK 2.20+
+ GdkScreen* screen = gdk_screen_get_default();
+ gint index = gdk_screen_get_primary_monitor(screen);
+ *aPrimaryScreen = mCachedScreenArray.SafeObjectAt(index);
+#else
*aPrimaryScreen = mCachedScreenArray.SafeObjectAt(0);
+#endif
NS_IF_ADDREF(*aPrimaryScreen);
return NS_OK;
-
} // GetPrimaryScreen
//
// GetNumberOfScreens
//
// Returns how many physical screens are available.
//
--- a/widget/gtk/nsScreenManagerGtk.h
+++ b/widget/gtk/nsScreenManagerGtk.h
@@ -36,17 +36,15 @@ public:
private:
virtual ~nsScreenManagerGtk();
nsresult EnsureInit();
// Cached screen array. Its length is the number of screens we have.
nsCOMArray<nsIScreen> mCachedScreenArray;
- PRLibrary *mXineramalib;
-
GdkWindow *mRootWindow;
#ifdef MOZ_X11
Atom mNetWorkareaAtom;
#endif
};
#endif // nsScreenManagerGtk_h___