Blob Blame History Raw
From 83dd316f42bcc959a533e6be2ba24bbc37417a0a Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Wed, 25 Apr 2012 15:08:53 +0200
Subject: [PATCH] rhbz#809019 count mirrored monitors as one

Change-Id: I I I184541e99ab4e04b8534dd0341bc2f3630094e9c
---
 vcl/inc/unx/gtk/gtkdata.hxx     |    2 +
 vcl/inc/unx/gtk/gtksys.hxx      |   11 ++++-
 vcl/unx/gtk/app/gtkdata.cxx     |    2 +
 vcl/unx/gtk/app/gtksys.cxx      |   85 ++++++++++++++++++++++++++++++--------
 vcl/unx/gtk/window/gtkframe.cxx |    4 +-
 5 files changed, 81 insertions(+), 23 deletions(-)

diff --git a/vcl/inc/unx/gtk/gtkdata.hxx b/vcl/inc/unx/gtk/gtkdata.hxx
index 63b8ae3..033bf1a 100644
--- a/vcl/inc/unx/gtk/gtkdata.hxx
+++ b/vcl/inc/unx/gtk/gtkdata.hxx
@@ -151,6 +151,8 @@ public:
     GdkDisplay* GetGdkDisplay() const { return m_pGdkDisplay; }
     bool        IsX11Display() const { return m_bX11Display; }
 
+    GtkSalSystem* getSystem() const { return m_pSys; }
+
     virtual void deregisterFrame( SalFrame* pFrame );
     GdkCursor *getCursor( PointerStyle ePointerStyle );
     virtual int CaptureMouse( SalFrame* pFrame );
diff --git a/vcl/inc/unx/gtk/gtksys.hxx b/vcl/inc/unx/gtk/gtksys.hxx
index df9e79e..582d4b9 100644
--- a/vcl/inc/unx/gtk/gtksys.hxx
+++ b/vcl/inc/unx/gtk/gtksys.hxx
@@ -33,10 +33,15 @@
 #include "generic/gensys.h"
 #include <gtk/gtk.h>
 #include <unx/saltype.h>
+#include <deque>
 
 class GtkSalSystem : public SalGenericSystem
 {
+    typedef std::deque<std::pair<GdkScreen*, int> > ScreenMonitors_t;
+
     GdkDisplay *mpDisplay;
+    // Number of monitors for every active screen.
+    ScreenMonitors_t maScreenMonitors;
 public:
              GtkSalSystem();
     virtual ~GtkSalSystem();
@@ -56,10 +61,11 @@
             { return getXScreenFromDisplayScreen( GetDisplayDefaultScreen() ); }
     int               GetDisplayXScreenCount();
     SalX11Screen      getXScreenFromDisplayScreen(unsigned int nDisplayScreen);
+    void              countScreenMonitors();
     // We have a 'screen' number that is combined from screen-idx + monitor-idx
-    static int        getScreenIdxFromPtr     (GdkDisplay *pDisplay, GdkScreen *pScreen);
-    static int        getScreenMonitorIdx     (GdkDisplay *pDisplay, GdkScreen *pScreen, int nX, int nY);
-    static GdkScreen *getScreenMonitorFromIdx (GdkDisplay *pDisplay, int nIdx, gint &nMonitor);
+    int        getScreenIdxFromPtr     (GdkScreen *pScreen);
+    int        getScreenMonitorIdx     (GdkScreen *pScreen, int nX, int nY);
+    GdkScreen *getScreenMonitorFromIdx (int nIdx, gint &nMonitor);
 };
 
 #endif // _VCL_GTKSYS_HXX_
diff --git a/vcl/unx/gtk/app/gtkdata.cxx b/vcl/unx/gtk/app/gtkdata.cxx
index 5189174..4d58110 100644
--- a/vcl/unx/gtk/app/gtkdata.cxx
+++ b/vcl/unx/gtk/app/gtkdata.cxx
@@ -197,12 +197,14 @@ GdkFilterReturn GtkSalDisplay::filterGdkEvent( GdkXEvent* sys_event,
 
 void GtkSalDisplay::screenSizeChanged( GdkScreen* pScreen )
 {
+    m_pSys->countScreenMonitors();
     if (pScreen)
         emitDisplayChanged();
 }
 
 void GtkSalDisplay::monitorsChanged( GdkScreen* pScreen )
 {
+    m_pSys->countScreenMonitors();
     if (pScreen)
         emitDisplayChanged();
 }
diff --git a/vcl/unx/gtk/app/gtksys.cxx b/vcl/unx/gtk/app/gtksys.cxx
index 538107f..25578b3 100644
--- a/vcl/unx/gtk/app/gtksys.cxx
+++ b/vcl/unx/gtk/app/gtksys.cxx
@@ -49,6 +49,7 @@ SalSystem *GtkInstance::CreateSalSystem()
 GtkSalSystem::GtkSalSystem() : SalGenericSystem()
 {
     mpDisplay = gdk_display_get_default();
+    countScreenMonitors();
 }
 
 GtkSalSystem::~GtkSalSystem()
@@ -61,6 +62,52 @@ GtkSalSystem::GetDisplayXScreenCount()
     return gdk_display_get_n_screens (mpDisplay);
 }
 
