Bug 1252408 - nsScreenMangerGtk should use GTK API instead of Xinerama. r?karlt draft
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Sun, 06 Mar 2016 20:39:00 +0900
changeset 340447 84d6579d517215f796d195684a7739aebf814aac
parent 340279 d6ee82b9a74155b6bfd544166f036fc572ae8c56
child 516186 189501f192025e175ceeaef1e7eb0135af47385e
push id12963
push userm_kato@ga2.so-net.ne.jp
push dateTue, 15 Mar 2016 08:41:03 +0000
reviewerskarlt
bugs1252408
milestone48.0a1
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
widget/gtk/mozgtk/mozgtk.c
widget/gtk/nsScreenGtk.cpp
widget/gtk/nsScreenGtk.h
widget/gtk/nsScreenManagerGtk.cpp
widget/gtk/nsScreenManagerGtk.h
--- 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___