summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cogl/Makefile.am3
-rw-r--r--cogl/cogl-output-private.h50
-rw-r--r--cogl/cogl-output.c110
-rw-r--r--cogl/cogl-output.h242
-rw-r--r--cogl/cogl-renderer-private.h2
-rw-r--r--cogl/cogl-xlib-renderer-private.h10
-rw-r--r--cogl/cogl-xlib-renderer.c334
-rw-r--r--cogl/winsys/cogl-winsys-glx.c110
-rw-r--r--cogl/winsys/cogl-winsys-private.h3
-rw-r--r--configure.ac3
10 files changed, 858 insertions, 9 deletions
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 405a997a..bf24f635 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -114,6 +114,7 @@ cogl_experimental_h = \
$(srcdir)/cogl-onscreen.h \
$(srcdir)/cogl-vector.h \
$(srcdir)/cogl-euler.h \
+ $(srcdir)/cogl-output.h \
$(srcdir)/cogl-quaternion.h \
$(srcdir)/cogl-matrix-stack.h \
$(srcdir)/cogl-poll.h \
@@ -387,6 +388,8 @@ cogl_sources_c = \
$(srcdir)/cogl-framebuffer.c \
$(srcdir)/cogl-onscreen-private.h \
$(srcdir)/cogl-onscreen.c \
+ $(srcdir)/cogl-output-private.h \
+ $(srcdir)/cogl-output.c \
$(srcdir)/cogl-profile.h \
$(srcdir)/cogl-profile.c \
$(srcdir)/cogl-flags.h \
diff --git a/cogl/cogl-output-private.h b/cogl/cogl-output-private.h
new file mode 100644
index 00000000..a4910e9c
--- /dev/null
+++ b/cogl/cogl-output-private.h
@@ -0,0 +1,50 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef __COGL_OUTPUT_PRIVATE_H
+#define __COGL_OUTPUT_PRIVATE_H
+
+#include "cogl-output.h"
+#include "cogl-object-private.h"
+
+struct _CoglOutput
+{
+ CoglObject _parent;
+
+ char *name;
+
+ int x; /* Must be first field for _cogl_output_values_equal() */
+ int y;
+ int width;
+ int height;
+ int mm_width;
+ int mm_height;
+ float refresh_rate;
+ CoglSubpixelOrder subpixel_order;
+};
+
+CoglOutput *_cogl_output_new (const char *name);
+CoglBool _cogl_output_values_equal (CoglOutput *output,
+ CoglOutput *other);
+
+#endif /* __COGL_OUTPUT_PRIVATE_H */
diff --git a/cogl/cogl-output.c b/cogl/cogl-output.c
new file mode 100644
index 00000000..1f5e78fc
--- /dev/null
+++ b/cogl/cogl-output.c
@@ -0,0 +1,110 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-output-private.h"
+
+#include <string.h>
+
+static void _cogl_output_free (CoglOutput *output);
+
+COGL_OBJECT_DEFINE (Output, output);
+
+CoglOutput *
+_cogl_output_new (const char *name)
+{
+ CoglOutput *output;
+
+ output = g_slice_new0 (CoglOutput);
+ output->name = g_strdup (name);
+
+ return _cogl_output_object_new (output);
+}
+
+static void
+_cogl_output_free (CoglOutput *output)
+{
+ g_free (output->name);
+
+ g_slice_free (CoglOutput, output);
+}
+
+gboolean
+_cogl_output_values_equal (CoglOutput *output,
+ CoglOutput *other)
+{
+ return memcmp ((const char *)output + G_STRUCT_OFFSET (CoglOutput, x),
+ (const char *)other + G_STRUCT_OFFSET (CoglOutput, x),
+ sizeof (CoglOutput) - G_STRUCT_OFFSET (CoglOutput, x)) == 0;
+}
+
+int
+cogl_output_get_x (CoglOutput *output)
+{
+ return output->x;
+}
+
+int
+cogl_output_get_y (CoglOutput *output)
+{
+ return output->y;
+}
+
+int
+cogl_output_get_width (CoglOutput *output)
+{
+ return output->width;
+}
+
+int
+cogl_output_get_height (CoglOutput *output)
+{
+ return output->height;
+}
+
+int
+cogl_output_get_mm_width (CoglOutput *output)
+{
+ return output->mm_width;
+}
+
+int
+cogl_output_get_mm_height (CoglOutput *output)
+{
+ return output->mm_height;
+}
+
+CoglSubpixelOrder
+cogl_output_get_subpixel_order (CoglOutput *output)
+{
+ return output->subpixel_order;
+}
+
+float
+cogl_output_get_refresh_rate (CoglOutput *output)
+{
+ return output->refresh_rate;
+}
diff --git a/cogl/cogl-output.h b/cogl/cogl-output.h
new file mode 100644
index 00000000..473a5cc9
--- /dev/null
+++ b/cogl/cogl-output.h
@@ -0,0 +1,242 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ * Owen Taylor <otaylor@redhat.com>
+ */
+#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef __COGL_OUTPUT_H
+#define __COGL_OUTPUT_H
+
+#include <cogl/cogl-types.h>
+
+COGL_BEGIN_DECLS
+
+/**
+ * SECTION:cogl-output
+ * @short_description: information about an output device
+ *
+ * The #CoglOutput object holds information about an output device
+ * such as a monitor or laptop display. It can be queried to find
+ * out the position of the output with respect to the screen
+ * coordinate system and other information such as the resolution
+ * and refresh rate of the device.
+ *
+ * There can be any number of outputs which may overlap: the
+ * same area of the screen may be displayed by multiple output
+ * devices.
+ *
+ * XXX: though it's possible to query the position of the output
+ * with respect to screen coordinates, there is currently no way
+ * of finding out the position of a #CoglOnscreen in screen
+ * coordinates, at least without using windowing-system specific
+ * API's, so it's not easy to get the output positions relative
+ * to the #CoglOnscreen.
+ */
+
+typedef struct _CoglOutput CoglOutput;
+#define COGL_OUTPUT(X) ((CoglOutput *)(X))
+
+/**
+ * CoglSubpixelOrder
+ * @COGL_SUBPIXEL_ORDER_UNKNOWN: the layout of subpixel
+ * components for the device is unknown.
+ * @COGL_SUBPIXEL_ORDER_NONE: the device displays colors
+ * without geometrically-separated subpixel components,
+ * or the positioning or colors of the components do not
+ * match any of the values in the enumeration.
+ * @COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB: the device has
+ * horizontally arranged components in the order
+ * red-green-blue from left to right.
+ * @COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR: the device has
+ * horizontally arranged components in the order
+ * blue-green-red from left to right.
+ * @COGL_SUBPIXEL_ORDER_VERTICAL_RGB: the device has
+ * vertically arranged components in the order
+ * red-green-blue from top to bottom.
+ * @COGL_SUBPIXEL_ORDER_VERTICAL_BGR: the device has
+ * vertically arranged components in the order
+ * blue-green-red from top to bottom.
+ *
+ * Some output devices (such as LCD panels) display colors
+ * by making each pixel consist of smaller "subpixels"
+ * that each have a particular color. By using knowledge
+ * of the layout of this subpixel components, it is possible
+ * to create image content with higher resolution than the
+ * pixel grid.
+ *
+ * Since: 1.14
+ * Stability: unstable
+ */
+typedef enum {
+ COGL_SUBPIXEL_ORDER_UNKNOWN,
+ COGL_SUBPIXEL_ORDER_NONE,
+ COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB,
+ COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR,
+ COGL_SUBPIXEL_ORDER_VERTICAL_RGB,
+ COGL_SUBPIXEL_ORDER_VERTICAL_BGR
+} CoglSubpixelOrder;
+
+/**
+ * cogl_is_output:
+ * @object: A #CoglObject pointer
+ *
+ * Gets whether the given object references a #CoglOutput.
+ *
+ * Return value: %TRUE if the object references a #CoglOutput
+ * and %FALSE otherwise.
+ * Since: 1.14
+ * Stability: unstable
+ */
+CoglBool
+cogl_is_output (void *object);
+
+/**
+ * cogl_output_get_x:
+ * @output: a #CoglOutput
+ *
+ * Gets the X position of the output with respect to the coordinate
+ * system of the screen.
+ *
+ * Return value: the X position of the output as a pixel offset
+ * from the left side of the screen coordinate space
+ * Since: 1.14
+ * Stability: unstable
+ */
+int
+cogl_output_get_x (CoglOutput *output);
+
+/**
+ * cogl_output_get_y:
+ * @output: a #CoglOutput
+ *
+ * Gets the Y position of the output with respect to the coordinate
+ * system of the screen.
+ *
+ * Return value: the Y position of the output as a pixel offset
+ * from the top side of the screen coordinate space
+ * Since: 1.14
+ * Stability: unstable
+ */
+int
+cogl_output_get_y (CoglOutput *output);
+
+/**
+ * cogl_output_get_width:
+ * @output: a #CoglOutput
+ *
+ * Gets the width of the output in pixels.
+ *
+ * Return value: the width of the output in pixels
+ * Since: 1.14
+ * Stability: unstable
+ */
+int
+cogl_output_get_width (CoglOutput *output);
+
+/**
+ * cogl_output_get_height:
+ * @output: a #CoglOutput
+ *
+ * Gets the height of the output in pixels.
+ *
+ * Return value: the height of the output in pixels
+ * Since: 1.14
+ * Stability: unstable
+ */
+int
+cogl_output_get_height (CoglOutput *output);
+
+/**
+ * cogl_output_get_mm_width:
+ * @output: a #CoglOutput
+ *
+ * Gets the physical width of the output. In some cases (such as
+ * as a projector), the value returned here might correspond to
+ * nominal resolution rather than the actual physical size of the
+ * output device.
+ *
+ * Return value: the height of the output in millimeters. A value
+ * of 0 indicates the width is unknown
+ * Since: 1.14
+ * Stability: unstable
+ */
+int
+cogl_output_get_mm_width (CoglOutput *output);
+
+/**
+ * cogl_output_get_mm_height:
+ * @output: a #CoglOutput
+ *
+ * Gets the physical height of the output. In some cases (such as
+ * as a projector), the value returned here might correspond to
+ * nominal resolution rather than the actual physical size of the
+ * output device.
+ *
+ * Return value: the height of the output in millimeters. A value
+ * of 0 indicates that the height is unknown
+ * Since: 1.14
+ * Stability: unstable
+ */
+int
+cogl_output_get_mm_height (CoglOutput *output);
+
+/**
+ * cogl_output_get_subpixel_order:
+ * @output: a #CoglOutput
+ *
+ * For an output device where each pixel is made up of smaller components
+ * with different colors, returns the layout of the subpixel
+ * components.
+ *
+ * Return value: the order of subpixel components for the output device
+ * Since: 1.14
+ * Stability: unstable
+ */
+CoglSubpixelOrder
+cogl_output_get_subpixel_order (CoglOutput *output);
+
+/**
+ * cogl_output_get_refresh_rate:
+ * @output: a #CoglOutput
+ *
+ * Gets the number of times per second that the output device refreshes
+ * the display contents.
+ *
+ * Return value: the refresh rate of the output device. A value of zero
+ * indicates that the refresh rate is unknown.
+ * Since: 1.14
+ * Stability: unstable
+ */
+float
+cogl_output_get_refresh_rate (CoglOutput *output);
+
+COGL_END_DECLS
+
+#endif /* __COGL_OUTPUT_H */
+
+
+
diff --git a/cogl/cogl-renderer-private.h b/cogl/cogl-renderer-private.h
index ac6effdb..2b5c8363 100644
--- a/cogl/cogl-renderer-private.h
+++ b/cogl/cogl-renderer-private.h
@@ -50,6 +50,8 @@ struct _CoglRenderer
CoglWinsysID winsys_id_override;
GList *constraints;
+ GList *outputs;
+
#ifdef COGL_HAS_XLIB_SUPPORT
Display *foreign_xdpy;
CoglBool xlib_enable_event_retrieval;
diff --git a/cogl/cogl-xlib-renderer-private.h b/cogl/cogl-xlib-renderer-private.h
index 4970f201..7990e6c6 100644
--- a/cogl/cogl-xlib-renderer-private.h
+++ b/cogl/cogl-xlib-renderer-private.h
@@ -28,6 +28,7 @@
#include "cogl-xlib-private.h"
#include "cogl-x11-renderer-private.h"
#include "cogl-context.h"
+#include "cogl-output.h"
typedef struct _CoglXlibRenderer
{
@@ -41,6 +42,8 @@ typedef struct _CoglXlibRenderer
/* A poll FD for handling event retrieval within Cogl */
CoglPollFD poll_fd;
+
+ unsigned long outputs_update_serial;
} CoglXlibRenderer;
CoglBool
@@ -92,4 +95,11 @@ _cogl_xlib_renderer_poll_dispatch (CoglRenderer *renderer,
const CoglPollFD *poll_fds,
int n_poll_fds);
+CoglOutput *
+_cogl_xlib_renderer_output_for_rectangle (CoglRenderer *renderer,
+ int x,
+ int y,
+ int width,
+ int height);
+
#endif /* __COGL_RENDERER_XLIB_PRIVATE_H */
diff --git a/cogl/cogl-xlib-renderer.c b/cogl/cogl-xlib-renderer.c
index 1116332a..18c0fe63 100644
--- a/cogl/cogl-xlib-renderer.c
+++ b/cogl/cogl-xlib-renderer.c
@@ -32,6 +32,7 @@
#include "cogl-util.h"
#include "cogl-object.h"
+#include "cogl-output-private.h"
#include "cogl-renderer-private.h"
#include "cogl-xlib-renderer-private.h"
#include "cogl-x11-renderer-private.h"
@@ -40,8 +41,10 @@
#include <X11/Xlib.h>
#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xrandr.h>
#include <stdlib.h>
+#include <string.h>
static char *_cogl_x11_display_name = NULL;
static GList *_cogl_xlib_renderers = NULL;
@@ -190,6 +193,280 @@ assert_xlib_display (CoglRenderer *renderer, CoglError **error)
return xdpy;
}
+static int
+compare_outputs (CoglOutput *a,
+ CoglOutput *b)
+{
+ return strcmp (a->name, b->name);
+}
+
+#define CSO(X) COGL_SUBPIXEL_ORDER_ ## X
+static CoglSubpixelOrder subpixel_map[6][6] = {
+ { CSO(UNKNOWN), CSO(NONE), CSO(HORIZONTAL_RGB), CSO(HORIZONTAL_BGR),
+ CSO(VERTICAL_RGB), CSO(VERTICAL_BGR) }, /* 0 */
+ { CSO(UNKNOWN), CSO(NONE), CSO(VERTICAL_RGB), CSO(VERTICAL_BGR),
+ CSO(HORIZONTAL_BGR), CSO(HORIZONTAL_RGB) }, /* 90 */
+ { CSO(UNKNOWN), CSO(NONE), CSO(HORIZONTAL_BGR), CSO(HORIZONTAL_RGB),
+ CSO(VERTICAL_BGR), CSO(VERTICAL_RGB) }, /* 180 */
+ { CSO(UNKNOWN), CSO(NONE), CSO(VERTICAL_BGR), CSO(VERTICAL_RGB),
+ CSO(HORIZONTAL_RGB), CSO(HORIZONTAL_BGR) }, /* 270 */
+ { CSO(UNKNOWN), CSO(NONE), CSO(HORIZONTAL_BGR), CSO(HORIZONTAL_RGB),
+ CSO(VERTICAL_RGB), CSO(VERTICAL_BGR) }, /* Reflect_X */
+ { CSO(UNKNOWN), CSO(NONE), CSO(HORIZONTAL_RGB), CSO(HORIZONTAL_BGR),
+ CSO(VERTICAL_BGR), CSO(VERTICAL_RGB) }, /* Reflect_Y */
+};
+#undef CSO
+
+static void
+update_outputs (CoglRenderer *renderer,
+ CoglBool notify)
+{
+ CoglXlibRenderer *xlib_renderer =
+ _cogl_xlib_renderer_get_data (renderer);
+ XRRScreenResources *resources;
+ CoglXlibTrapState state;
+ CoglBool error = FALSE;
+ GList *new_outputs = NULL;
+ GList *l, *m;
+ CoglBool changed = FALSE;
+ int i;
+
+ xlib_renderer->outputs_update_serial = XNextRequest (xlib_renderer->xdpy);
+
+ resources = XRRGetScreenResources (xlib_renderer->xdpy,
+ DefaultRootWindow (xlib_renderer->xdpy));
+
+ _cogl_xlib_renderer_trap_errors (renderer, &state);
+
+ for (i = 0; i < resources->ncrtc && !error; i++)
+ {
+ XRRCrtcInfo *crtc_info = NULL;
+ XRROutputInfo *output_info = NULL;
+ CoglOutput *output;
+ float refresh_rate = 0;
+ int j;
+
+ crtc_info = XRRGetCrtcInfo (xlib_renderer->xdpy,
+ resources, resources->crtcs[i]);
+ if (crtc_info == NULL)
+ {
+ error = TRUE;
+ goto next;
+ }
+
+ if (crtc_info->mode == None)
+ goto next;
+
+ for (j = 0; j < resources->nmode; j++)
+ {
+ if (resources->modes[j].id == crtc_info->mode)
+ refresh_rate = (resources->modes[j].dotClock /
+ ((float)resources->modes[j].hTotal *
+ resources->modes[j].vTotal));
+ }
+
+ output_info = XRRGetOutputInfo (xlib_renderer->xdpy,
+ resources,
+ crtc_info->outputs[0]);
+ if (output_info == NULL)
+ {
+ error = TRUE;
+ goto next;
+ }
+
+ output = _cogl_output_new (output_info->name);
+ output->x = crtc_info->x;
+ output->y = crtc_info->y;
+ output->width = crtc_info->width;
+ output->height = crtc_info->height;
+ if ((crtc_info->rotation & (RR_Rotate_90 | RR_Rotate_270)) != 0)
+ {
+ output->mm_width = output_info->mm_height;
+ output->mm_height = output_info->mm_width;
+ }
+ else
+ {
+ output->mm_width = output_info->mm_width;
+ output->mm_height = output_info->mm_height;
+ }
+
+ output->refresh_rate = refresh_rate;
+
+ switch (output_info->subpixel_order)
+ {
+ case SubPixelUnknown:
+ default:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
+ break;
+ case SubPixelNone:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
+ break;
+ case SubPixelHorizontalRGB:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
+ break;
+ case SubPixelHorizontalBGR:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
+ break;
+ case SubPixelVerticalRGB:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
+ break;
+ case SubPixelVerticalBGR:
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
+ break;
+ }
+
+ output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
+
+ /* Handle the effect of rotation and reflection on subpixel order (ugh) */
+ for (j = 0; j < 6; j++)
+ {
+ if ((crtc_info->rotation & (1 << j)) != 0)
+ output->subpixel_order = subpixel_map[j][output->subpixel_order];
+ }
+
+ new_outputs = g_list_prepend (new_outputs, output);
+
+ next:
+ if (crtc_info != NULL)
+ XFree (crtc_info);
+
+ if (output_info != NULL)
+ XFree (output_info);
+ }
+
+ XFree (resources);
+
+ if (!error)
+ {
+ new_outputs = g_list_sort (new_outputs, (GCompareFunc)compare_outputs);
+
+ l = new_outputs;
+ m = renderer->outputs;
+
+ while (l || m)
+ {
+ int cmp;
+ CoglOutput *output_l = l ? (CoglOutput *)l->data : NULL;
+ CoglOutput *output_m = m ? (CoglOutput *)m->data : NULL;
+
+ if (l && m)
+ cmp = compare_outputs (output_l, output_m);
+ else if (l)
+ cmp = -1;
+ else
+ cmp = 1;
+
+ if (cmp == 0)
+ {
+ GList *m_next = m->next;
+
+ if (!_cogl_output_values_equal (output_l, output_m))
+ {
+ renderer->outputs = g_list_remove_link (renderer->outputs, m);
+ renderer->outputs = g_list_insert_before (renderer->outputs,
+ m_next, output_l);
+ cogl_object_ref (output_l);
+
+ changed = TRUE;
+ }
+
+ l = l->next;
+ m = m_next;
+ }
+ else if (cmp < 0)
+ {
+ renderer->outputs =
+ g_list_insert_before (renderer->outputs, m, output_l);
+ cogl_object_ref (output_l);
+ changed = TRUE;
+ l = l->next;
+ }
+ else
+ {
+ GList *m_next = m->next;
+ renderer->outputs = g_list_remove_link (renderer->outputs, m);
+ changed = TRUE;
+ m = m_next;
+ }
+ }
+ }
+
+ g_list_free_full (new_outputs, (GDestroyNotify)cogl_object_unref);
+ _cogl_xlib_renderer_untrap_errors (renderer, &state);
+
+ if (changed)
+ {
+ const CoglWinsysVtable *winsys = renderer->winsys_vtable;
+
+ if (notify)
+ COGL_NOTE (WINSYS, "Outputs changed:");
+ else
+ COGL_NOTE (WINSYS, "Outputs:");
+
+ for (l = renderer->outputs; l; l = l->next)
+ {
+ CoglOutput *output = l->data;
+ const char *subpixel_string;
+
+ switch (output->subpixel_order)
+ {
+ case COGL_SUBPIXEL_ORDER_UNKNOWN:
+ default:
+ subpixel_string = "unknown";
+ break;
+ case COGL_SUBPIXEL_ORDER_NONE:
+ subpixel_string = "none";
+ break;
+ case COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB:
+ subpixel_string = "horizontal_rgb";
+ break;
+ case COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR:
+ subpixel_string = "horizontal_bgr";
+ break;
+ case COGL_SUBPIXEL_ORDER_VERTICAL_RGB:
+ subpixel_string = "vertical_rgb";
+ break;
+ case COGL_SUBPIXEL_ORDER_VERTICAL_BGR:
+ subpixel_string = "vertical_bgr";
+ break;
+ }
+
+ COGL_NOTE (WINSYS,
+ " %10s: +%d+%dx%dx%d mm=%dx%d dpi=%.1fx%.1f "
+ "subpixel_order=%s refresh_rate=%.3f",
+ output->name,
+ output->x, output->y, output->width, output->height,
+ output->mm_width, output->mm_height,
+ output->width / (output->mm_width / 25.4),
+ output->height / (output->mm_height / 25.4),
+ subpixel_string,
+ output->refresh_rate);
+ }
+
+ if (notify && winsys->renderer_outputs_changed != NULL)
+ winsys->renderer_outputs_changed (renderer);
+ }
+}
+
+static CoglFilterReturn
+randr_filter (XEvent *event,
+ void *data)
+{
+ CoglRenderer *renderer = data;
+ CoglXlibRenderer *xlib_renderer =
+ _cogl_xlib_renderer_get_data (renderer);
+ CoglX11Renderer *x11_renderer =
+ (CoglX11Renderer *) xlib_renderer;
+
+ if (x11_renderer->randr_base != -1 &&
+ (event->xany.type == x11_renderer->randr_base + RRScreenChangeNotify ||
+ event->xany.type == x11_renderer->randr_base + RRNotify) &&
+ event->xany.serial >= xlib_renderer->outputs_update_serial)
+ update_outputs (renderer, TRUE);
+
+ return COGL_FILTER_CONTINUE;
+}
+
CoglBool
_cogl_xlib_renderer_connect (CoglRenderer *renderer, CoglError **error)
{
@@ -198,6 +475,7 @@ _cogl_xlib_renderer_connect (CoglRenderer *renderer, CoglError **error)
CoglX11Renderer *x11_renderer =
(CoglX11Renderer *) xlib_renderer;
int damage_error;
+ int randr_error;
if (!assert_xlib_display (renderer, error))
return FALSE;
@@ -211,13 +489,30 @@ _cogl_xlib_renderer_connect (CoglRenderer *renderer, CoglError **error)
&damage_error))
x11_renderer->damage_base = -1;
+ /* Check whether randr is supported on this display */
+ if (!XRRQueryExtension (xlib_renderer->xdpy,
+ &x11_renderer->randr_base,
+ &randr_error))
+ x11_renderer->randr_base = -1;
+
xlib_renderer->trap_state = NULL;
xlib_renderer->poll_fd.fd = ConnectionNumber (xlib_renderer->xdpy);
xlib_renderer->poll_fd.events = COGL_POLL_FD_EVENT_IN;
+ XRRSelectInput(xlib_renderer->xdpy,
+ DefaultRootWindow (xlib_renderer->xdpy),
+ RRScreenChangeNotifyMask
+ | RRCrtcChangeNotifyMask
+ | RROutputPropertyNotifyMask);
+ update_outputs (renderer, FALSE);
+
register_xlib_renderer (renderer);
+ cogl_xlib_renderer_add_filter (renderer,
+ randr_filter,
+ renderer);
+
return TRUE;
}
@@ -227,6 +522,9 @@ _cogl_xlib_renderer_disconnect (CoglRenderer *renderer)
CoglXlibRenderer *xlib_renderer =
_cogl_xlib_renderer_get_data (renderer);
+ g_list_free_full (renderer->outputs, (GDestroyNotify)cogl_object_unref);
+ renderer->outputs = NULL;
+
if (!renderer->foreign_xdpy && xlib_renderer->xdpy)
XCloseDisplay (xlib_renderer->xdpy);
@@ -312,3 +610,39 @@ _cogl_xlib_renderer_poll_dispatch (CoglRenderer *renderer,
cogl_xlib_renderer_handle_event (renderer, &xevent);
}
}
+
+CoglOutput *
+_cogl_xlib_renderer_output_for_rectangle (CoglRenderer *renderer,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ int max_overlap = 0;
+ CoglOutput *max_overlapped = NULL;
+ GList *l;
+ int xa1 = x, xa2 = x + width;
+ int ya1 = y, ya2 = y + height;
+
+ for (l = renderer->outputs; l; l = l->next)
+ {
+ CoglOutput *output = l->data;
+ int xb1 = output->x, xb2 = output->x + output->width;
+ int yb1 = output->y, yb2 = output->y + output->height;
+
+ int overlap_x = MIN(xa2, xb2) - MAX(xa1, xb1);
+ int overlap_y = MIN(ya2, yb2) - MAX(ya1, yb1);
+
+ if (overlap_x > 0 && overlap_y > 0)
+ {
+ int overlap = overlap_x * overlap_y;
+ if (overlap > max_overlap)
+ {
+ max_overlap = overlap;
+ max_overlapped = output;
+ }
+ }
+ }
+
+ return max_overlapped;
+}
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index f91e73ad..d4cd096e 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -71,7 +71,9 @@ typedef struct _CoglContextGLX
typedef struct _CoglOnscreenXlib
{
Window xwin;
+ int x, y;
CoglBool is_foreign_xwin;
+ CoglOutput *output;
} CoglOnscreenXlib;
typedef struct _CoglOnscreenGLX
@@ -189,29 +191,84 @@ notify_swap_buffers (CoglContext *context, GLXDrawable drawable)
}
static void
+update_output (CoglOnscreen *onscreen)
+{
+ CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ CoglContext *context = framebuffer->context;
+ CoglDisplay *display = context->display;
+ CoglOutput *output;
+ int width, height;
+
+ width = cogl_framebuffer_get_width (framebuffer);
+ height = cogl_framebuffer_get_height (framebuffer);
+ output = _cogl_xlib_renderer_output_for_rectangle (display->renderer,
+ xlib_onscreen->x,
+ xlib_onscreen->y,
+ width, height);
+ if (xlib_onscreen->output != output)
+ {
+ if (xlib_onscreen->output)
+ cogl_object_unref (xlib_onscreen->output);
+
+ xlib_onscreen->output = output;
+
+ if (output)
+ cogl_object_ref (xlib_onscreen->output);
+ }
+}
+
+static void
notify_resize (CoglContext *context,
- GLXDrawable drawable,
- int width,
- int height)
+ XConfigureEvent *configure_event)
{
- CoglOnscreen *onscreen = find_onscreen_for_xid (context, drawable);
+ CoglOnscreen *onscreen = find_onscreen_for_xid (context,
+ configure_event->window);
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglDisplay *display = context->display;
CoglGLXDisplay *glx_display = display->winsys;
CoglOnscreenGLX *glx_onscreen;
+ CoglOnscreenXlib *xlib_onscreen;
if (!onscreen)
return;
glx_onscreen = onscreen->winsys;
+ xlib_onscreen = onscreen->winsys;
- _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
+ _cogl_framebuffer_winsys_update_size (framebuffer,
+ configure_event->width,
+ configure_event->height);
/* We only want to notify that a resize happened when the
application calls cogl_context_dispatch so instead of immediately
notifying we'll set a flag to remember to notify later */
glx_display->pending_resize_notify = TRUE;
glx_onscreen->pending_resize_notify = TRUE;
+
+ if (!xlib_onscreen->is_foreign_xwin)
+ {
+ int x, y;
+
+ if (configure_event->send_event)
+ {
+ x = configure_event->x;
+ y = configure_event->y;
+ }
+ else
+ {
+ Window child;
+ XTranslateCoordinates (configure_event->display,
+ configure_event->window,
+ DefaultRootWindow (configure_event->display),
+ 0, 0, &x, &y, &child);
+ }
+
+ xlib_onscreen->x = x;
+ xlib_onscreen->y = y;
+
+ update_output (onscreen);
+ }
}
static CoglFilterReturn
@@ -225,9 +282,7 @@ glx_event_filter_cb (XEvent *xevent, void *data)
if (xevent->type == ConfigureNotify)
{
notify_resize (context,
- xevent->xconfigure.window,
- xevent->xconfigure.width,
- xevent->xconfigure.height);
+ &xevent->xconfigure);
/* we let ConfigureNotify pass through */
return COGL_FILTER_CONTINUE;
@@ -264,6 +319,38 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
}
static CoglBool
+update_all_outputs (CoglRenderer *renderer)
+{
+ GList *l;
+
+ _COGL_GET_CONTEXT (context, FALSE);
+
+ if (context->display == NULL) /* during connection */
+ return FALSE;
+
+ if (context->display->renderer != renderer)
+ return FALSE;
+
+ for (l = context->framebuffers; l; l = l->next)
+ {
+ CoglFramebuffer *framebuffer = l->data;
+
+ if (framebuffer->type != COGL_FRAMEBUFFER_TYPE_ONSCREEN)
+ continue;
+
+ update_output (COGL_ONSCREEN (framebuffer));
+ }
+
+ return TRUE;
+}
+
+static void
+_cogl_winsys_renderer_outputs_changed (CoglRenderer *renderer)
+{
+ update_all_outputs (renderer);
+}
+
+static CoglBool
resolve_core_glx_functions (CoglRenderer *renderer,
CoglError **error)
{
@@ -1060,6 +1147,12 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
if (glx_onscreen == NULL)
return;
+ if (xlib_onscreen->output != NULL)
+ {
+ cogl_object_unref (xlib_onscreen->output);
+ xlib_onscreen->output = NULL;
+ }
+
_cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state);
drawable =
@@ -2206,6 +2299,7 @@ static CoglWinsysVtable _cogl_winsys_vtable =
.renderer_get_proc_address = _cogl_winsys_renderer_get_proc_address,
.renderer_connect = _cogl_winsys_renderer_connect,
.renderer_disconnect = _cogl_winsys_renderer_disconnect,
+ .renderer_outputs_changed = _cogl_winsys_renderer_outputs_changed,
.display_setup = _cogl_winsys_display_setup,
.display_destroy = _cogl_winsys_display_destroy,
.context_init = _cogl_winsys_context_init,
diff --git a/cogl/winsys/cogl-winsys-private.h b/cogl/winsys/cogl-winsys-private.h
index dafbada8..5be79f60 100644
--- a/cogl/winsys/cogl-winsys-private.h
+++ b/cogl/winsys/cogl-winsys-private.h
@@ -83,6 +83,9 @@ typedef struct _CoglWinsysVtable
void
(*renderer_disconnect) (CoglRenderer *renderer);
+ void
+ (*renderer_outputs_changed) (CoglRenderer *renderer);
+
CoglBool
(*display_setup) (CoglDisplay *display, CoglError **error);
diff --git a/configure.ac b/configure.ac
index 170c624b..4ca62255 100644
--- a/configure.ac
+++ b/configure.ac
@@ -90,6 +90,7 @@ m4_define([uprof_req_version], [0.3])
m4_define([gtk_doc_req_version], [1.13])
m4_define([xfixes_req_version], [3])
m4_define([xcomposite_req_version], [0.4])
+m4_define([xrandr_req_version], [1.2])
m4_define([cairo_req_version], [1.10])
dnl These variables get copied into the generated README
@@ -1073,7 +1074,7 @@ dnl Check X11 dependencies if required
dnl ========================================================
AS_IF([test "x$NEED_XLIB" = "xyes"],
[
- X11_MODULES="x11 xext xfixes >= xfixes_req_version xdamage xcomposite >= xcomposite_req_version"
+ X11_MODULES="x11 xext xfixes >= xfixes_req_version xdamage xcomposite >= xcomposite_req_version xrandr >= xrandr_req_version"
PKG_CHECK_MODULES(DUMMY, [$X11_MODULES],
[COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES $X11_MODULES"])
SUPPORT_X11=yes