+namespace
+{
+
+struct GdkRectangleEqual
+{
+    bool operator()(GdkRectangle const& rLeft, GdkRectangle const& rRight)
+    {
+        return
+            rLeft.x == rRight.x
+            && rLeft.y == rRight.y
+            && rLeft.width == rRight.width
+            && rLeft.height == rRight.height
+            ;
+    }
+};
+
+}
+
+void
+GtkSalSystem::countScreenMonitors()
+{
+    maScreenMonitors.clear();
+    for (gint i = 0; i < gdk_display_get_n_screens(mpDisplay); i++)
+    {
+        GdkScreen* const pScreen(gdk_display_get_screen(mpDisplay, i));
+        gint nMonitors(pScreen ? gdk_screen_get_n_monitors(pScreen) : 0);
+        if (nMonitors > 1)
+        {
+            std::vector<GdkRectangle> aGeometries;
+            aGeometries.reserve(nMonitors);
+            for (gint j(0); j != nMonitors; ++j)
+            {
+                GdkRectangle aGeometry;
+                gdk_screen_get_monitor_geometry(pScreen, j, &aGeometry);
+                aGeometries.push_back(aGeometry);
+            }
+            GdkRectangleEqual aCmp;
+            std::sort(aGeometries.begin(), aGeometries.end(), aCmp);
+            const std::vector<GdkRectangle>::iterator aUniqueEnd(
+                    std::unique(aGeometries.begin(), aGeometries.end(), aCmp));
+            nMonitors = std::distance(aGeometries.begin(), aUniqueEnd);
+        }
+        maScreenMonitors.push_back(std::make_pair(pScreen, nMonitors));
+    }
+}
+
 // Including gdkx.h kills us with the Window / XWindow conflict
 extern "C" {
     GType gdk_x11_display_get_type (void);
@@ -73,7 +120,7 @@ GtkSalSystem::getXScreenFromDisplayScreen(unsigned int nScreen)
     gint nMonitor;
     GdkScreen *pScreen = NULL;
 
-    pScreen = getScreenMonitorFromIdx (mpDisplay, nScreen, nMonitor);
+    pScreen = getScreenMonitorFromIdx (nScreen, nMonitor);
     if (!pScreen)
         return SalX11Screen (0);
 #if GTK_CHECK_VERSION(3,0,0)
@@ -84,16 +131,16 @@ GtkSalSystem::getXScreenFromDisplayScreen(unsigned int nScreen)
 }
 
 GdkScreen *
