File gnome-panel-bnc479684-pick-primary-output.diff of Package gnome-panel
diff --git a/configure.in b/configure.in
index 4824f84..75ec51e 100644
--- a/configure.in
+++ b/configure.in
@@ -266,6 +266,12 @@ PKG_CHECK_MODULES(X, x11 xau, :, [
AC_SUBST(X_LIBS)
+dnl X RANDR extension
+
+if $PKG_CONFIG --exists "xrandr >= 1.2.0" ; then
+ AC_DEFINE(HAVE_RANDR, 1, [Have the Xrandr extension library])
+fi
+
dnl IDL directories
ORBIT_IDL="`$PKG_CONFIG --variable=orbit_idl ORBit-2.0`"
diff --git a/gnome-panel/panel-multiscreen.c b/gnome-panel/panel-multiscreen.c
index 06df009..0a542ce 100644
--- a/gnome-panel/panel-multiscreen.c
+++ b/gnome-panel/panel-multiscreen.c
@@ -25,6 +25,9 @@
#include <config.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.h>
+#include <gdk/gdkx.h>
#include "panel-multiscreen.h"
#include <string.h>
@@ -40,6 +43,134 @@ static int screens = 0;
static int *monitors = NULL;
static GdkRectangle **geometries = NULL;
static gboolean initialized = FALSE;
+static gboolean have_randr;
+
+static gboolean
+get_xrandr_monitor_geometries (GdkScreen *screen, int *monitors_ret, GdkRectangle **geometries_ret)
+{
+ if (!have_randr)
+ return FALSE;
+
+#ifdef HAVE_RANDR
+ /* GTK+ 2.14.x uses the Xinerama API, instead of RANDR, to get the
+ * monitor geometries. It does this to avoid calling
+ * XRRGetScreenResources(), which is slow as it re-detects all the
+ * monitors --- note that XRRGetScreenResourcesCurrent() had not been
+ * introduced yet. Using Xinerama in GTK+ has the bad side effect that
+ * gdk_screen_get_monitor_plug_name() will return NULL, as Xinerama does
+ * not provide that information, unlike RANDR.
+ *
+ * Here we need to identify the output names, so that we can put the
+ * built-in LCD in a laptop *before* all other outputs. This is so that
+ * gnome-panel will normally prefer to appear on the "native" display
+ * rather than on an external monitor.
+ *
+ * To get the output names and geometries, we will not use
+ * gdk_screen_get_n_monitors() and friends, but rather we will call
+ * XRR*() directly.
+ *
+ * See https://bugzilla.novell.com/show_bug.cgi?id=479684 for this
+ * particular bug, and and
+ * http://bugzilla.gnome.org/show_bug.cgi?id=562944 for a more long-term
+ * solution.
+ */
+
+ Display *xdisplay;
+ XRRScreenResources *resources;
+ GArray *geometries;
+ int i;
+ gboolean driver_is_pre_randr_1_2;
+
+ xdisplay = GDK_SCREEN_XDISPLAY (screen);
+
+ resources = XRRGetScreenResources (xdisplay, GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)));
+ if (!resources)
+ return FALSE;
+
+ geometries = g_array_sized_new (FALSE, FALSE, sizeof (GdkRectangle), resources->noutput);
+
+ driver_is_pre_randr_1_2 = FALSE;
+
+ for (i = 0; i < resources->noutput; i++) {
+ XRROutputInfo *output;
+
+ output = XRRGetOutputInfo (xdisplay, resources, resources->outputs[i]);
+
+ if (g_strcmp0 (output->name, "default") == 0)
+ driver_is_pre_randr_1_2 = TRUE; /* Drivers before RANDR 1.2 return "default" for the output name */
+
+ if (output->connection != RR_Disconnected && output->crtc != 0) {
+ XRRCrtcInfo *crtc;
+ GdkRectangle rect;
+
+ crtc = XRRGetCrtcInfo (xdisplay, resources, output->crtc);
+
+ rect.x = crtc->x;
+ rect.y = crtc->y;
+ rect.width = crtc->width;
+ rect.height = crtc->height;
+
+ XRRFreeCrtcInfo (crtc);
+
+ /* "LVDS" is the oh-so-intuitive name that X gives to laptop LCDs.
+ *
+ * Note that on RANDR 1.3, the right way to check for
+ * this is to get the ConnectorType property for the
+ * output, and see if it is "Panel". Yes, they changed
+ * the known output names for 1.3. Amateurs.
+ */
+
+ if (g_str_has_prefix (output->name, "LVDS")) /* can be "LVDS0", "LVDS-0", etc. */
+ g_array_prepend_vals (geometries, &rect, 1);
+ else
+ g_array_append_vals (geometries, &rect, 1);
+ }
+
+ XRRFreeOutputInfo (output);
+ }
+
+ XRRFreeScreenResources (resources);
+
+ if (driver_is_pre_randr_1_2) {
+ /* Drivers before RANDR 1.2 don't provide useful info about outputs */
+ g_array_free (geometries, TRUE);
+ return FALSE;
+ }
+
+ *monitors_ret = geometries->len;
+ *geometries_ret = (GdkRectangle *) g_array_free (geometries, FALSE);
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+static void
+get_gdk_monitor_geometries (GdkScreen *screen, int *monitors_ret, GdkRectangle **geometries_ret)
+{
+ int num_monitors;
+ GdkRectangle *geometries;
+ int i;
+
+ num_monitors = gdk_screen_get_n_monitors (screen);
+ geometries = g_new (GdkRectangle, num_monitors);
+
+ for (i = 0; i < num_monitors; i++)
+ gdk_screen_get_monitor_geometry (screen, i, &(geometries[i]));
+
+ *monitors_ret = num_monitors;
+ *geometries_ret = geometries;
+}
+
+static void
+get_raw_monitor_geometries (GdkScreen *screen, int *monitors_ret, GdkRectangle **geometries_ret)
+{
+ if (get_xrandr_monitor_geometries (screen, monitors_ret, geometries_ret))
+ return;
+
+ get_gdk_monitor_geometries (screen, monitors_ret, geometries_ret);
+}
static gboolean
overlaps (GdkRectangle *a, GdkRectangle *b)
@@ -54,17 +185,14 @@ pixels_in_rectangle (GdkRectangle *r)
}
static void
-get_monitors_for_screen (GdkScreen *screen, int *monitors_ret, GdkRectangle **geometries_ret)
+compress_overlapping_monitors (int *num_monitors_inout, GdkRectangle **geometries_inout)
{
int num_monitors;
GdkRectangle *geometries;
int i;
- num_monitors = gdk_screen_get_n_monitors (screen);
- geometries = g_new (GdkRectangle, num_monitors);
-
- for (i = 0; i < num_monitors; i++)
- gdk_screen_get_monitor_geometry (screen, i, &(geometries[i]));
+ num_monitors = *num_monitors_inout;
+ geometries = *geometries_inout;
/* http://bugzilla.gnome.org/show_bug.cgi?id=530969
* https://bugzilla.novell.com/show_bug.cgi?id=310208
@@ -142,10 +270,50 @@ get_monitors_for_screen (GdkScreen *screen, int *monitors_ret, GdkRectangle **ge
}
}
+ *num_monitors_inout = num_monitors;
+ *geometries_inout = geometries;
+}
+
+static void
+get_monitors_for_screen (GdkScreen *screen, int *monitors_ret, GdkRectangle **geometries_ret)
+{
+ int num_monitors;
+ GdkRectangle *geometries;
+
+ get_raw_monitor_geometries (screen, &num_monitors, &geometries);
+ compress_overlapping_monitors (&num_monitors, &geometries);
+
*monitors_ret = num_monitors;
*geometries_ret = geometries;
}
+static void
+init_randr (GdkDisplay *display)
+{
+#ifdef HAVE_RANDR
+ Display *xdisplay;
+ int event_base, error_base;
+#endif
+
+ have_randr = FALSE;
+
+#ifdef HAVE_RANDR
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+ /* We don't remember the event/error bases, as we expect to get "screen
+ * changed" events from GdkScreen instead.
+ */
+
+ if (XRRQueryExtension (xdisplay, &event_base, &error_base)) {
+ int major, minor;
+
+ XRRQueryVersion (xdisplay, &major, &minor);
+ if ((major == 1 && minor >= 2) || major > 1)
+ have_randr = TRUE;
+ }
+#endif
+}
+
void
panel_multiscreen_init (void)
{
@@ -158,6 +326,8 @@ panel_multiscreen_init (void)
display = gdk_display_get_default ();
screens = gdk_display_get_n_screens (display);
+ init_randr (display);
+
monitors = g_new0 (int, screens);
geometries = g_new0 (GdkRectangle *, screens);