summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--configure.in15
-rw-r--r--gdk/gdk.symbols4
-rw-r--r--gdk/gdkscreen.c23
-rw-r--r--gdk/gdkscreen.h7
-rw-r--r--gdk/x11/gdkdisplay-x11.c19
-rw-r--r--gdk/x11/gdkdisplay-x11.h3
-rw-r--r--gdk/x11/gdkevents-x11.c14
-rw-r--r--gdk/x11/gdkscreen-x11.c601
-rw-r--r--gdk/x11/gdkscreen-x11.h9
-rw-r--r--gdk/x11/gdkx.h3
11 files changed, 500 insertions, 205 deletions
diff --git a/ChangeLog b/ChangeLog
index 5fa4e99e41..4cc50d6cfc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Thu Dec 13 13:14:50 2007 Søren Sandmann <sandmann@redhat.com>
+
+ * Add RandR 1.2 support
+
+ - New monitors_changed signal - New API to get width/height of
+ monitors, and the name of the plug
+
2007-12-13 Kristian Rietveld <kris@imendio.com>
* gtk/tests/liststore.c:
diff --git a/configure.in b/configure.in
index 0741e53c05..fbab5bb3c5 100644
--- a/configure.in
+++ b/configure.in
@@ -1325,19 +1325,10 @@ if test "x$gdktarget" = "xx11"; then
AM_CONDITIONAL(XINPUT_XFREE, test x$with_xinput = xxfree || test x$with_xinput = xyes)
# Check for the RANDR extension
+ if $PKG_CONFIG --exists "xrandr >= 1.2" ; then
+ AC_DEFINE(HAVE_RANDR, 1, Have the Xrandr extension library)
- have_randr=false
- if $PKG_CONFIG --exists xrandr ; then
- have_randr=true
- X_PACKAGES="$X_PACKAGES xrandr"
- else
- AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration,
- [AC_CHECK_HEADER(X11/extensions/Xrandr.h,
- # RANDR requires RENDER
- [have_randr=true
- GTK_ADD_LIB(x_extra_libs, Xrender)
- GTK_ADD_LIB(x_extra_libs, Xrandr)],
- :, [#include <X11/Xlib.h>])])
+ X_PACKAGES="$X_PACKAGES xrandr"
fi
if $have_randr ; then
diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols
index 40f05a2f5e..71f8c9e9cd 100644
--- a/gdk/gdk.symbols
+++ b/gdk/gdk.symbols
@@ -1056,6 +1056,9 @@ gdk_screen_get_default_colormap
gdk_screen_set_default_colormap
gdk_screen_get_n_monitors
gdk_screen_get_monitor_geometry
+gdk_screen_get_monitor_width_mm
+gdk_screen_get_monitor_height_mm
+gdk_screen_get_monitor_plug_name
gdk_screen_get_rgba_colormap
gdk_screen_get_rgba_visual
gdk_screen_get_active_window
@@ -1234,6 +1237,7 @@ gdk_x11_image_get_ximage
#if IN_FILE(__GDK_SCREEN_X11_C__)
gdk_x11_screen_get_screen_number
gdk_x11_screen_get_xscreen
+gdk_x11_screen_get_monitor_output
#endif
#if IN_FILE(__GDK_VISUAL_X11_C__)
diff --git a/gdk/gdkscreen.c b/gdk/gdkscreen.c
index 986f9f5525..72aa3f7313 100644
--- a/gdk/gdkscreen.c
+++ b/gdk/gdkscreen.c
@@ -51,6 +51,7 @@ enum
{
SIZE_CHANGED,
COMPOSITED_CHANGED,
+ MONITORS_CHANGED,
LAST_SIGNAL
};
@@ -124,6 +125,28 @@ gdk_screen_class_init (GdkScreenClass *klass)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
+
+ /**
+ * GdkScreen::monitors-changed:
+ * @screen: the object on which the signal is emitted
+ *
+ * The ::monitors_changed signal is emitted when the number, size
+ * or position of the monitors attached to the screen change.
+ *
+ * Only for X for now. Future implementations for Win32 and
+ * OS X may be a possibility.
+ *
+ * Since: 2.14
+ */
+ signals[MONITORS_CHANGED] =
+ g_signal_new (g_intern_static_string ("monitors_changed"),
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdkScreenClass, monitors_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
}
static void
diff --git a/gdk/gdkscreen.h b/gdk/gdkscreen.h
index 7ff920193f..c89990335d 100644
--- a/gdk/gdkscreen.h
+++ b/gdk/gdkscreen.h
@@ -58,6 +58,7 @@ struct _GdkScreenClass
void (*size_changed) (GdkScreen *screen);
void (*composited_changed) (GdkScreen *screen);
+ void (*monitors_changed) (GdkScreen *screen);
};
GType gdk_screen_get_type (void) G_GNUC_CONST;
@@ -93,6 +94,12 @@ gint gdk_screen_get_monitor_at_point (GdkScreen *screen,
gint y);
gint gdk_screen_get_monitor_at_window (GdkScreen *screen,
GdkWindow *window);
+gint gdk_screen_get_monitor_width_mm (GdkScreen *screen,
+ gint monitor_num);
+gint gdk_screen_get_monitor_height_mm (GdkScreen *screen,
+ gint monitor_num);
+gchar * gdk_screen_get_monitor_plug_name (GdkScreen *screen,
+ gint monitor_num);
void gdk_screen_broadcast_client_message (GdkScreen *screen,
GdkEvent *event);
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 89aedfa3f2..56eccc91f1 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -62,6 +62,10 @@
#include <X11/extensions/Xdamage.h>
#endif
+#ifdef HAVE_RANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
static void gdk_display_x11_dispose (GObject *object);
static void gdk_display_x11_finalize (GObject *object);
@@ -165,6 +169,21 @@ gdk_display_open (const gchar *display_name)
XAddConnectionWatch (xdisplay, gdk_internal_connection_watch, NULL);
#endif /* HAVE_X11R6 */
+ /* RandR must be initialized before we initialize the screens */
+ display_x11->have_randr12 = FALSE;
+#ifdef HAVE_RANDR
+ if (XRRQueryExtension (display_x11->xdisplay,
+ &display_x11->xrandr_event_base, &ignore))
+ {
+ int major, minor;
+
+ XRRQueryVersion (display_x11->xdisplay, &major, &minor);
+
+ if ((major == 1 && minor >= 2) || major > 1)
+ display_x11->have_randr12 = TRUE;
+ }
+#endif
+
/* initialize the display's screens */
display_x11->screens = g_new (GdkScreen *, ScreenCount (display_x11->xdisplay));
for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h
index 7b2654cd7c..ffd0461113 100644
--- a/gdk/x11/gdkdisplay-x11.h
+++ b/gdk/x11/gdkdisplay-x11.h
@@ -85,6 +85,9 @@ struct _GdkDisplayX11
gboolean have_xdamage;
gint xdamage_event_base;
+ gboolean have_randr12;
+ gint xrandr_event_base;
+
/* If the SECURITY extension is in place, whether this client holds
* a trusted authorization and so is allowed to make various requests
* (grabs, properties etc.) Otherwise always TRUE. */
diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c
index d55b572dd5..a537ffc75a 100644
--- a/gdk/x11/gdkevents-x11.c
+++ b/gdk/x11/gdkevents-x11.c
@@ -58,6 +58,10 @@
#include <X11/extensions/Xfixes.h>
#endif
+#ifdef HAVE_RANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
#include <X11/Xatom.h>
typedef struct _GdkIOClosure GdkIOClosure;
@@ -2102,6 +2106,16 @@ gdk_event_translate (GdkDisplay *display,
}
else
#endif
+#ifdef HAVE_RANDR
+ if (xevent->type - display_x11->xrandr_event_base == RRNotify)
+ {
+ XRRNotifyEvent *notify = (XRRNotifyEvent *)xevent;
+
+ if (screen)
+ _gdk_x11_screen_process_monitors_change (screen);
+ }
+ else
+#endif
#if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
if (display_x11->have_xdamage && window_private && window_private->composited &&
xevent->type == display_x11->xdamage_event_base + XDamageNotify &&
diff --git a/gdk/x11/gdkscreen-x11.c b/gdk/x11/gdkscreen-x11.c
index 624870f850..469f9b6c2a 100644
--- a/gdk/x11/gdkscreen-x11.c
+++ b/gdk/x11/gdkscreen-x11.c
@@ -53,8 +53,8 @@
static void gdk_screen_x11_dispose (GObject *object);
static void gdk_screen_x11_finalize (GObject *object);
-static void init_xinerama_support (GdkScreen *screen);
static void init_randr_support (GdkScreen *screen);
+static void deinit_multihead (GdkScreen *screen);
enum
{
@@ -66,6 +66,16 @@ static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (GdkScreenX11, _gdk_screen_x11, GDK_TYPE_SCREEN)
+struct _GdkX11Monitor
+{
+ GdkRectangle geometry;
+ XID output;
+ int width_mm;
+ int height_mm;
+ char * output_name;
+ char * manufacturer;
+};
+
static void
_gdk_screen_x11_class_init (GdkScreenX11Class *klass)
{
@@ -321,8 +331,8 @@ gdk_screen_x11_finalize (GObject *object)
g_hash_table_destroy (screen_x11->colormap_hash);
- g_free (screen_x11->monitors);
-
+ deinit_multihead (GDK_SCREEN (object));
+
G_OBJECT_CLASS (_gdk_screen_x11_parent_class)->finalize (object);
}
@@ -341,7 +351,100 @@ gdk_screen_get_n_monitors (GdkScreen *screen)
{
g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
- return GDK_SCREEN_X11 (screen)->num_monitors;
+ return GDK_SCREEN_X11 (screen)->n_monitors;
+}
+
+static GdkX11Monitor *
+get_monitor (GdkScreen *screen,
+ int monitor_num)
+{
+ GdkScreenX11 *screen_x11;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+
+ g_return_val_if_fail (monitor_num < screen_x11->n_monitors, NULL);
+ g_return_val_if_fail (monitor_num >= 0, NULL);
+
+ return &(screen_x11->monitors[monitor_num]);
+}
+
+/**
+ * gdk_screen_get_monitor_width_mm:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor
+ *
+ * Gets the width in millimeters of the specified monitor, if available.
+ *
+ * Returns the width of the monitor, or -1 if not available;
+ *
+ * Since: 2.14
+ */
+gint
+gdk_screen_get_monitor_width_mm (GdkScreen *screen,
+ gint monitor_num)
+{
+ return get_monitor (screen, monitor_num)->width_mm;
+}
+
+/**
+ * gdk_screen_get_monitor_height_mm:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor
+ *
+ * Gets the height in millimeters of the specified monitor.
+ *
+ * Returns: the height of the monitor
+ *
+ * Since: 2.14
+ */
+gint
+gdk_screen_get_monitor_height_mm (GdkScreen *screen,
+ gint monitor_num)
+{
+ return get_monitor (screen, monitor_num)->height_mm;
+}
+
+/**
+ * gdk_screen_get_monitor_plug_name:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor
+ *
+ * Returns the output name of the specified monitor.
+ * Usually something like VGA, DVI, or TV, not the actual
+ * product name of the display device.
+ *
+ * Returns: a newly-allocated string containing the name of the monitor,
+ * or %NULL if the name cannot be determined
+ *
+ * Since: 2.14
+ */
+gchar *
+gdk_screen_get_monitor_plug_name (GdkScreen *screen,
+ gint monitor_num)
+{
+ return g_strdup (get_monitor (screen, monitor_num)->output_name);
+}
+
+/**
+ * gdk_x11_screen_get_monitor_output:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor
+ *
+ * Gets the XID of the specified output/monitor.
+ * If the X server does not support version 1.2 of the RANDR
+ * extension, 0 is returned.
+ *
+ * Returns: the XID of the monitor
+ *
+ * Since: 2.14
+ */
+XID
+gdk_x11_screen_get_monitor_output (GdkScreen *screen,
+ gint monitor_num)
+{
+ return get_monitor (screen, monitor_num)->output;
}
/**
@@ -363,11 +466,12 @@ gdk_screen_get_monitor_geometry (GdkScreen *screen,
gint monitor_num,
GdkRectangle *dest)
{
- g_return_if_fail (GDK_IS_SCREEN (screen));
- g_return_if_fail (monitor_num < GDK_SCREEN_X11 (screen)->num_monitors);
- g_return_if_fail (monitor_num >= 0);
+ if (dest)
+ {
+ GdkX11Monitor *monitor = get_monitor (screen, monitor_num);
- *dest = GDK_SCREEN_X11 (screen)->monitors[monitor_num];
+ *dest = monitor->geometry;
+ }
}
/**
@@ -452,7 +556,6 @@ gdk_x11_screen_get_xscreen (GdkScreen *screen)
return GDK_SCREEN_X11 (screen)->xscreen;
}
-
/**
* gdk_x11_screen_get_screen_number:
* @screen: a #GdkScreen.
@@ -490,6 +593,287 @@ make_cm_atom (int screen_number)
return atom;
}
+static void
+init_monitor_geometry (GdkX11Monitor *monitor,
+ int x, int y, int width, int height)
+{
+ monitor->geometry.x = x;
+ monitor->geometry.y = y;
+ monitor->geometry.width = width;
+ monitor->geometry.height = height;
+
+ monitor->output = None;
+ monitor->width_mm = -1;
+ monitor->height_mm = -1;
+ monitor->output_name = NULL;
+ monitor->manufacturer = NULL;
+}
+
+static gboolean
+init_fake_xinerama (GdkScreen *screen)
+{
+#ifdef G_ENABLE_DEBUG
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ XSetWindowAttributes atts;
+ Window win;
+ gint w, h;
+
+ if (!(_gdk_debug_flags & GDK_DEBUG_XINERAMA))
+ return FALSE;
+
+ /* Fake Xinerama mode by splitting the screen into 4 monitors.
+ * Also draw a little cross to make the monitor boundaries visible.
+ */
+ w = WidthOfScreen (screen_x11->xscreen);
+ h = HeightOfScreen (screen_x11->xscreen);
+
+ screen_x11->n_monitors = 4;
+ screen_x11->monitors = g_new0 (GdkX11Monitor, 4);
+ init_monitor_geometry (&screen_x11->monitors[0], 0, 0, w / 2, h / 2);
+ init_monitor_geometry (&screen_x11->monitors[1], w / 2, 0, w / 2, h / 2);
+ init_monitor_geometry (&screen_x11->monitors[2], 0, h / 2, w / 2, h / 2);
+ init_monitor_geometry (&screen_x11->monitors[3], w / 2, h / 2, w / 2, h / 2);
+
+ atts.override_redirect = 1;
+ atts.background_pixel = WhitePixel(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->screen_num);
+ win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->xroot_window, 0, h / 2, w, 1, 0,
+ DefaultDepth(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->screen_num),
+ InputOutput,
+ DefaultVisual(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->screen_num),
+ CWOverrideRedirect|CWBackPixel,
+ &atts);
+ XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
+ win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->xroot_window, w/2 , 0, 1, h, 0,
+ DefaultDepth(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->screen_num),
+ InputOutput,
+ DefaultVisual(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->screen_num),
+ CWOverrideRedirect|CWBackPixel,
+ &atts);
+ XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
+ return TRUE;
+#endif
+
+ return FALSE;
+}
+
+static gboolean
+init_randr12 (GdkScreen *screen)
+{
+#ifdef HAVE_RANDR
+ GdkDisplay *display = gdk_screen_get_display (screen);
+ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+ XRRScreenResources *resources;
+ int i;
+ GArray *monitors;
+
+ if (!display_x11->have_randr12)
+ return FALSE;
+
+ monitors = g_array_new (TRUE, TRUE, sizeof (GdkX11Monitor));
+
+ resources = XRRGetScreenResources (screen_x11->xdisplay,
+ screen_x11->xroot_window);
+
+ /* FIXME: can GetScreenResources return NULL except when it's out of memory? */
+ for (i = 0; i < resources->noutput; ++i)
+ {
+ XRROutputInfo *output =
+ XRRGetOutputInfo (dpy, resources, resources->outputs[i]);
+
+ if (output->crtc)
+ {
+ GdkX11Monitor monitor;
+ XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, output->crtc);
+
+ monitor.geometry.x = crtc->x;
+ monitor.geometry.y = crtc->y;
+ monitor.geometry.width = crtc->width;
+ monitor.geometry.height = crtc->height;
+
+ /* FIXME: fill this out properly - need EDID parser */
+ monitor.output = resources->outputs[i];
+ monitor.width_mm = -1;
+ monitor.height_mm = -1;
+ monitor.output_name = NULL;
+ monitor.manufacturer = NULL;
+
+ g_array_append_val (monitors, monitor);
+ }
+
+ XRRFreeOutputInfo (output);
+ }
+
+ screen_x11->n_monitors = monitors->len;
+ screen_x11->monitors = (GdkX11Monitor *)g_array_free (monitors, FALSE);
+
+ return TRUE;
+#endif
+
+ return FALSE;
+}
+
+static gboolean
+init_solaris_xinerama (GdkScreen *screen)
+{
+#ifdef HAVE_SOLARIS_XINERAMA
+ Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+ int screen_no = gdk_screen_get_number (screen);
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ XRectangle monitors[MAXFRAMEBUFFERS];
+ unsigned char hints[16];
+ gint result;
+ int n_monitors;
+ int i;
+
+ if (!XineramaGetState (dpy, screen_no))
+ return FALSE;
+
+ result = XineramaGetInfo (dpy, screen_no, monitors, hints, &n_monitors);
+
+ /* Yes I know it should be Success but the current implementation
+ * returns the num of monitor
+ */
+ if (result == 0)
+ {
+ /* FIXME: We need to trap errors, since
+ * XINERAMA isn't always XINERAMA.
+ */
+ g_error ("error while retrieving Xinerama information");
+ }
+
+ screen_x11->monitors = g_new0 (GdkX11Monitor, n_rects);
+ screen_x11->n_monitors = n_rects;
+
+ for (i = 0; i < n_rects; i++)
+ {
+ init_monitor_geometry (&screen_x11->monitors[i],
+ rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height);
+ }
+
+ return TRUE;
+#endif /* HAVE_SOLARIS_XINERAMA */
+
+ return FALSE;
+}
+
+static gboolean
+init_xfree_xinerama (GdkScreen *screen)
+{
+#ifdef HAVE_XFREE_XINERAMA
+ Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ XineramaScreenInfo *monitors;
+ int i, n_monitors;
+
+ if (!XineramaIsActive (dpy))
+ return FALSE;
+
+ monitors = XineramaQueryScreens (dpy, &n_monitors);
+
+ if (n_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
+ * is because XRandR 1.2 is currently switching between CRTCs,
+ * we'll be notified again when we have our monitor back,
+ * and can go back into Xinerama-ish mode at that point.
+ */
+ if (monitors)
+ XFree (monitors);
+
+ return FALSE;
+ }
+
+ screen_x11->n_monitors = n_monitors;
+ screen_x11->monitors = g_new0 (GdkX11Monitor, n_monitors);
+
+ for (i = 0; i < n_monitors; ++i)
+ {
+ init_monitor_geometry (&screen_x11->monitors[i],
+ monitors[i].x_org, monitors[i].y_org,
+ monitors[i].width, monitors[i].height);
+ }
+
+ XFree (monitors);
+
+ return TRUE;
+#endif /* HAVE_XFREE_XINERAMA */
+
+ return FALSE;
+}
+
+static void
+deinit_multihead (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ int i;
+
+ for (i = 0; i < screen_x11->n_monitors; ++i)
+ {
+ GdkX11Monitor *monitor = get_monitor (screen, i);
+
+ g_free (monitor->output_name);
+ g_free (monitor->manufacturer);
+ }
+
+ g_free (screen_x11->monitors);
+
+ screen_x11->n_monitors = 0;
+ screen_x11->monitors = NULL;
+}
+
+static void
+init_multihead (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ int opcode, firstevent, firsterror;
+
+ deinit_multihead (screen);
+
+ /* There are four different implementations of multihead support:
+ *
+ * 1. Fake Xinerama for debugging purposes
+ * 2. RandR 1.2
+ * 3. Solaris Xinerama
+ * 4. XFree86/Xorg Xinerama
+ *
+ * We use them in that order.
+ */
+ if (init_fake_xinerama (screen))
+ return;
+
+ if (init_randr12 (screen))
+ return;
+
+ if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
+ &opcode, &firstevent, &firsterror))
+ {
+ if (init_solaris_xinerama (screen))
+ return;
+
+ if (init_xfree_xinerama (screen))
+ return;
+ }
+
+ /* No multihead support of any kind for this screen */
+ screen_x11->n_monitors = 1;
+ screen_x11->monitors = g_new0 (GdkX11Monitor, 1);
+
+ init_monitor_geometry (screen_x11->monitors, 0, 0,
+ WidthOfScreen (screen_x11->xscreen),
+ HeightOfScreen (screen_x11->xscreen));
+}
+
GdkScreen *
_gdk_x11_screen_new (GdkDisplay *display,
gint screen_number)
@@ -512,7 +896,7 @@ _gdk_x11_screen_new (GdkDisplay *display,
screen_x11->cm_selection_atom = make_cm_atom (screen_number);
screen_x11->is_composited = check_is_composited (display, screen_x11);
- init_xinerama_support (screen);
+ init_multihead (screen);
init_randr_support (screen);
_gdk_visual_init (screen);
@@ -549,185 +933,6 @@ gdk_screen_is_composited (GdkScreen *screen)
return screen_x11->is_composited;
}
-#ifdef HAVE_XINERAMA
-static gboolean
-check_solaris_xinerama (GdkScreen *screen)
-{
-#ifdef HAVE_SOLARIS_XINERAMA
-
- if (XineramaGetState (GDK_SCREEN_XDISPLAY (screen),
- gdk_screen_get_number (screen)))
- {
- XRectangle monitors[MAXFRAMEBUFFERS];
- unsigned char hints[16];
- gint result;
- GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
-
- result = XineramaGetInfo (GDK_SCREEN_XDISPLAY (screen),
- gdk_screen_get_number (screen),
- monitors, hints,
- &screen_x11->num_monitors);
- /* Yes I know it should be Success but the current implementation
- returns the num of monitor*/
- if (result == 0)
- {
- /* FIXME: We need to trap errors, since XINERAMA isn't always XINERAMA.
- */
- g_error ("error while retrieving Xinerama information");
- }
- else
- {
- int i;
- screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
-
- for (i = 0; i < screen_x11->num_monitors; i++)
- {
- screen_x11->monitors[i].x = monitors[i].x;
- screen_x11->monitors[i].y = monitors[i].y;
- screen_x11->monitors[i].width = monitors[i].width;
- screen_x11->monitors[i].height = monitors[i].height;
- }
-
- return TRUE;
- }
- }
-#endif /* HAVE_SOLARIS_XINERAMA */
-
- return FALSE;
-}
-
-static gboolean
-check_xfree_xinerama (GdkScreen *screen)
-{
-#ifdef HAVE_XFREE_XINERAMA
- if (XineramaIsActive (GDK_SCREEN_XDISPLAY (screen)))
- {
- GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
- XineramaScreenInfo *monitors = XineramaQueryScreens (GDK_SCREEN_XDISPLAY (screen),
- &screen_x11->num_monitors);
- if (screen_x11->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
- * is because XRandR 1.2 is currently switching between CRTCs,
- * we'll be notified again when we have our monitor back,
- * and can go back into Xinerama-ish mode at that point. */
- if (monitors)
- XFree (monitors);
- return FALSE;
- }
- else
- {
- int i;
- screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
-
- for (i = 0; i < screen_x11->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;
- }
-
- XFree (monitors);
-
- return TRUE;
- }
- }
-#endif /* HAVE_XFREE_XINERAMA */
-
- return FALSE;
-}
-#endif /* HAVE_XINERAMA */
-
-static void
-init_xinerama_support (GdkScreen * screen)
-{
- GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
-#ifdef HAVE_XINERAMA
- int opcode, firstevent, firsterror;
-#endif
-
- g_free (screen_x11->monitors);
-
-#ifdef HAVE_XINERAMA
- if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
- &opcode, &firstevent, &firsterror))
- {
- if (check_solaris_xinerama (screen) ||
- check_xfree_xinerama (screen))
- return;
- }
-#endif /* HAVE_XINERAMA */
-
- /* No Xinerama
- */
-#ifdef G_ENABLE_DEBUG
- if (_gdk_debug_flags & GDK_DEBUG_XINERAMA)
- {
- /* Fake Xinerama mode by splitting the screen into 4 monitors.
- * Also draw a little cross to make the monitor boundaries visible.
- */
- XSetWindowAttributes atts;
- Window win;
- gint w, h;
-
- w = WidthOfScreen (screen_x11->xscreen);
- h = HeightOfScreen (screen_x11->xscreen);
- screen_x11->num_monitors = 4;
- screen_x11->monitors = g_new0 (GdkRectangle, 4);
- screen_x11->monitors[0].x = 0;
- screen_x11->monitors[0].y = 0;
- screen_x11->monitors[0].width = w / 2;
- screen_x11->monitors[0].height = h / 2;
- screen_x11->monitors[1].x = w / 2;
- screen_x11->monitors[1].y = 0;
- screen_x11->monitors[1].width = w / 2;
- screen_x11->monitors[1].height = h / 2;
- screen_x11->monitors[2].x = 0;
- screen_x11->monitors[2].y = h / 2;
- screen_x11->monitors[2].width = w / 2;
- screen_x11->monitors[2].height = h / 2;
- screen_x11->monitors[3].x = w / 2;
- screen_x11->monitors[3].y = h / 2;
- screen_x11->monitors[3].width = w / 2;
- screen_x11->monitors[3].height = h / 2;
- atts.override_redirect = 1;
- atts.background_pixel = WhitePixel(GDK_SCREEN_XDISPLAY (screen),
- screen_x11->screen_num);
- win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen),
- screen_x11->xroot_window, 0, h / 2, w, 1, 0,
- DefaultDepth(GDK_SCREEN_XDISPLAY (screen),
- screen_x11->screen_num),
- InputOutput,
- DefaultVisual(GDK_SCREEN_XDISPLAY (screen),
- screen_x11->screen_num),
- CWOverrideRedirect|CWBackPixel,
- &atts);
- XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
- win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen),
- screen_x11->xroot_window, w/2 , 0, 1, h, 0,
- DefaultDepth(GDK_SCREEN_XDISPLAY (screen),
- screen_x11->screen_num),
- InputOutput,
- DefaultVisual(GDK_SCREEN_XDISPLAY (screen),
- screen_x11->screen_num),
- CWOverrideRedirect|CWBackPixel,
- &atts);
- XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
- }
- else
-#endif
- {
- screen_x11->num_monitors = 1;
- screen_x11->monitors = g_new0 (GdkRectangle, 1);
- screen_x11->monitors[0].x = 0;
- screen_x11->monitors[0].y = 0;
- screen_x11->monitors[0].width = WidthOfScreen (screen_x11->xscreen);
- screen_x11->monitors[0].height = HeightOfScreen (screen_x11->xscreen);
- }
-}
-
static void
init_randr_support (GdkScreen * screen)
{
@@ -736,6 +941,14 @@ init_randr_support (GdkScreen * screen)
XSelectInput (GDK_SCREEN_XDISPLAY (screen),
screen_x11->xroot_window,
StructureNotifyMask);
+
+#ifdef HAVE_RANDR
+ XRRSelectInput (GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->xroot_window,
+ RRScreenChangeNotifyMask |
+ RRCrtcChangeNotifyMask |
+ RROutputPropertyNotifyMask);
+#endif
}
void
@@ -758,11 +971,19 @@ _gdk_x11_screen_size_changed (GdkScreen *screen,
return;
#endif
- init_xinerama_support (screen);
+ init_multihead (screen);
g_signal_emit_by_name (screen, "size_changed");
}
void
+_gdk_x11_screen_process_monitors_change (GdkScreen *screen)
+{
+ init_multihead (screen);
+
+ g_signal_emit_by_name (screen, "monitors_changed");
+}
+
+void
_gdk_x11_screen_window_manager_changed (GdkScreen *screen)
{
g_signal_emit (screen, signals[WINDOW_MANAGER_CHANGED], 0);
diff --git a/gdk/x11/gdkscreen-x11.h b/gdk/x11/gdkscreen-x11.h
index 6ba8d62999..c5b191095b 100644
--- a/gdk/x11/gdkscreen-x11.h
+++ b/gdk/x11/gdkscreen-x11.h
@@ -43,6 +43,8 @@ typedef struct _GdkScreenX11Class GdkScreenX11Class;
#define GDK_IS_SCREEN_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SCREEN_X11))
#define GDK_SCREEN_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SCREEN_X11, GdkScreenX11Class))
+typedef struct _GdkX11Monitor GdkX11Monitor;
+
struct _GdkScreenX11
{
GdkScreen parent_instance;
@@ -87,9 +89,9 @@ struct _GdkScreenX11
XSettingsClient *xsettings_client;
guint xsettings_in_init : 1;
- /* Xinerama */
- gint num_monitors;
- GdkRectangle *monitors;
+ /* Xinerama/RandR 1.2 */
+ gint n_monitors;
+ GdkX11Monitor *monitors;
/* Pango renderer object singleton */
PangoRenderer *renderer;
@@ -124,6 +126,7 @@ void _gdk_x11_screen_size_changed (GdkScreen *screen,
XEvent *event);
void _gdk_x11_screen_process_owner_change (GdkScreen *screen,
XEvent *event);
+void _gdk_x11_screen_process_monitors_change (GdkScreen *screen);
G_END_DECLS
diff --git a/gdk/x11/gdkx.h b/gdk/x11/gdkx.h
index ec85047913..64185f8288 100644
--- a/gdk/x11/gdkx.h
+++ b/gdk/x11/gdkx.h
@@ -156,6 +156,9 @@ void gdk_x11_display_broadcast_startup_message (GdkDisplay *display,
gboolean gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
GdkAtom property);
+XID gdk_x11_screen_get_monitor_output (GdkScreen *screen,
+ gint monitor_num);
+
#ifndef GDK_MULTIHEAD_SAFE
gpointer gdk_xid_table_lookup (XID xid);
gboolean gdk_net_wm_supports (GdkAtom property);