-GtkSalSystem::getScreenMonitorFromIdx (GdkDisplay *pDisplay, int nIdx, gint &nMonitor)
+GtkSalSystem::getScreenMonitorFromIdx (int nIdx, gint &nMonitor)
 {
     GdkScreen *pScreen = NULL;
-    for (gint i = 0; i < gdk_display_get_n_screens (pDisplay); i++)
+    for (ScreenMonitors_t::const_iterator aIt(maScreenMonitors.begin()), aEnd(maScreenMonitors.end()); aIt != aEnd; ++aIt)
     {
-        pScreen = gdk_display_get_screen (pDisplay, i);
+        pScreen = aIt->first;
         if (!pScreen)
             break;
-        if (nIdx >= gdk_screen_get_n_monitors (pScreen))
-            nIdx -= gdk_screen_get_n_monitors (pScreen);
+        if (nIdx >= aIt->second)
+            nIdx -= aIt->second;
         else
             break;
     }
@@ -102,32 +149,34 @@ GtkSalSystem::getScreenMonitorFromIdx (GdkDisplay *pDisplay, int nIdx, gint &nMo
 }
 
 int
-GtkSalSystem::getScreenIdxFromPtr (GdkDisplay *pDisplay, GdkScreen *pScreen)
+GtkSalSystem::getScreenIdxFromPtr (GdkScreen *pScreen)
 {
     int nIdx = 0;
-    for (gint i = 0; i < gdk_display_get_n_screens (pDisplay); i++)
+    for (ScreenMonitors_t::const_iterator aIt(maScreenMonitors.begin()), aEnd(maScreenMonitors.end()); aIt != aEnd; ++aIt)
     {
-        GdkScreen *pCmp = gdk_display_get_screen (pDisplay, i);
-        if (pCmp == pScreen)
+        if (aIt->first == pScreen)
             return nIdx;
-        nIdx += gdk_screen_get_n_monitors (pCmp);
+        nIdx += aIt->second;
     }
     g_warning ("failed to find screen %p", pScreen);
     return 0;
 }
 
-int GtkSalSystem::getScreenMonitorIdx (GdkDisplay *pDisplay,
-                                       GdkScreen *pScreen,
+int GtkSalSystem::getScreenMonitorIdx (GdkScreen *pScreen,
                                        int nX, int nY)
 {
-    return getScreenIdxFromPtr (pDisplay, pScreen) +
+    // TODO: this will fail horribly for exotic combinations like two
+    // monitors in mirror mode and one extra. Hopefully such
+    // abominations are not used (or, even better, not possible) in
+    // practice .-)
+    return getScreenIdxFromPtr (pScreen) +
         gdk_screen_get_monitor_at_point (pScreen, nX, nY);
 }
 
 unsigned int GtkSalSystem::GetDisplayScreenCount()
 {
     gint nMonitor;
-    (void)getScreenMonitorFromIdx (mpDisplay, G_MAXINT, nMonitor);
+    (void)getScreenMonitorFromIdx (G_MAXINT, nMonitor);
     return G_MAXINT - nMonitor;
 }
 
@@ -183,7 +232,7 @@ static int _get_primary_monitor (GdkScreen *pScreen)
 unsigned int GtkSalSystem::GetDisplayDefaultScreen()
 {
     GdkScreen *pDefault = gdk_display_get_default_screen (mpDisplay);
-    int idx = getScreenIdxFromPtr (mpDisplay, pDefault);
+    int idx = getScreenIdxFromPtr (pDefault);
     return idx + _get_primary_monitor (pDefault);
 }
 
@@ -192,7 +241,7 @@ Rectangle GtkSalSystem::GetDisplayScreenPosSizePixel (unsigned int nScreen)
     gint nMonitor;
     GdkScreen *pScreen;
     GdkRectangle aRect;
-    pScreen = getScreenMonitorFromIdx (mpDisplay, nScreen, nMonitor);
+    pScreen = getScreenMonitorFromIdx (nScreen, nMonitor);
     if (!pScreen)
         return Rectangle();
     gdk_screen_get_monitor_geometry (pScreen, nMonitor, &aRect);
@@ -212,7 +261,7 @@ rtl::OUString GtkSalSystem::GetDisplayScreenName(unsigned int nScreen)
     gchar *pStr;
     gint nMonitor;
     GdkScreen *pScreen;
-    pScreen = getScreenMonitorFromIdx (mpDisplay, nScreen, nMonitor);
+    pScreen = getScreenMonitorFromIdx (nScreen, nMonitor);
     if (!pScreen)
         return rtl::OUString();
 
diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx
index 28776f1..eb77e75 100644
--- a/vcl/unx/gtk/window/gtkframe.cxx
+++ b/vcl/unx/gtk/window/gtkframe.cxx
@@ -593,7 +593,7 @@ void GtkSalFrame::updateScreenNumber()
     int nScreen = 0;
     GdkScreen *pScreen = gtk_widget_get_screen( m_pWindow );
     if( pScreen )
-        nScreen = GtkSalSystem::getScreenMonitorIdx( getGdkDisplay(), pScreen, maGeometry.nX, maGeometry.nY );
+        nScreen = getDisplay()->getSystem()->getScreenMonitorIdx( pScreen, maGeometry.nX, maGeometry.nY );
     maGeometry.nDisplayScreenNumber = nScreen;
 }
 
@@ -1862,7 +1862,7 @@ void GtkSalFrame::SetScreen( unsigned int nNewScreen, int eType, Rectangle *pSiz
 
     gint nMonitor;
     GdkScreen *pScreen = NULL;
-    pScreen = GtkSalSystem::getScreenMonitorFromIdx( getGdkDisplay(), nNewScreen, nMonitor );
+    pScreen = getDisplay()->getSystem()->getScreenMonitorFromIdx( nNewScreen, nMonitor );
 
     // Heavy lifting, need to move screen ...
     if( pScreen != gtk_widget_get_screen( m_pWindow ))
-- 
1.7.7.6