2008-01-15 Federico Mena Quintero 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; } }