2008-01-15  Federico Mena Quintero  <federico@novell.com>

	Start fixing https://bugzilla.novell.com/show_bug.cgi?id=343858 -
	X servers with Intel 915GM graphics report a connected VGA output
	incorrectly, so applications don't use the whole screen.

	* gdk/x11/gdkscreen-x11.c (check_xfree_xinerama): Sanitize the
	monitors that we get from XineramaQueryScreens().
	(sanitize_monitors): Workaround for an Intel 915GM driver bug,
	where it will return that a VGA output is connected to a laptop,
	even though it isn't.  In the case of just two overlapping
	monitors ("laptop plus cloned external display"), simulate that we
	have only *one* monitor.

diff --git a/gdk/x11/gdkscreen-x11.c b/gdk/x11/gdkscreen-x11.c
index 624870f..7626ca8 100644
--- a/gdk/x11/gdkscreen-x11.c
+++ b/gdk/x11/gdkscreen-x11.c
@@ -596,6 +596,73 @@ check_solaris_xinerama (GdkScreen *screen)
   return FALSE;
 }
 
+static GdkRectangle
+pick_the_biggest_geometry (GdkRectangle *geometries, int num_geometries)
+{
+  long max_pixels;
+  int largest_index;
+  int i;
+
+  max_pixels = 0;
+  largest_index = 0;
+
+  for (i = 0; i < num_geometries; i++)
+    {
+      long pixels;
+
+      pixels = (long) geometries[i].width * geometries[i].height;
+
+      if (pixels > max_pixels)
+	{
+	  max_pixels = pixels;
+	  largest_index = i;
+	}
+    }
+
+  return geometries[largest_index];
+}
+
+static void
+sanitize_monitors (GdkRectangle *monitors, int n_monitors,
+		   GdkRectangle **monitors_ret, int *n_monitors_ret)
+{
+  if (n_monitors == 2
+      && gdk_rectangle_intersect (monitors + 0, monitors + 1, NULL))
+    {
+      /* https://bugzilla.novell.com/show_bug.cgi?id=310208
+       *
+       * The X driver for Intel 915GM chipsets has/had a bug where it would
+       * report that laptops started with a VGA output connected, and most
+       * of the time it defaults to a resolution of 1024x768.  This doesn't
+       * match the resolution of the laptop, which these days is big and fancy.
+       *
+       * Both monitors (the VGA output's and the laptop's) *overlap* in the Xinerama
+       * configuration, since that is how "clone the display" is implemented.
+       * So, we see if there are only two monitors *and* if they intersect --- in
+       * that case, we can be reasonably confident that we can just pick the bigger
+       * monitor, which will be the laptop's display.
+       *
+       * This shouldn't break real setups with "make a big screen out of two monitors",
+       * since those monitors don't overlap in the Xinerama configuration.
+       *
+       * To summarize: in the case of just two overlapping monitors ("laptop
+       * plus cloned external display"), we simulate that we have only *one* monitor.
+       */
+
+      *n_monitors_ret = 1;
+      *monitors_ret = g_new (GdkRectangle, 1);
+
+      **monitors_ret = pick_the_biggest_geometry (monitors, n_monitors);
+
+      g_free (monitors);
+    }
+  else
+    {
+      *monitors_ret = monitors;
+      *n_monitors_ret = n_monitors;
+    }
+}
+
 static gboolean
 check_xfree_xinerama (GdkScreen *screen)
 {
@@ -603,9 +670,10 @@ check_xfree_xinerama (GdkScreen *screen)
   if (XineramaIsActive (GDK_SCREEN_XDISPLAY (screen)))
     {
       GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+      int num_monitors;
       XineramaScreenInfo *monitors = XineramaQueryScreens (GDK_SCREEN_XDISPLAY (screen),
-							   &screen_x11->num_monitors);
-      if (screen_x11->num_monitors <= 0 || monitors == NULL)
+							   &num_monitors);
+      if (num_monitors <= 0 || monitors == NULL)
 	{
 	  /* If Xinerama doesn't think we have any monitors, try acting as
 	   * though we had no Xinerama. If the "no monitors" condition
@@ -614,23 +682,34 @@ check_xfree_xinerama (GdkScreen *screen)
 	   * and can go back into Xinerama-ish mode at that point. */
 	  if (monitors)
 	    XFree (monitors);
+
+	  screen_x11->num_monitors = 0;
 	  return FALSE;
 	}
       else
 	{
+	  GdkRectangle *rects;
 	  int i;
-	  screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
+	  GdkRectangle *sane_rects;
+	  int sane_num_monitors;
+
+	  rects = g_new0 (GdkRectangle, num_monitors);
 	  
-	  for (i = 0; i < screen_x11->num_monitors; i++)
+	  for (i = 0; i < num_monitors; i++)
 	    {
-	      screen_x11->monitors[i].x = monitors[i].x_org;
-	      screen_x11->monitors[i].y = monitors[i].y_org;
-	      screen_x11->monitors[i].width = monitors[i].width;
-	      screen_x11->monitors[i].height = monitors[i].height;
+	      rects[i].x = monitors[i].x_org;
+	      rects[i].y = monitors[i].y_org;
+	      rects[i].width = monitors[i].width;
+	      rects[i].height = monitors[i].height;
 	    }
 
 	  XFree (monitors);
 
+	  sanitize_monitors (rects, num_monitors, &sane_rects, &sane_num_monitors);
+
+	  screen_x11->num_monitors = sane_num_monitors;
+	  screen_x11->monitors = sane_rects;
+
 	  return TRUE;
 	}
     }
