[cogl/wip/frame-synchronization: 238/240] Add CoglOutput and track for the GLX backend



commit 7dc907004a70c3983d0f04cd74446a8ad8ecd31c
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Mon Nov 12 11:31:16 2012 -0500

    Add CoglOutput and track for the GLX backend
    
    The CoglOutput object represents one output such as a monitor or
    laptop panel, with information about attributes of the output such as
    the position of the output within the global coordinate space, and
    the refresh rate.
    
    We don't yet publically export the ability to get output information but
    we track it for the GLX backend, where we'll use it to track the refresh
    rate.

 cogl/Makefile.am                  |    3 +
 cogl/cogl-output-private.h        |   50 ++++++
 cogl/cogl-output.h                |   87 ++++++++++
 cogl/cogl-xlib-renderer-private.h |   11 ++
 cogl/cogl-xlib-renderer.c         |  327 +++++++++++++++++++++++++++++++++++++
 cogl/winsys/cogl-winsys-glx.c     |  106 +++++++++++-
 cogl/winsys/cogl-winsys-private.h |    3 +
 configure.ac                      |    3 +-
 8 files changed, 581 insertions(+), 9 deletions(-)
---
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index a73d3f8..022caf5 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -106,6 +106,7 @@ cogl_experimental_h = \
 	$(srcdir)/cogl-clip-state.h		\
 	$(srcdir)/cogl-framebuffer.h		\
 	$(srcdir)/cogl-onscreen.h		\
+	$(srcdir)/cogl-output.h			\
 	$(srcdir)/cogl-vector.h 		\
 	$(srcdir)/cogl-euler.h 			\
 	$(srcdir)/cogl-quaternion.h 		\
@@ -345,6 +346,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 0000000..05803de
--- /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);
+gboolean _cogl_output_values_equal (CoglOutput *output,
+                                    CoglOutput *other);
+
+#endif /* __COGL_OUTPUT_PRIVATE_H */
diff --git a/cogl/cogl-output.h b/cogl/cogl-output.h
new file mode 100644
index 0000000..48da41f
--- /dev/null
+++ b/cogl/cogl-output.h
@@ -0,0 +1,87 @@
+/*
+ * 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>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _CoglOutput CoglOutput;
+#define COGL_OUTPUT(X) ((CoglOutput *)(X))
+
+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: 2.0
+ * Stability: unstable
+ */
+CoglBool
+cogl_is_output (void *object);
+
+int
+cogl_output_get_x (CoglOutput *output);
+int
+cogl_output_get_y (CoglOutput *output);
+int
+cogl_output_get_width (CoglOutput *output);
+int
+cogl_output_get_height (CoglOutput *output);
+int
+cogl_output_get_mm_width (CoglOutput *output);
+int
+cogl_output_get_mm_height (CoglOutput *output);
+CoglSubpixelOrder
+cogl_output_get_subpixel_order (CoglOutput *output);
+float
+cogl_output_get_refresh_rate (CoglOutput *output);
+
+G_END_DECLS
+
+#endif /* __COGL_OUTPUT_H */
+
+
+
diff --git a/cogl/cogl-xlib-renderer-private.h b/cogl/cogl-xlib-renderer-private.h
index 0c73b5c..cb3b60e 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,9 @@ typedef struct _CoglXlibRenderer
 
   /* A poll FD for handling event retrieval within Cogl */
   CoglPollFD poll_fd;
+
+  unsigned long outputs_update_serial;
+  GList *outputs;
 } CoglXlibRenderer;
 
 CoglBool
@@ -92,4 +96,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 9ae7765..fff3c35 100644
--- a/cogl/cogl-xlib-renderer.c
+++ b/cogl/cogl-xlib-renderer.c
@@ -33,6 +33,7 @@
 #include "cogl-internal.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,271 @@ assert_xlib_display (CoglRenderer *renderer, GError **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,
+                gboolean      notify)
+{
+  CoglXlibRenderer *xlib_renderer =
+    _cogl_xlib_renderer_get_data (renderer);
+  XRRScreenResources *resources;
+  CoglXlibTrapState state;
+  gboolean error = FALSE;
+  GList *new_outputs = NULL;
+  GList *l, *m;
+  gboolean 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 = xlib_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))
+                {
+                  xlib_renderer->outputs = g_list_remove_link (xlib_renderer->outputs, m);
+                  xlib_renderer->outputs = g_list_insert_before (xlib_renderer->outputs ,
+                                                                 m_next, output_l);
+                  cogl_object_ref (output_l);
+
+                  changed = TRUE;
+                }
+
+              l = l->next;
+              m = m_next;
+            }
+          else if (cmp < 0)
+            {
+              xlib_renderer->outputs = g_list_insert_before (xlib_renderer->outputs ,
+                                                             m, output_l);
+              cogl_object_ref (output_l);
+              changed = TRUE;
+              l = l->next;
+            }
+          else
+            {
+              GList *m_next = m->next;
+              xlib_renderer->outputs = g_list_remove_link (xlib_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 = xlib_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, GError **error)
 {
@@ -198,6 +466,7 @@ _cogl_xlib_renderer_connect (CoglRenderer *renderer, GError **error)
   CoglX11Renderer *x11_renderer =
     (CoglX11Renderer *) xlib_renderer;
   int damage_error;
+  int randr_error;
 
   if (!assert_xlib_display (renderer, error))
     return FALSE;
@@ -211,13 +480,30 @@ _cogl_xlib_renderer_connect (CoglRenderer *renderer, GError **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 +513,10 @@ _cogl_xlib_renderer_disconnect (CoglRenderer *renderer)
   CoglXlibRenderer *xlib_renderer =
     _cogl_xlib_renderer_get_data (renderer);
 
+  g_list_free_full (xlib_renderer->outputs,
+                    (GDestroyNotify)cogl_object_unref);
+  xlib_renderer->outputs = NULL;
+
   if (!renderer->foreign_xdpy && xlib_renderer->xdpy)
     XCloseDisplay (xlib_renderer->xdpy);
 
@@ -312,3 +602,40 @@ _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)
+{
+  CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
+  int max_overlap = 0;
+  CoglOutput *max_overlapped = NULL;
+  GList *l;
+  int xa1 = x, xa2 = x + width;
+  int ya1 = y, ya2 = y + height;
+
+  for (l = xlib_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 839464f..e7f83ab 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
@@ -185,29 +187,80 @@ 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
@@ -221,9 +274,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;
@@ -259,6 +310,38 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
   g_slice_free (CoglGLXRenderer, renderer->winsys);
 }
 
+static gboolean
+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,
                             GError **error)
@@ -1023,6 +1106,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);
 
   if (glx_onscreen->glxwin != None)
@@ -2126,6 +2215,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 3262d2f..1ca37e5 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, GError **error);
 
diff --git a/configure.ac b/configure.ac
index 7f55462..6dae920 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
@@ -983,7 +984,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



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]