diff options
-rw-r--r-- | cogl/Makefile.am | 3 | ||||
-rw-r--r-- | cogl/cogl-output-private.h | 50 | ||||
-rw-r--r-- | cogl/cogl-output.c | 110 | ||||
-rw-r--r-- | cogl/cogl-output.h | 242 | ||||
-rw-r--r-- | cogl/cogl-renderer-private.h | 2 | ||||
-rw-r--r-- | cogl/cogl-xlib-renderer-private.h | 10 | ||||
-rw-r--r-- | cogl/cogl-xlib-renderer.c | 334 | ||||
-rw-r--r-- | cogl/winsys/cogl-winsys-glx.c | 110 | ||||
-rw-r--r-- | cogl/winsys/cogl-winsys-private.h | 3 | ||||
-rw-r--r-- | configure.ac | 3 |
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 |