Compare commits
	
		
			39 Commits
		
	
	
		
			wip/carlos
			...
			gnome-3-14
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					049b277ca5 | ||
| 
						 | 
					9f23f466de | ||
| 
						 | 
					461f193c00 | ||
| 
						 | 
					9b1d436854 | ||
| 
						 | 
					662d50460b | ||
| 
						 | 
					47cb21b36c | ||
| 
						 | 
					8b75b41c4d | ||
| 
						 | 
					c45c39bff3 | ||
| 
						 | 
					8b80a70efc | ||
| 
						 | 
					63ad42e1f6 | ||
| 
						 | 
					6b3be51ca8 | ||
| 
						 | 
					46d57bf0ac | ||
| 
						 | 
					8dd7102909 | ||
| 
						 | 
					7a57e59fcc | ||
| 
						 | 
					6772758a64 | ||
| 
						 | 
					08ba9c689e | ||
| 
						 | 
					bdb2dac244 | ||
| 
						 | 
					dd9b1ce440 | ||
| 
						 | 
					878f0e6443 | ||
| 
						 | 
					fc1f78e8cc | ||
| 
						 | 
					25aa942a0e | ||
| 
						 | 
					56e74b1ea8 | ||
| 
						 | 
					7d3204b196 | ||
| 
						 | 
					d7ff632c67 | ||
| 
						 | 
					6d3e64226d | ||
| 
						 | 
					2e7b9e0dfe | ||
| 
						 | 
					08d81b6f7f | ||
| 
						 | 
					e01077914d | ||
| 
						 | 
					d7cf6bed63 | ||
| 
						 | 
					d071ba8446 | ||
| 
						 | 
					4d08e89c16 | ||
| 
						 | 
					21d8c4b032 | ||
| 
						 | 
					c98686da92 | ||
| 
						 | 
					a19eda5ae7 | ||
| 
						 | 
					0a9bbe0109 | ||
| 
						 | 
					a8eb42e43c | ||
| 
						 | 
					9d0c9f1f42 | ||
| 
						 | 
					9fa0743394 | ||
| 
						 | 
					bb79a20fac | 
							
								
								
									
										42
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								NEWS
									
									
									
									
									
								
							@@ -1,3 +1,45 @@
 | 
			
		||||
3.14.4
 | 
			
		||||
======
 | 
			
		||||
* Fix flash on unredirection [Chris; #743858]
 | 
			
		||||
* Fix incompatibility with GLES2 GLSL [Alban; #745442]
 | 
			
		||||
* Add function to refresh all background instances [Rui; #739178]
 | 
			
		||||
* Fix geometry of shaded windows [Florian; #746145]
 | 
			
		||||
* Misc. bug fixes [Florian, Rui; #698995, #743217, #743254]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Alban Browaeys, Rui Matos, Florian Müllner, Chris Wilson
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Matej Urbančič [sl], Muhammet Kara [tr], Samir Ribic [bs]
 | 
			
		||||
 | 
			
		||||
3.14.3
 | 
			
		||||
======
 | 
			
		||||
* Fix crash when trying to unredirect a destroyed window [Florian; #740133]
 | 
			
		||||
* Fix "flicker" during startup transition [Ray; #740377]
 | 
			
		||||
* Don't leave left-over frames queued [Owen; #738686]
 | 
			
		||||
* Set CRTC configuration even if it might be redundant [Rui; #740838]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Rui Matos, Florian Müllner, Jasper St. Pierre, Ray Strode, Owen W. Taylor
 | 
			
		||||
 | 
			
		||||
3.14.2
 | 
			
		||||
======
 | 
			
		||||
* Prevent crash applying monitor config for a closed lid [Rui; #739450]
 | 
			
		||||
* Misc. fixes [Rui, Jonathon, Jasper; #738630]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Jonathon Jongsma, Rui Matos, Jasper St. Pierre
 | 
			
		||||
 | 
			
		||||
3.14.1.5
 | 
			
		||||
========
 | 
			
		||||
* Fix wayland hiDPI regressions [Adel; #739161]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Adel Gadllah, Florian Müllner, Jasper St. Pierre
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Dušan Kazik [sk]
 | 
			
		||||
 | 
			
		||||
3.14.1
 | 
			
		||||
======
 | 
			
		||||
* Fix move-titlebar-onscreen function [Florian; #736915]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								configure.ac
									
									
									
									
									
								
							@@ -2,7 +2,7 @@ AC_PREREQ(2.62)
 | 
			
		||||
 | 
			
		||||
m4_define([mutter_major_version], [3])
 | 
			
		||||
m4_define([mutter_minor_version], [14])
 | 
			
		||||
m4_define([mutter_micro_version], [1])
 | 
			
		||||
m4_define([mutter_micro_version], [4])
 | 
			
		||||
 | 
			
		||||
m4_define([mutter_version],
 | 
			
		||||
          [mutter_major_version.mutter_minor_version.mutter_micro_version])
 | 
			
		||||
@@ -72,13 +72,12 @@ CLUTTER_PACKAGE=clutter-1.0
 | 
			
		||||
 | 
			
		||||
MUTTER_PC_MODULES="
 | 
			
		||||
   gtk+-3.0 >= 3.9.11
 | 
			
		||||
   gio-unix-2.0 >= 2.25.10
 | 
			
		||||
   gio-unix-2.0 >= 2.35.1
 | 
			
		||||
   pango >= 1.2.0
 | 
			
		||||
   cairo >= 1.10.0
 | 
			
		||||
   gsettings-desktop-schemas >= 3.7.3
 | 
			
		||||
   $CLUTTER_PACKAGE >= 1.19.5
 | 
			
		||||
   cogl-1.0 >= 1.17.1
 | 
			
		||||
   gbm >= 10.3
 | 
			
		||||
   upower-glib >= 0.99.0
 | 
			
		||||
   gnome-desktop-3.0
 | 
			
		||||
   xcomposite >= 0.2
 | 
			
		||||
@@ -91,6 +90,7 @@ MUTTER_PC_MODULES="
 | 
			
		||||
   xkeyboard-config
 | 
			
		||||
   xkbcommon >= 0.4.3
 | 
			
		||||
   xkbcommon-x11
 | 
			
		||||
   xrender
 | 
			
		||||
   x11-xcb
 | 
			
		||||
   xcb-randr
 | 
			
		||||
"
 | 
			
		||||
@@ -201,7 +201,7 @@ AC_SUBST(XWAYLAND_PATH)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [clutter-egl-1.0 libdrm libsystemd libinput], [have_native_backend=yes], [have_native_backend=no])
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [clutter-egl-1.0 libdrm libsystemd libinput gbm >= 10.3], [have_native_backend=yes], [have_native_backend=no])
 | 
			
		||||
if test $have_native_backend = yes; then
 | 
			
		||||
   AC_DEFINE([HAVE_NATIVE_BACKEND],[1],[Define if you want to enable the native (KMS) backend based on systemd])
 | 
			
		||||
fi
 | 
			
		||||
@@ -315,6 +315,11 @@ fi
 | 
			
		||||
 | 
			
		||||
GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
 | 
			
		||||
 | 
			
		||||
AC_CHECK_DECL([GL_EXT_x11_sync_object],
 | 
			
		||||
              [],
 | 
			
		||||
              [AC_MSG_ERROR([GL_EXT_x11_sync_object definition not found, please update your GL headers])],
 | 
			
		||||
              [#include <GL/glx.h>])
 | 
			
		||||
 | 
			
		||||
#### Warnings (last since -Werror can disturb other tests)
 | 
			
		||||
 | 
			
		||||
# Stay command-line compatible with the gnome-common configure option. Here
 | 
			
		||||
 
 | 
			
		||||
@@ -126,6 +126,8 @@ libmutter_la_SOURCES =				\
 | 
			
		||||
	compositor/meta-surface-actor.h		\
 | 
			
		||||
	compositor/meta-surface-actor-x11.c	\
 | 
			
		||||
	compositor/meta-surface-actor-x11.h	\
 | 
			
		||||
	compositor/meta-sync-ring.c		\
 | 
			
		||||
	compositor/meta-sync-ring.h		\
 | 
			
		||||
	compositor/meta-texture-rectangle.c	\
 | 
			
		||||
	compositor/meta-texture-rectangle.h	\
 | 
			
		||||
	compositor/meta-texture-tower.c		\
 | 
			
		||||
 
 | 
			
		||||
@@ -29,8 +29,11 @@
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  CoglTexture2D *texture;
 | 
			
		||||
  struct gbm_bo *bo;
 | 
			
		||||
  int hot_x, hot_y;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  struct gbm_bo *bo;
 | 
			
		||||
#endif
 | 
			
		||||
} MetaCursorImage;
 | 
			
		||||
 | 
			
		||||
struct _MetaCursorReference {
 | 
			
		||||
@@ -44,8 +47,10 @@ CoglTexture *meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor
 | 
			
		||||
                                                     int                 *hot_x,
 | 
			
		||||
                                                     int                 *hot_y);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
 | 
			
		||||
                                                 int                 *hot_x,
 | 
			
		||||
                                                 int                 *hot_y);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* META_CURSOR_PRIVATE_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -56,8 +56,11 @@ static void
 | 
			
		||||
meta_cursor_image_free (MetaCursorImage *image)
 | 
			
		||||
{
 | 
			
		||||
  cogl_object_unref (image->texture);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  if (image->bo)
 | 
			
		||||
    gbm_bo_destroy (image->bo);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -139,10 +142,10 @@ load_cursor_on_client (MetaCursor cursor)
 | 
			
		||||
                                  meta_prefs_get_cursor_size ());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
static void
 | 
			
		||||
get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  MetaBackend *meta_backend = meta_get_backend ();
 | 
			
		||||
  MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
 | 
			
		||||
 | 
			
		||||
@@ -151,11 +154,12 @@ get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
 | 
			
		||||
      meta_cursor_renderer_native_get_cursor_size (META_CURSOR_RENDERER_NATIVE (renderer), cursor_width, cursor_height);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  g_assert_not_reached ();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
static void
 | 
			
		||||
meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
 | 
			
		||||
                                   MetaCursorImage   *image,
 | 
			
		||||
@@ -193,20 +197,21 @@ meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
 | 
			
		||||
  else
 | 
			
		||||
    meta_warning ("HW cursor for format %d not supported\n", gbm_format);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
static struct gbm_device *
 | 
			
		||||
get_gbm_device (void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  MetaBackend *meta_backend = meta_get_backend ();
 | 
			
		||||
  MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
 | 
			
		||||
 | 
			
		||||
  if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
 | 
			
		||||
    return meta_cursor_renderer_native_get_gbm_device (META_CURSOR_RENDERER_NATIVE (renderer));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
  else
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_cursor_image_load_from_xcursor_image (MetaCursorImage   *image,
 | 
			
		||||
@@ -214,16 +219,13 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage   *image,
 | 
			
		||||
{
 | 
			
		||||
  uint width, height, rowstride;
 | 
			
		||||
  CoglPixelFormat cogl_format;
 | 
			
		||||
  uint32_t gbm_format;
 | 
			
		||||
  ClutterBackend *clutter_backend;
 | 
			
		||||
  CoglContext *cogl_context;
 | 
			
		||||
  struct gbm_device *gbm;
 | 
			
		||||
 | 
			
		||||
  width           = xc_image->width;
 | 
			
		||||
  height          = xc_image->height;
 | 
			
		||||
  rowstride       = width * 4;
 | 
			
		||||
 | 
			
		||||
  gbm_format = GBM_FORMAT_ARGB8888;
 | 
			
		||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
 | 
			
		||||
  cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
 | 
			
		||||
#else
 | 
			
		||||
@@ -242,13 +244,15 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage   *image,
 | 
			
		||||
                                                  (uint8_t *) xc_image->pixels,
 | 
			
		||||
                                                  NULL);
 | 
			
		||||
 | 
			
		||||
  gbm = get_gbm_device ();
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  struct gbm_device *gbm = get_gbm_device ();
 | 
			
		||||
  if (gbm)
 | 
			
		||||
    meta_cursor_image_load_gbm_buffer (gbm,
 | 
			
		||||
                                       image,
 | 
			
		||||
                                       (uint8_t *) xc_image->pixels,
 | 
			
		||||
                                       width, height, rowstride,
 | 
			
		||||
                                       gbm_format);
 | 
			
		||||
                                       GBM_FORMAT_ARGB8888);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaCursorReference *
 | 
			
		||||
@@ -277,14 +281,8 @@ meta_cursor_image_load_from_buffer (MetaCursorImage    *image,
 | 
			
		||||
                                    int                 hot_x,
 | 
			
		||||
                                    int                 hot_y)
 | 
			
		||||
{
 | 
			
		||||
  struct gbm_device *gbm = get_gbm_device ();
 | 
			
		||||
 | 
			
		||||
  ClutterBackend *backend;
 | 
			
		||||
  CoglContext *cogl_context;
 | 
			
		||||
  struct wl_shm_buffer *shm_buffer;
 | 
			
		||||
  uint32_t gbm_format;
 | 
			
		||||
  uint64_t cursor_width, cursor_height;
 | 
			
		||||
  uint width, height;
 | 
			
		||||
 | 
			
		||||
  image->hot_x = hot_x;
 | 
			
		||||
  image->hot_y = hot_y;
 | 
			
		||||
@@ -294,13 +292,19 @@ meta_cursor_image_load_from_buffer (MetaCursorImage    *image,
 | 
			
		||||
 | 
			
		||||
  image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
 | 
			
		||||
 | 
			
		||||
  width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
 | 
			
		||||
  height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
 | 
			
		||||
 | 
			
		||||
  shm_buffer = wl_shm_buffer_get (buffer);
 | 
			
		||||
  if (shm_buffer)
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  struct gbm_device *gbm = get_gbm_device ();
 | 
			
		||||
  if (gbm)
 | 
			
		||||
    {
 | 
			
		||||
      if (gbm)
 | 
			
		||||
      uint32_t gbm_format;
 | 
			
		||||
      uint64_t cursor_width, cursor_height;
 | 
			
		||||
      uint width, height;
 | 
			
		||||
 | 
			
		||||
      width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
 | 
			
		||||
      height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
 | 
			
		||||
 | 
			
		||||
      struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
 | 
			
		||||
      if (shm_buffer)
 | 
			
		||||
        {
 | 
			
		||||
          int rowstride = wl_shm_buffer_get_stride (shm_buffer);
 | 
			
		||||
 | 
			
		||||
@@ -332,10 +336,7 @@ meta_cursor_image_load_from_buffer (MetaCursorImage    *image,
 | 
			
		||||
                                             width, height, rowstride,
 | 
			
		||||
                                             gbm_format);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (gbm)
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          /* HW cursors have a predefined size (at least 64x64), which usually is bigger than cursor theme
 | 
			
		||||
             size, so themed cursors must be padded with transparent pixels to fill the
 | 
			
		||||
@@ -356,6 +357,7 @@ meta_cursor_image_load_from_buffer (MetaCursorImage    *image,
 | 
			
		||||
            meta_warning ("Importing HW cursor from wl_buffer failed\n");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaCursorReference *
 | 
			
		||||
@@ -385,6 +387,7 @@ meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
 | 
			
		||||
  return COGL_TEXTURE (cursor->image.texture);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
struct gbm_bo *
 | 
			
		||||
meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
 | 
			
		||||
                                  int                 *hot_x,
 | 
			
		||||
@@ -396,6 +399,7 @@ meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
 | 
			
		||||
    *hot_y = cursor->image.hot_y;
 | 
			
		||||
  return cursor->image.bo;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
MetaCursor
 | 
			
		||||
meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor)
 | 
			
		||||
 
 | 
			
		||||
@@ -796,27 +796,6 @@ make_config_key (MetaConfiguration *key,
 | 
			
		||||
  key->n_outputs = o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_monitor_config_match_current (MetaMonitorConfig  *self,
 | 
			
		||||
                                   MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutput *outputs;
 | 
			
		||||
  unsigned n_outputs;
 | 
			
		||||
  MetaConfiguration key;
 | 
			
		||||
  gboolean ok;
 | 
			
		||||
 | 
			
		||||
  if (self->current == NULL)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
 | 
			
		||||
 | 
			
		||||
  make_config_key (&key, outputs, n_outputs, -1);
 | 
			
		||||
  ok = config_equal (&key, self->current);
 | 
			
		||||
 | 
			
		||||
  config_clear (&key);
 | 
			
		||||
  return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
@@ -945,6 +924,19 @@ laptop_display_is_on (MetaConfiguration *config)
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
multiple_outputs_are_enabled (MetaConfiguration *config)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int i, enabled;
 | 
			
		||||
 | 
			
		||||
  enabled = 0;
 | 
			
		||||
  for (i = 0; i < config->n_outputs; i++)
 | 
			
		||||
    if (config->outputs[i].enabled)
 | 
			
		||||
      enabled++;
 | 
			
		||||
 | 
			
		||||
  return enabled > 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaConfiguration *
 | 
			
		||||
make_laptop_lid_config (MetaConfiguration  *reference)
 | 
			
		||||
{
 | 
			
		||||
@@ -954,7 +946,7 @@ make_laptop_lid_config (MetaConfiguration  *reference)
 | 
			
		||||
  int x_after, y_after;
 | 
			
		||||
  int x_offset, y_offset;
 | 
			
		||||
 | 
			
		||||
  g_assert (reference->n_outputs > 1);
 | 
			
		||||
  g_assert (multiple_outputs_are_enabled (reference));
 | 
			
		||||
 | 
			
		||||
  new = g_slice_new0 (MetaConfiguration);
 | 
			
		||||
  new->n_outputs = reference->n_outputs;
 | 
			
		||||
@@ -1025,7 +1017,7 @@ meta_monitor_config_apply_stored (MetaMonitorConfig  *self,
 | 
			
		||||
  if (stored)
 | 
			
		||||
    {
 | 
			
		||||
      if (self->lid_is_closed &&
 | 
			
		||||
          stored->n_outputs > 1 &&
 | 
			
		||||
          multiple_outputs_are_enabled (stored) &&
 | 
			
		||||
          laptop_display_is_on (stored))
 | 
			
		||||
        {
 | 
			
		||||
          if (apply_configuration (self, make_laptop_lid_config (stored),
 | 
			
		||||
@@ -1287,7 +1279,7 @@ meta_monitor_config_make_default (MetaMonitorConfig  *self,
 | 
			
		||||
  if (default_config != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      if (self->lid_is_closed &&
 | 
			
		||||
          default_config->n_outputs > 1 &&
 | 
			
		||||
          multiple_outputs_are_enabled (default_config) &&
 | 
			
		||||
          laptop_display_is_on (default_config))
 | 
			
		||||
        {
 | 
			
		||||
          ok = apply_configuration (self, make_laptop_lid_config (default_config),
 | 
			
		||||
@@ -1378,7 +1370,7 @@ turn_off_laptop_display (MetaMonitorConfig  *self,
 | 
			
		||||
{
 | 
			
		||||
  MetaConfiguration *new;
 | 
			
		||||
 | 
			
		||||
  if (self->current->n_outputs == 1)
 | 
			
		||||
  if (!multiple_outputs_are_enabled (self->current))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  new = make_laptop_lid_config (self->current);
 | 
			
		||||
 
 | 
			
		||||
@@ -36,9 +36,6 @@ GType meta_monitor_config_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
MetaMonitorConfig *meta_monitor_config_new (void);
 | 
			
		||||
 | 
			
		||||
gboolean           meta_monitor_config_match_current (MetaMonitorConfig  *config,
 | 
			
		||||
                                                      MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
gboolean           meta_monitor_config_apply_stored (MetaMonitorConfig  *config,
 | 
			
		||||
                                                     MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -130,8 +130,8 @@ take_device (Login1Session *session_proxy,
 | 
			
		||||
{
 | 
			
		||||
  gboolean ret = FALSE;
 | 
			
		||||
  GVariant *fd_variant = NULL;
 | 
			
		||||
  GUnixFDList *fd_list = NULL;
 | 
			
		||||
  int fd = -1;
 | 
			
		||||
  GUnixFDList *fd_list;
 | 
			
		||||
 | 
			
		||||
  if (!login1_session_call_take_device_sync (session_proxy,
 | 
			
		||||
                                             dev_major,
 | 
			
		||||
 
 | 
			
		||||
@@ -140,6 +140,30 @@ meta_monitor_transform_from_xrandr_all (Rotation rotation)
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
output_get_property_exists (MetaMonitorManagerXrandr *manager_xrandr,
 | 
			
		||||
                            MetaOutput *output, const char *propname)
 | 
			
		||||
{
 | 
			
		||||
  gboolean exists = FALSE;
 | 
			
		||||
  Atom atom, actual_type;
 | 
			
		||||
  int actual_format;
 | 
			
		||||
  unsigned long nitems, bytes_after;
 | 
			
		||||
  unsigned char *buffer;
 | 
			
		||||
 | 
			
		||||
  atom = XInternAtom (manager_xrandr->xdisplay, propname, False);
 | 
			
		||||
  XRRGetOutputProperty (manager_xrandr->xdisplay,
 | 
			
		||||
                        (XID)output->winsys_id,
 | 
			
		||||
                        atom,
 | 
			
		||||
                        0, G_MAXLONG, False, False, AnyPropertyType,
 | 
			
		||||
                        &actual_type, &actual_format,
 | 
			
		||||
                        &nitems, &bytes_after, &buffer);
 | 
			
		||||
 | 
			
		||||
  exists = (actual_type != None);
 | 
			
		||||
 | 
			
		||||
  XFree (buffer);
 | 
			
		||||
  return exists;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
 | 
			
		||||
                             MetaOutput *output, const char *propname)
 | 
			
		||||
@@ -330,7 +354,7 @@ static gboolean
 | 
			
		||||
output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
 | 
			
		||||
                                MetaOutput               *output)
 | 
			
		||||
{
 | 
			
		||||
  return output_get_boolean_property (manager_xrandr, output, "hotplug_mode_update");
 | 
			
		||||
  return output_get_property_exists (manager_xrandr, output, "hotplug_mode_update");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
@@ -814,26 +838,12 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
 | 
			
		||||
          unsigned int j, n_outputs;
 | 
			
		||||
          int width, height;
 | 
			
		||||
          Status ok;
 | 
			
		||||
          unsigned long old_controlled_mask;
 | 
			
		||||
          unsigned long new_controlled_mask;
 | 
			
		||||
 | 
			
		||||
          mode = crtc_info->mode;
 | 
			
		||||
 | 
			
		||||
          n_outputs = crtc_info->outputs->len;
 | 
			
		||||
          outputs = g_new (XID, n_outputs);
 | 
			
		||||
 | 
			
		||||
          old_controlled_mask = 0;
 | 
			
		||||
          for (j = 0; j < manager->n_outputs; j++)
 | 
			
		||||
            {
 | 
			
		||||
              MetaOutput *output;
 | 
			
		||||
 | 
			
		||||
              output = &manager->outputs[j];
 | 
			
		||||
 | 
			
		||||
              if (output->crtc == crtc)
 | 
			
		||||
                old_controlled_mask |= 1UL << j;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          new_controlled_mask = 0;
 | 
			
		||||
          for (j = 0; j < n_outputs; j++)
 | 
			
		||||
            {
 | 
			
		||||
              MetaOutput *output;
 | 
			
		||||
@@ -842,21 +852,10 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
 | 
			
		||||
 | 
			
		||||
              output->is_dirty = TRUE;
 | 
			
		||||
              output->crtc = crtc;
 | 
			
		||||
              new_controlled_mask |= 1UL << j;
 | 
			
		||||
 | 
			
		||||
              outputs[j] = output->winsys_id;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          if (crtc->current_mode == mode &&
 | 
			
		||||
              crtc->rect.x == crtc_info->x &&
 | 
			
		||||
              crtc->rect.y == crtc_info->y &&
 | 
			
		||||
              crtc->transform == crtc_info->transform &&
 | 
			
		||||
              old_controlled_mask == new_controlled_mask)
 | 
			
		||||
            {
 | 
			
		||||
              /* No change */
 | 
			
		||||
              goto next;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
 | 
			
		||||
                                 manager_xrandr->resources,
 | 
			
		||||
                                 (XID)crtc->crtc_id,
 | 
			
		||||
@@ -1097,7 +1096,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
 | 
			
		||||
  /* If this is the X server telling us we set a new configuration,
 | 
			
		||||
   * we can simply short-cut to rebuilding our logical configuration.
 | 
			
		||||
   */
 | 
			
		||||
  if (new_config || meta_monitor_config_match_current (manager->config, manager))
 | 
			
		||||
  if (new_config)
 | 
			
		||||
    {
 | 
			
		||||
      meta_monitor_manager_xrandr_rebuild_derived (manager);
 | 
			
		||||
      goto out;
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,8 @@ struct _MetaCompositor
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay    *display;
 | 
			
		||||
 | 
			
		||||
  guint           repaint_func_id;
 | 
			
		||||
  guint           pre_paint_func_id;
 | 
			
		||||
  guint           post_paint_func_id;
 | 
			
		||||
 | 
			
		||||
  gint64          server_time_query_time;
 | 
			
		||||
  gint64          server_time_offset;
 | 
			
		||||
@@ -40,6 +41,7 @@ struct _MetaCompositor
 | 
			
		||||
  MetaPluginManager *plugin_mgr;
 | 
			
		||||
 | 
			
		||||
  gboolean frame_has_updated_xsurfaces;
 | 
			
		||||
  gboolean have_x11_sync_object;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Wait 2ms after vblank before starting to draw next frame */
 | 
			
		||||
 
 | 
			
		||||
@@ -79,6 +79,7 @@
 | 
			
		||||
#include "frame.h"
 | 
			
		||||
#include <X11/extensions/shape.h>
 | 
			
		||||
#include <X11/extensions/Xcomposite.h>
 | 
			
		||||
#include "meta-sync-ring.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/x11/meta-backend-x11.h"
 | 
			
		||||
 | 
			
		||||
@@ -125,7 +126,11 @@ meta_switch_workspace_completed (MetaCompositor *compositor)
 | 
			
		||||
void
 | 
			
		||||
meta_compositor_destroy (MetaCompositor *compositor)
 | 
			
		||||
{
 | 
			
		||||
  clutter_threads_remove_repaint_func (compositor->repaint_func_id);
 | 
			
		||||
  clutter_threads_remove_repaint_func (compositor->pre_paint_func_id);
 | 
			
		||||
  clutter_threads_remove_repaint_func (compositor->post_paint_func_id);
 | 
			
		||||
 | 
			
		||||
  if (compositor->have_x11_sync_object)
 | 
			
		||||
    meta_sync_ring_destroy ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -468,13 +473,11 @@ meta_compositor_manage (MetaCompositor *compositor)
 | 
			
		||||
  MetaDisplay *display = compositor->display;
 | 
			
		||||
  Display *xdisplay = display->xdisplay;
 | 
			
		||||
  MetaScreen *screen = display->screen;
 | 
			
		||||
  MetaBackend *backend = meta_get_backend ();
 | 
			
		||||
 | 
			
		||||
  meta_screen_set_cm_selection (display->screen);
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    MetaBackend *backend = meta_get_backend ();
 | 
			
		||||
    compositor->stage = meta_backend_get_stage (backend);
 | 
			
		||||
  }
 | 
			
		||||
  compositor->stage = meta_backend_get_stage (backend);
 | 
			
		||||
 | 
			
		||||
  /* We use connect_after() here to accomodate code in GNOME Shell that,
 | 
			
		||||
   * when benchmarking drawing performance, connects to ::after-paint
 | 
			
		||||
@@ -510,7 +513,7 @@ meta_compositor_manage (MetaCompositor *compositor)
 | 
			
		||||
 | 
			
		||||
      compositor->output = screen->composite_overlay_window;
 | 
			
		||||
 | 
			
		||||
      xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (meta_get_backend ()));
 | 
			
		||||
      xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
 | 
			
		||||
 | 
			
		||||
      XReparentWindow (xdisplay, xwin, compositor->output, 0, 0);
 | 
			
		||||
 | 
			
		||||
@@ -530,6 +533,8 @@ meta_compositor_manage (MetaCompositor *compositor)
 | 
			
		||||
       * contents until we show the stage.
 | 
			
		||||
       */
 | 
			
		||||
      XMapWindow (xdisplay, compositor->output);
 | 
			
		||||
 | 
			
		||||
      compositor->have_x11_sync_object = meta_sync_ring_init (xdisplay);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  redirect_windows (display->screen);
 | 
			
		||||
@@ -614,6 +619,7 @@ set_unredirected_window (MetaCompositor *compositor,
 | 
			
		||||
      meta_window_actor_set_unredirected (window_actor, FALSE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_shape_cow_for_window (compositor, window);
 | 
			
		||||
  compositor->unredirected_window = window;
 | 
			
		||||
 | 
			
		||||
  if (compositor->unredirected_window != NULL)
 | 
			
		||||
@@ -621,8 +627,6 @@ set_unredirected_window (MetaCompositor *compositor,
 | 
			
		||||
      MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window));
 | 
			
		||||
      meta_window_actor_set_unredirected (window_actor, TRUE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_shape_cow_for_window (compositor, compositor->unredirected_window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -732,6 +736,9 @@ meta_compositor_process_event (MetaCompositor *compositor,
 | 
			
		||||
        process_damage (compositor, (XDamageNotifyEvent *) event, window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (compositor->have_x11_sync_object)
 | 
			
		||||
    meta_sync_ring_handle_event (event);
 | 
			
		||||
 | 
			
		||||
  /* Clutter needs to know about MapNotify events otherwise it will
 | 
			
		||||
     think the stage is invisible */
 | 
			
		||||
  if (!meta_is_wayland_compositor () && event->type == MapNotify)
 | 
			
		||||
@@ -1045,11 +1052,12 @@ frame_callback (CoglOnscreen  *onscreen,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pre_paint_windows (MetaCompositor *compositor)
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_pre_paint_func (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  GList *l;
 | 
			
		||||
  MetaWindowActor *top_window;
 | 
			
		||||
  MetaCompositor *compositor = data;
 | 
			
		||||
 | 
			
		||||
  if (compositor->onscreen == NULL)
 | 
			
		||||
    {
 | 
			
		||||
@@ -1061,7 +1069,7 @@ pre_paint_windows (MetaCompositor *compositor)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (compositor->windows == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
    return TRUE;
 | 
			
		||||
 | 
			
		||||
  top_window = g_list_last (compositor->windows)->data;
 | 
			
		||||
 | 
			
		||||
@@ -1078,10 +1086,12 @@ pre_paint_windows (MetaCompositor *compositor)
 | 
			
		||||
    {
 | 
			
		||||
      /* We need to make sure that any X drawing that happens before
 | 
			
		||||
       * the XDamageSubtract() for each window above is visible to
 | 
			
		||||
       * subsequent GL rendering; the only standardized way to do this
 | 
			
		||||
       * is EXT_x11_sync_object, which isn't yet widely available. For
 | 
			
		||||
       * now, we count on details of Xorg and the open source drivers,
 | 
			
		||||
       * and hope for the best otherwise.
 | 
			
		||||
       * subsequent GL rendering; the standardized way to do this is
 | 
			
		||||
       * GL_EXT_X11_sync_object. Since this isn't implemented yet in
 | 
			
		||||
       * mesa, we also have a path that relies on the implementation
 | 
			
		||||
       * of the open source drivers.
 | 
			
		||||
       *
 | 
			
		||||
       * Anything else, we just hope for the best.
 | 
			
		||||
       *
 | 
			
		||||
       * Xorg and open source driver specifics:
 | 
			
		||||
       *
 | 
			
		||||
@@ -1096,17 +1106,28 @@ pre_paint_windows (MetaCompositor *compositor)
 | 
			
		||||
       * round trip request at this point is sufficient to flush the
 | 
			
		||||
       * GLX buffers.
 | 
			
		||||
       */
 | 
			
		||||
      XSync (compositor->display->xdisplay, False);
 | 
			
		||||
 | 
			
		||||
      compositor->frame_has_updated_xsurfaces = FALSE;
 | 
			
		||||
      if (compositor->have_x11_sync_object)
 | 
			
		||||
        compositor->have_x11_sync_object = meta_sync_ring_insert_wait ();
 | 
			
		||||
      else
 | 
			
		||||
        XSync (compositor->display->xdisplay, False);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_repaint_func (gpointer data)
 | 
			
		||||
meta_post_paint_func (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  MetaCompositor *compositor = data;
 | 
			
		||||
  pre_paint_windows (compositor);
 | 
			
		||||
 | 
			
		||||
  if (compositor->frame_has_updated_xsurfaces)
 | 
			
		||||
    {
 | 
			
		||||
      if (compositor->have_x11_sync_object)
 | 
			
		||||
        compositor->have_x11_sync_object = meta_sync_ring_after_frame ();
 | 
			
		||||
 | 
			
		||||
      compositor->frame_has_updated_xsurfaces = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1141,10 +1162,16 @@ meta_compositor_new (MetaDisplay *display)
 | 
			
		||||
                    G_CALLBACK (on_shadow_factory_changed),
 | 
			
		||||
                    compositor);
 | 
			
		||||
 | 
			
		||||
  compositor->repaint_func_id = clutter_threads_add_repaint_func (meta_repaint_func,
 | 
			
		||||
                                                                  compositor,
 | 
			
		||||
                                                                  NULL);
 | 
			
		||||
 | 
			
		||||
  compositor->pre_paint_func_id =
 | 
			
		||||
    clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT,
 | 
			
		||||
                                           meta_pre_paint_func,
 | 
			
		||||
                                           compositor,
 | 
			
		||||
                                           NULL);
 | 
			
		||||
  compositor->post_paint_func_id =
 | 
			
		||||
    clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
 | 
			
		||||
                                           meta_post_paint_func,
 | 
			
		||||
                                           compositor,
 | 
			
		||||
                                           NULL);
 | 
			
		||||
  return compositor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -115,7 +115,7 @@ typedef enum {
 | 
			
		||||
#define FRAGMENT_SHADER_CODE                                                   \
 | 
			
		||||
"float t = 2.0 * length(position);\n"                                          \
 | 
			
		||||
"t = min(t, 1.0);\n"                                                           \
 | 
			
		||||
"float pixel_brightness = 1 - t * vignette_sharpness;\n"                       \
 | 
			
		||||
"float pixel_brightness = 1.0 - t * vignette_sharpness;\n"                       \
 | 
			
		||||
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n"                \
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaBackgroundLayer MetaBackgroundLayer;
 | 
			
		||||
 
 | 
			
		||||
@@ -71,6 +71,8 @@ enum
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaBackground, meta_background, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
static GSList *all_backgrounds = NULL;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
free_fbos (MetaBackground *self)
 | 
			
		||||
{
 | 
			
		||||
@@ -291,6 +293,8 @@ meta_background_dispose (GObject *object)
 | 
			
		||||
static void
 | 
			
		||||
meta_background_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  all_backgrounds = g_slist_remove (all_backgrounds, object);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_background_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -333,6 +337,7 @@ meta_background_init (MetaBackground *self)
 | 
			
		||||
  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
 | 
			
		||||
                                            META_TYPE_BACKGROUND,
 | 
			
		||||
                                            MetaBackgroundPrivate);
 | 
			
		||||
  all_backgrounds = g_slist_prepend (all_backgrounds, self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -899,3 +904,12 @@ meta_background_set_blend (MetaBackground          *self,
 | 
			
		||||
  free_wallpaper_texture (self);
 | 
			
		||||
  mark_changed (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_background_refresh_all (void)
 | 
			
		||||
{
 | 
			
		||||
  GSList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = all_backgrounds; l; l = l->next)
 | 
			
		||||
    mark_changed (l->data);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										592
									
								
								src/compositor/meta-sync-ring.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										592
									
								
								src/compositor/meta-sync-ring.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,592 @@
 | 
			
		||||
/*
 | 
			
		||||
 * This is based on an original C++ implementation for compiz that
 | 
			
		||||
 * carries the following copyright notice:
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright © 2011 NVIDIA Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software
 | 
			
		||||
 * and its documentation for any purpose is hereby granted without
 | 
			
		||||
 * fee, provided that the above copyright notice appear in all copies
 | 
			
		||||
 * and that both that copyright notice and this permission notice
 | 
			
		||||
 * appear in supporting documentation, and that the name of NVIDIA
 | 
			
		||||
 * Corporation not be used in advertising or publicity pertaining to
 | 
			
		||||
 * distribution of the software without specific, written prior
 | 
			
		||||
 * permission.  NVIDIA Corporation makes no representations about the
 | 
			
		||||
 * suitability of this software for any purpose. It is provided "as
 | 
			
		||||
 * is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * NVIDIA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 | 
			
		||||
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
 * FITNESS, IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
 | 
			
		||||
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 | 
			
		||||
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 *
 | 
			
		||||
 * Authors: James Jones <jajones@nvidia.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <GL/gl.h>
 | 
			
		||||
#include <GL/glx.h>
 | 
			
		||||
#include <X11/extensions/sync.h>
 | 
			
		||||
 | 
			
		||||
#include <cogl/cogl.h>
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
 | 
			
		||||
#include <meta/util.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-sync-ring.h"
 | 
			
		||||
 | 
			
		||||
/* Theory of operation:
 | 
			
		||||
 *
 | 
			
		||||
 * We use a ring of NUM_SYNCS fence objects. On each frame we advance
 | 
			
		||||
 * to the next fence in the ring. For each fence we do:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. fence is XSyncTriggerFence()'d and glWaitSync()'d
 | 
			
		||||
 * 2. NUM_SYNCS / 2 frames later, fence should be triggered
 | 
			
		||||
 * 3. fence is XSyncResetFence()'d
 | 
			
		||||
 * 4. NUM_SYNCS / 2 frames later, fence should be reset
 | 
			
		||||
 * 5. go back to 1 and re-use fence
 | 
			
		||||
 *
 | 
			
		||||
 * glClientWaitSync() and XAlarms are used in steps 2 and 4,
 | 
			
		||||
 * respectively, to double-check the expectections.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define NUM_SYNCS 10
 | 
			
		||||
#define MAX_SYNC_WAIT_TIME (1 * 1000 * 1000 * 1000) /* one sec */
 | 
			
		||||
#define MAX_REBOOT_ATTEMPTS 2
 | 
			
		||||
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  META_SYNC_STATE_READY,
 | 
			
		||||
  META_SYNC_STATE_WAITING,
 | 
			
		||||
  META_SYNC_STATE_DONE,
 | 
			
		||||
  META_SYNC_STATE_RESET_PENDING,
 | 
			
		||||
} MetaSyncState;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  Display *xdisplay;
 | 
			
		||||
 | 
			
		||||
  XSyncFence xfence;
 | 
			
		||||
  GLsync gl_x11_sync;
 | 
			
		||||
  GLsync gpu_fence;
 | 
			
		||||
 | 
			
		||||
  XSyncCounter xcounter;
 | 
			
		||||
  XSyncAlarm xalarm;
 | 
			
		||||
  XSyncValue next_counter_value;
 | 
			
		||||
 | 
			
		||||
  MetaSyncState state;
 | 
			
		||||
} MetaSync;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  Display *xdisplay;
 | 
			
		||||
  int xsync_event_base;
 | 
			
		||||
  int xsync_error_base;
 | 
			
		||||
 | 
			
		||||
  GHashTable *alarm_to_sync;
 | 
			
		||||
 | 
			
		||||
  MetaSync *syncs_array[NUM_SYNCS];
 | 
			
		||||
  guint current_sync_idx;
 | 
			
		||||
  MetaSync *current_sync;
 | 
			
		||||
  guint warmup_syncs;
 | 
			
		||||
 | 
			
		||||
  guint reboots;
 | 
			
		||||
} MetaSyncRing;
 | 
			
		||||
 | 
			
		||||
static MetaSyncRing meta_sync_ring = { 0 };
 | 
			
		||||
 | 
			
		||||
static XSyncValue SYNC_VALUE_ZERO;
 | 
			
		||||
static XSyncValue SYNC_VALUE_ONE;
 | 
			
		||||
 | 
			
		||||
static const char*      (*meta_gl_get_string) (GLenum name);
 | 
			
		||||
static void             (*meta_gl_get_integerv) (GLenum  pname,
 | 
			
		||||
                                                 GLint  *params);
 | 
			
		||||
static const char*      (*meta_gl_get_stringi) (GLenum name,
 | 
			
		||||
                                                GLuint index);
 | 
			
		||||
static void             (*meta_gl_delete_sync) (GLsync sync);
 | 
			
		||||
static GLenum           (*meta_gl_client_wait_sync) (GLsync sync,
 | 
			
		||||
                                                     GLbitfield flags,
 | 
			
		||||
                                                     GLuint64 timeout);
 | 
			
		||||
static void             (*meta_gl_wait_sync) (GLsync sync,
 | 
			
		||||
                                              GLbitfield flags,
 | 
			
		||||
                                              GLuint64 timeout);
 | 
			
		||||
static GLsync           (*meta_gl_import_sync) (GLenum external_sync_type,
 | 
			
		||||
                                                GLintptr external_sync,
 | 
			
		||||
                                                GLbitfield flags);
 | 
			
		||||
static GLsync           (*meta_gl_fence_sync) (GLenum condition,
 | 
			
		||||
                                               GLbitfield flags);
 | 
			
		||||
 | 
			
		||||
static MetaSyncRing *
 | 
			
		||||
meta_sync_ring_get (void)
 | 
			
		||||
{
 | 
			
		||||
  if (meta_sync_ring.reboots > MAX_REBOOT_ATTEMPTS)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  return &meta_sync_ring;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
load_gl_symbol (const char  *name,
 | 
			
		||||
                void       **func)
 | 
			
		||||
{
 | 
			
		||||
  *func = cogl_get_proc_address (name);
 | 
			
		||||
  if (!*func)
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("MetaSyncRing: failed to resolve required GL symbol \"%s\"\n", name);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
check_gl_extensions (void)
 | 
			
		||||
{
 | 
			
		||||
  ClutterBackend *backend;
 | 
			
		||||
  CoglContext *cogl_context;
 | 
			
		||||
  CoglDisplay *cogl_display;
 | 
			
		||||
  CoglRenderer *cogl_renderer;
 | 
			
		||||
 | 
			
		||||
  backend = clutter_get_default_backend ();
 | 
			
		||||
  cogl_context = clutter_backend_get_cogl_context (backend);
 | 
			
		||||
  cogl_display = cogl_context_get_display (cogl_context);
 | 
			
		||||
  cogl_renderer = cogl_display_get_renderer (cogl_display);
 | 
			
		||||
 | 
			
		||||
  switch (cogl_renderer_get_driver (cogl_renderer))
 | 
			
		||||
    {
 | 
			
		||||
    case COGL_DRIVER_GL3:
 | 
			
		||||
      {
 | 
			
		||||
        int num_extensions, i;
 | 
			
		||||
        gboolean arb_sync = FALSE;
 | 
			
		||||
        gboolean x11_sync_object = FALSE;
 | 
			
		||||
 | 
			
		||||
        meta_gl_get_integerv (GL_NUM_EXTENSIONS, &num_extensions);
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < num_extensions; ++i)
 | 
			
		||||
          {
 | 
			
		||||
            const char *ext = meta_gl_get_stringi (GL_EXTENSIONS, i);
 | 
			
		||||
 | 
			
		||||
            if (g_strcmp0 ("GL_ARB_sync", ext) == 0)
 | 
			
		||||
              arb_sync = TRUE;
 | 
			
		||||
            else if (g_strcmp0 ("GL_EXT_x11_sync_object", ext) == 0)
 | 
			
		||||
              x11_sync_object = TRUE;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
        return arb_sync && x11_sync_object;
 | 
			
		||||
      }
 | 
			
		||||
    case COGL_DRIVER_GL:
 | 
			
		||||
      {
 | 
			
		||||
        const char *extensions = meta_gl_get_string (GL_EXTENSIONS);
 | 
			
		||||
        return (extensions != NULL &&
 | 
			
		||||
                strstr (extensions, "GL_ARB_sync") != NULL &&
 | 
			
		||||
                strstr (extensions, "GL_EXT_x11_sync_object") != NULL);
 | 
			
		||||
      }
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
load_required_symbols (void)
 | 
			
		||||
{
 | 
			
		||||
  static gboolean success = FALSE;
 | 
			
		||||
 | 
			
		||||
  if (success)
 | 
			
		||||
    return TRUE;
 | 
			
		||||
 | 
			
		||||
  /* We don't link against libGL directly because cogl may want to
 | 
			
		||||
   * use something else. This assumes that cogl has been initialized
 | 
			
		||||
   * and dynamically loaded libGL at this point.
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  if (!load_gl_symbol ("glGetString", (void **) &meta_gl_get_string))
 | 
			
		||||
    goto out;
 | 
			
		||||
  if (!load_gl_symbol ("glGetIntegerv", (void **) &meta_gl_get_integerv))
 | 
			
		||||
    goto out;
 | 
			
		||||
  if (!load_gl_symbol ("glGetStringi", (void **) &meta_gl_get_stringi))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  if (!check_gl_extensions ())
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("MetaSyncRing: couldn't find required GL extensions\n");
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!load_gl_symbol ("glDeleteSync", (void **) &meta_gl_delete_sync))
 | 
			
		||||
    goto out;
 | 
			
		||||
  if (!load_gl_symbol ("glClientWaitSync", (void **) &meta_gl_client_wait_sync))
 | 
			
		||||
    goto out;
 | 
			
		||||
  if (!load_gl_symbol ("glWaitSync", (void **) &meta_gl_wait_sync))
 | 
			
		||||
    goto out;
 | 
			
		||||
  if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
 | 
			
		||||
    goto out;
 | 
			
		||||
  if (!load_gl_symbol ("glFenceSync", (void **) &meta_gl_fence_sync))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  success = TRUE;
 | 
			
		||||
 out:
 | 
			
		||||
  return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_sync_insert (MetaSync *self)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (self->state == META_SYNC_STATE_READY);
 | 
			
		||||
 | 
			
		||||
  XSyncTriggerFence (self->xdisplay, self->xfence);
 | 
			
		||||
  XFlush (self->xdisplay);
 | 
			
		||||
 | 
			
		||||
  meta_gl_wait_sync (self->gl_x11_sync, 0, GL_TIMEOUT_IGNORED);
 | 
			
		||||
  self->gpu_fence = meta_gl_fence_sync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
 | 
			
		||||
 | 
			
		||||
  self->state = META_SYNC_STATE_WAITING;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GLenum
 | 
			
		||||
meta_sync_check_update_finished (MetaSync *self,
 | 
			
		||||
                                 GLuint64  timeout)
 | 
			
		||||
{
 | 
			
		||||
  GLenum status = GL_WAIT_FAILED;
 | 
			
		||||
 | 
			
		||||
  switch (self->state)
 | 
			
		||||
    {
 | 
			
		||||
    case META_SYNC_STATE_DONE:
 | 
			
		||||
      status = GL_ALREADY_SIGNALED;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_SYNC_STATE_WAITING:
 | 
			
		||||
      status = meta_gl_client_wait_sync (self->gpu_fence, 0, timeout);
 | 
			
		||||
      if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
 | 
			
		||||
        {
 | 
			
		||||
          self->state = META_SYNC_STATE_DONE;
 | 
			
		||||
          meta_gl_delete_sync (self->gpu_fence);
 | 
			
		||||
          self->gpu_fence = 0;
 | 
			
		||||
        }
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_warn_if_fail (status != GL_WAIT_FAILED);
 | 
			
		||||
 | 
			
		||||
  return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_sync_reset (MetaSync *self)
 | 
			
		||||
{
 | 
			
		||||
  XSyncAlarmAttributes attrs;
 | 
			
		||||
  int overflow;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (self->state == META_SYNC_STATE_DONE);
 | 
			
		||||
 | 
			
		||||
  XSyncResetFence (self->xdisplay, self->xfence);
 | 
			
		||||
 | 
			
		||||
  attrs.trigger.wait_value = self->next_counter_value;
 | 
			
		||||
 | 
			
		||||
  XSyncChangeAlarm (self->xdisplay, self->xalarm, XSyncCAValue, &attrs);
 | 
			
		||||
  XSyncSetCounter (self->xdisplay, self->xcounter, self->next_counter_value);
 | 
			
		||||
 | 
			
		||||
  XSyncValueAdd (&self->next_counter_value,
 | 
			
		||||
                 self->next_counter_value,
 | 
			
		||||
                 SYNC_VALUE_ONE,
 | 
			
		||||
                 &overflow);
 | 
			
		||||
 | 
			
		||||
  self->state = META_SYNC_STATE_RESET_PENDING;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_sync_handle_event (MetaSync              *self,
 | 
			
		||||
                        XSyncAlarmNotifyEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (event->alarm == self->xalarm);
 | 
			
		||||
  g_return_if_fail (self->state == META_SYNC_STATE_RESET_PENDING);
 | 
			
		||||
 | 
			
		||||
  self->state = META_SYNC_STATE_READY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaSync *
 | 
			
		||||
meta_sync_new (Display *xdisplay)
 | 
			
		||||
{
 | 
			
		||||
  MetaSync *self;
 | 
			
		||||
  XSyncAlarmAttributes attrs;
 | 
			
		||||
 | 
			
		||||
  self = g_malloc0 (sizeof (MetaSync));
 | 
			
		||||
 | 
			
		||||
  self->xdisplay = xdisplay;
 | 
			
		||||
 | 
			
		||||
  self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
 | 
			
		||||
  self->gl_x11_sync = 0;
 | 
			
		||||
  self->gpu_fence = 0;
 | 
			
		||||
 | 
			
		||||
  self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
 | 
			
		||||
 | 
			
		||||
  attrs.trigger.counter = self->xcounter;
 | 
			
		||||
  attrs.trigger.value_type = XSyncAbsolute;
 | 
			
		||||
  attrs.trigger.wait_value = SYNC_VALUE_ONE;
 | 
			
		||||
  attrs.trigger.test_type = XSyncPositiveTransition;
 | 
			
		||||
  attrs.events = TRUE;
 | 
			
		||||
  self->xalarm = XSyncCreateAlarm (xdisplay,
 | 
			
		||||
                                   XSyncCACounter |
 | 
			
		||||
                                   XSyncCAValueType |
 | 
			
		||||
                                   XSyncCAValue |
 | 
			
		||||
                                   XSyncCATestType |
 | 
			
		||||
                                   XSyncCAEvents,
 | 
			
		||||
                                   &attrs);
 | 
			
		||||
 | 
			
		||||
  XSyncIntToValue (&self->next_counter_value, 1);
 | 
			
		||||
 | 
			
		||||
  self->state = META_SYNC_STATE_READY;
 | 
			
		||||
 | 
			
		||||
  return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_sync_import (MetaSync *self)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (self->gl_x11_sync == 0);
 | 
			
		||||
  self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Bool
 | 
			
		||||
alarm_event_predicate (Display  *dpy,
 | 
			
		||||
                       XEvent   *event,
 | 
			
		||||
                       XPointer  data)
 | 
			
		||||
{
 | 
			
		||||
  MetaSyncRing *ring = meta_sync_ring_get ();
 | 
			
		||||
 | 
			
		||||
  if (!ring)
 | 
			
		||||
    return False;
 | 
			
		||||
 | 
			
		||||
  if (event->type == ring->xsync_event_base + XSyncAlarmNotify)
 | 
			
		||||
    {
 | 
			
		||||
      if (((MetaSync *) data)->xalarm == ((XSyncAlarmNotifyEvent *) event)->alarm)
 | 
			
		||||
        return True;
 | 
			
		||||
    }
 | 
			
		||||
  return False;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_sync_free (MetaSync *self)
 | 
			
		||||
{
 | 
			
		||||
  /* When our assumptions don't hold, something has gone wrong but we
 | 
			
		||||
   * don't know what, so we reboot the ring. While doing that, we
 | 
			
		||||
   * trigger fences before deleting them to try to get ourselves out
 | 
			
		||||
   * of a potentially stuck GPU state.
 | 
			
		||||
   */
 | 
			
		||||
  switch (self->state)
 | 
			
		||||
    {
 | 
			
		||||
    case META_SYNC_STATE_WAITING:
 | 
			
		||||
      meta_gl_delete_sync (self->gpu_fence);
 | 
			
		||||
      break;
 | 
			
		||||
    case META_SYNC_STATE_DONE:
 | 
			
		||||
      /* nothing to do */
 | 
			
		||||
      break;
 | 
			
		||||
    case META_SYNC_STATE_RESET_PENDING:
 | 
			
		||||
      {
 | 
			
		||||
        XEvent event;
 | 
			
		||||
        XIfEvent (self->xdisplay, &event, alarm_event_predicate, (XPointer) self);
 | 
			
		||||
        meta_sync_handle_event (self, (XSyncAlarmNotifyEvent *) &event);
 | 
			
		||||
      }
 | 
			
		||||
      /* fall through */
 | 
			
		||||
    case META_SYNC_STATE_READY:
 | 
			
		||||
      XSyncTriggerFence (self->xdisplay, self->xfence);
 | 
			
		||||
      XFlush (self->xdisplay);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_gl_delete_sync (self->gl_x11_sync);
 | 
			
		||||
  XSyncDestroyFence (self->xdisplay, self->xfence);
 | 
			
		||||
  XSyncDestroyCounter (self->xdisplay, self->xcounter);
 | 
			
		||||
  XSyncDestroyAlarm (self->xdisplay, self->xalarm);
 | 
			
		||||
 | 
			
		||||
  g_free (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_sync_ring_init (Display *xdisplay)
 | 
			
		||||
{
 | 
			
		||||
  gint major, minor;
 | 
			
		||||
  guint i;
 | 
			
		||||
  MetaSyncRing *ring = meta_sync_ring_get ();
 | 
			
		||||
 | 
			
		||||
  if (!ring)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (xdisplay != NULL, FALSE);
 | 
			
		||||
  g_return_val_if_fail (ring->xdisplay == NULL, FALSE);
 | 
			
		||||
 | 
			
		||||
  if (!load_required_symbols ())
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (!XSyncQueryExtension (xdisplay, &ring->xsync_event_base, &ring->xsync_error_base) ||
 | 
			
		||||
      !XSyncInitialize (xdisplay, &major, &minor))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  XSyncIntToValue (&SYNC_VALUE_ZERO, 0);
 | 
			
		||||
  XSyncIntToValue (&SYNC_VALUE_ONE, 1);
 | 
			
		||||
 | 
			
		||||
  ring->xdisplay = xdisplay;
 | 
			
		||||
 | 
			
		||||
  ring->alarm_to_sync = g_hash_table_new (NULL, NULL);
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < NUM_SYNCS; ++i)
 | 
			
		||||
    {
 | 
			
		||||
      MetaSync *sync = meta_sync_new (ring->xdisplay);
 | 
			
		||||
      ring->syncs_array[i] = sync;
 | 
			
		||||
      g_hash_table_replace (ring->alarm_to_sync, (gpointer) sync->xalarm, sync);
 | 
			
		||||
    }
 | 
			
		||||
  /* Since the connection we create the X fences on isn't the same as
 | 
			
		||||
   * the one used for the GLX context, we need to XSync() here to
 | 
			
		||||
   * ensure glImportSync() succeeds. */
 | 
			
		||||
  XSync (xdisplay, False);
 | 
			
		||||
  for (i = 0; i < NUM_SYNCS; ++i)
 | 
			
		||||
    meta_sync_import (ring->syncs_array[i]);
 | 
			
		||||
 | 
			
		||||
  ring->current_sync_idx = 0;
 | 
			
		||||
  ring->current_sync = ring->syncs_array[0];
 | 
			
		||||
  ring->warmup_syncs = 0;
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_sync_ring_destroy (void)
 | 
			
		||||
{
 | 
			
		||||
  guint i;
 | 
			
		||||
  MetaSyncRing *ring = meta_sync_ring_get ();
 | 
			
		||||
 | 
			
		||||
  if (!ring)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (ring->xdisplay != NULL);
 | 
			
		||||
 | 
			
		||||
  ring->current_sync_idx = 0;
 | 
			
		||||
  ring->current_sync = NULL;
 | 
			
		||||
  ring->warmup_syncs = 0;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < NUM_SYNCS; ++i)
 | 
			
		||||
    meta_sync_free (ring->syncs_array[i]);
 | 
			
		||||
 | 
			
		||||
  g_hash_table_destroy (ring->alarm_to_sync);
 | 
			
		||||
 | 
			
		||||
  ring->xsync_event_base = 0;
 | 
			
		||||
  ring->xsync_error_base = 0;
 | 
			
		||||
  ring->xdisplay = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_sync_ring_reboot (Display *xdisplay)
 | 
			
		||||
{
 | 
			
		||||
  MetaSyncRing *ring = meta_sync_ring_get ();
 | 
			
		||||
 | 
			
		||||
  if (!ring)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  meta_sync_ring_destroy ();
 | 
			
		||||
 | 
			
		||||
  ring->reboots += 1;
 | 
			
		||||
 | 
			
		||||
  if (!meta_sync_ring_get ())
 | 
			
		||||
    {
 | 
			
		||||
      meta_warning ("MetaSyncRing: Too many reboots -- disabling\n");
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return meta_sync_ring_init (xdisplay);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_sync_ring_after_frame (void)
 | 
			
		||||
{
 | 
			
		||||
  MetaSyncRing *ring = meta_sync_ring_get ();
 | 
			
		||||
 | 
			
		||||
  if (!ring)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (ring->xdisplay != NULL, FALSE);
 | 
			
		||||
 | 
			
		||||
  if (ring->warmup_syncs >= NUM_SYNCS / 2)
 | 
			
		||||
    {
 | 
			
		||||
      guint reset_sync_idx = (ring->current_sync_idx + NUM_SYNCS - (NUM_SYNCS / 2)) % NUM_SYNCS;
 | 
			
		||||
      MetaSync *sync_to_reset = ring->syncs_array[reset_sync_idx];
 | 
			
		||||
 | 
			
		||||
      GLenum status = meta_sync_check_update_finished (sync_to_reset, 0);
 | 
			
		||||
      if (status == GL_TIMEOUT_EXPIRED)
 | 
			
		||||
        {
 | 
			
		||||
          meta_warning ("MetaSyncRing: We should never wait for a sync -- add more syncs?\n");
 | 
			
		||||
          status = meta_sync_check_update_finished (sync_to_reset, MAX_SYNC_WAIT_TIME);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED)
 | 
			
		||||
        {
 | 
			
		||||
          meta_warning ("MetaSyncRing: Timed out waiting for sync object.\n");
 | 
			
		||||
          return meta_sync_ring_reboot (ring->xdisplay);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_sync_reset (sync_to_reset);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      ring->warmup_syncs += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  ring->current_sync_idx += 1;
 | 
			
		||||
  ring->current_sync_idx %= NUM_SYNCS;
 | 
			
		||||
 | 
			
		||||
  ring->current_sync = ring->syncs_array[ring->current_sync_idx];
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_sync_ring_insert_wait (void)
 | 
			
		||||
{
 | 
			
		||||
  MetaSyncRing *ring = meta_sync_ring_get ();
 | 
			
		||||
 | 
			
		||||
  if (!ring)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (ring->xdisplay != NULL, FALSE);
 | 
			
		||||
 | 
			
		||||
  if (ring->current_sync->state != META_SYNC_STATE_READY)
 | 
			
		||||
    {
 | 
			
		||||
      meta_warning ("MetaSyncRing: Sync object is not ready -- were events handled properly?\n");
 | 
			
		||||
      if (!meta_sync_ring_reboot (ring->xdisplay))
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_sync_insert (ring->current_sync);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_sync_ring_handle_event (XEvent *xevent)
 | 
			
		||||
{
 | 
			
		||||
  XSyncAlarmNotifyEvent *event;
 | 
			
		||||
  MetaSync *sync;
 | 
			
		||||
  MetaSyncRing *ring = meta_sync_ring_get ();
 | 
			
		||||
 | 
			
		||||
  if (!ring)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (ring->xdisplay != NULL);
 | 
			
		||||
 | 
			
		||||
  if (xevent->type != (ring->xsync_event_base + XSyncAlarmNotify))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  event = (XSyncAlarmNotifyEvent *) xevent;
 | 
			
		||||
 | 
			
		||||
  sync = g_hash_table_lookup (ring->alarm_to_sync, (gpointer) event->alarm);
 | 
			
		||||
  if (sync)
 | 
			
		||||
    meta_sync_handle_event (sync, event);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								src/compositor/meta-sync-ring.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/compositor/meta-sync-ring.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
#ifndef _META_SYNC_RING_H_
 | 
			
		||||
#define _META_SYNC_RING_H_
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
 | 
			
		||||
gboolean meta_sync_ring_init (Display *dpy);
 | 
			
		||||
void meta_sync_ring_destroy (void);
 | 
			
		||||
gboolean meta_sync_ring_after_frame (void);
 | 
			
		||||
gboolean meta_sync_ring_insert_wait (void);
 | 
			
		||||
void meta_sync_ring_handle_event (XEvent *event);
 | 
			
		||||
 | 
			
		||||
#endif  /* _META_SYNC_RING_H_ */
 | 
			
		||||
@@ -100,7 +100,7 @@ struct _MetaWindowActorPrivate
 | 
			
		||||
  guint		    disposed               : 1;
 | 
			
		||||
 | 
			
		||||
  /* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
 | 
			
		||||
   * client message using the most recent frame in ->frames */
 | 
			
		||||
   * client message for one or more messages in ->frames */
 | 
			
		||||
  guint             needs_frame_drawn      : 1;
 | 
			
		||||
  guint             repaint_scheduled      : 1;
 | 
			
		||||
 | 
			
		||||
@@ -118,10 +118,21 @@ struct _MetaWindowActorPrivate
 | 
			
		||||
 | 
			
		||||
typedef struct _FrameData FrameData;
 | 
			
		||||
 | 
			
		||||
/* Each time the application updates the sync request counter to a new even value
 | 
			
		||||
 * value, we queue a frame into the windows list of frames. Once we're painting
 | 
			
		||||
 * an update "in response" to the window, we fill in frame_counter with the
 | 
			
		||||
 * Cogl counter for that frame, and send _NET_WM_FRAME_DRAWN at the end of the
 | 
			
		||||
 * frame. _NET_WM_FRAME_TIMINGS is sent when we get a frame_complete callback.
 | 
			
		||||
 *
 | 
			
		||||
 * As an exception, if a window is completely obscured, we try to throttle drawning
 | 
			
		||||
 * to a slower frame rate. In this case, frame_counter stays -1 until
 | 
			
		||||
 * send_frame_message_timeout() runs, at which point we send both the
 | 
			
		||||
 * _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages.
 | 
			
		||||
 */
 | 
			
		||||
struct _FrameData
 | 
			
		||||
{
 | 
			
		||||
  int64_t frame_counter;
 | 
			
		||||
  guint64 sync_request_serial;
 | 
			
		||||
  int64_t frame_counter;
 | 
			
		||||
  gint64 frame_drawn_time;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -655,6 +666,30 @@ clip_shadow_under_window (MetaWindowActor *self)
 | 
			
		||||
  return is_non_opaque (self) && priv->window->frame;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
assign_frame_counter_to_frames (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  /* If the window is obscured, then we're expecting to deal with sending
 | 
			
		||||
   * frame messages in a timeout, rather than in this paint cycle.
 | 
			
		||||
   */
 | 
			
		||||
  if (priv->send_frame_messages_timer != 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  for (l = priv->frames; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      FrameData *frame = l->data;
 | 
			
		||||
 | 
			
		||||
      if (frame->frame_counter == -1)
 | 
			
		||||
        {
 | 
			
		||||
          CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
 | 
			
		||||
          frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_window_actor_paint (ClutterActor *actor)
 | 
			
		||||
{
 | 
			
		||||
@@ -671,6 +706,8 @@ meta_window_actor_paint (ClutterActor *actor)
 | 
			
		||||
    {
 | 
			
		||||
      g_source_remove (priv->send_frame_messages_timer);
 | 
			
		||||
      priv->send_frame_messages_timer = 0;
 | 
			
		||||
 | 
			
		||||
      assign_frame_counter_to_frames (self);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (shadow != NULL)
 | 
			
		||||
@@ -873,16 +910,27 @@ send_frame_messages_timeout (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActor *self = (MetaWindowActor *) data;
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
  FrameData *frame = g_slice_new0 (FrameData);
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  frame->sync_request_serial = priv->window->sync_request_serial;
 | 
			
		||||
  for (l = priv->frames; l;)
 | 
			
		||||
    {
 | 
			
		||||
      GList *l_next = l->next;
 | 
			
		||||
      FrameData *frame = l->data;
 | 
			
		||||
 | 
			
		||||
  do_send_frame_drawn (self, frame);
 | 
			
		||||
  do_send_frame_timings (self, frame, 0, 0);
 | 
			
		||||
      if (frame->frame_counter == -1)
 | 
			
		||||
        {
 | 
			
		||||
          do_send_frame_drawn (self, frame);
 | 
			
		||||
          do_send_frame_timings (self, frame, 0, 0);
 | 
			
		||||
 | 
			
		||||
          priv->frames = g_list_delete_link (priv->frames, l);
 | 
			
		||||
          frame_data_free (frame);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      l = l_next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  priv->needs_frame_drawn = FALSE;
 | 
			
		||||
  priv->send_frame_messages_timer = 0;
 | 
			
		||||
  frame_data_free (frame);
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
@@ -891,6 +939,10 @@ static void
 | 
			
		||||
queue_send_frame_messages_timeout (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
 | 
			
		||||
  if (priv->send_frame_messages_timer != 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  MetaDisplay *display = meta_window_get_display (priv->window);
 | 
			
		||||
  gint64 current_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ());
 | 
			
		||||
  MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
 | 
			
		||||
@@ -933,6 +985,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  frame = g_slice_new0 (FrameData);
 | 
			
		||||
  frame->frame_counter = -1;
 | 
			
		||||
 | 
			
		||||
  priv->needs_frame_drawn = TRUE;
 | 
			
		||||
 | 
			
		||||
@@ -1155,7 +1208,7 @@ gboolean
 | 
			
		||||
meta_window_actor_should_unredirect (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
  if (priv->surface)
 | 
			
		||||
  if (!meta_window_actor_is_destroyed (self) && priv->surface)
 | 
			
		||||
    return meta_surface_actor_should_unredirect (priv->surface);
 | 
			
		||||
  else
 | 
			
		||||
    return FALSE;
 | 
			
		||||
@@ -1905,24 +1958,12 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
 | 
			
		||||
void
 | 
			
		||||
meta_window_actor_pre_paint (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  if (meta_window_actor_is_destroyed (self))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_handle_updates (self);
 | 
			
		||||
 | 
			
		||||
  for (l = priv->frames; l != NULL; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      FrameData *frame = l->data;
 | 
			
		||||
 | 
			
		||||
      if (frame->frame_counter == 0)
 | 
			
		||||
        {
 | 
			
		||||
          CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
 | 
			
		||||
          frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  assign_frame_counter_to_frames (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -1963,16 +2004,23 @@ meta_window_actor_post_paint (MetaWindowActor *self)
 | 
			
		||||
  if (meta_window_actor_is_destroyed (self))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
 /* This window had damage, but wasn't actually redrawn because
 | 
			
		||||
  * it is obscured. So we should wait until timer expiration
 | 
			
		||||
  * before sending _NET_WM_FRAME_* messages.
 | 
			
		||||
  */
 | 
			
		||||
  if (priv->send_frame_messages_timer != 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (priv->needs_frame_drawn)
 | 
			
		||||
  /* If the window had damage, but wasn't actually redrawn because
 | 
			
		||||
   * it is obscured, we should wait until timer expiration before
 | 
			
		||||
   * sending _NET_WM_FRAME_* messages.
 | 
			
		||||
   */
 | 
			
		||||
  if (priv->send_frame_messages_timer == 0 &&
 | 
			
		||||
      priv->needs_frame_drawn)
 | 
			
		||||
    {
 | 
			
		||||
      do_send_frame_drawn (self, priv->frames->data);
 | 
			
		||||
      GList *l;
 | 
			
		||||
 | 
			
		||||
      for (l = priv->frames; l; l = l->next)
 | 
			
		||||
        {
 | 
			
		||||
          FrameData *frame = l->data;
 | 
			
		||||
 | 
			
		||||
          if (frame->frame_drawn_time == 0)
 | 
			
		||||
            do_send_frame_drawn (self, frame);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      priv->needs_frame_drawn = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -2057,15 +2105,20 @@ meta_window_actor_frame_complete (MetaWindowActor *self,
 | 
			
		||||
    {
 | 
			
		||||
      GList *l_next = l->next;
 | 
			
		||||
      FrameData *frame = l->data;
 | 
			
		||||
      gint64 frame_counter = cogl_frame_info_get_frame_counter (frame_info);
 | 
			
		||||
 | 
			
		||||
      if (frame->frame_counter == cogl_frame_info_get_frame_counter (frame_info))
 | 
			
		||||
      if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter)
 | 
			
		||||
        {
 | 
			
		||||
          if (frame->frame_drawn_time != 0)
 | 
			
		||||
            {
 | 
			
		||||
              priv->frames = g_list_delete_link (priv->frames, l);
 | 
			
		||||
              send_frame_timings (self, frame, frame_info, presentation_time);
 | 
			
		||||
              frame_data_free (frame);
 | 
			
		||||
            }
 | 
			
		||||
          if (G_UNLIKELY (frame->frame_drawn_time == 0))
 | 
			
		||||
            g_warning ("%s: Frame has assigned frame counter but no frame drawn time",
 | 
			
		||||
                       priv->window->desc);
 | 
			
		||||
          if (G_UNLIKELY (frame->frame_counter < frame_counter))
 | 
			
		||||
            g_warning ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT,
 | 
			
		||||
                       priv->window->desc, frame->frame_counter);
 | 
			
		||||
 | 
			
		||||
          priv->frames = g_list_delete_link (priv->frames, l);
 | 
			
		||||
          send_frame_timings (self, frame, frame_info, presentation_time);
 | 
			
		||||
          frame_data_free (frame);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      l = l_next;
 | 
			
		||||
 
 | 
			
		||||
@@ -1214,7 +1214,7 @@ meta_grab_op_is_moving (MetaGrabOp op)
 | 
			
		||||
  if (!grab_op_is_window (op))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  return (op & META_GRAB_OP_WINDOW_DIR_MASK) == 0;
 | 
			
		||||
  return !meta_grab_op_is_resizing (op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -1965,7 +1965,7 @@ meta_display_end_grab_op (MetaDisplay *display,
 | 
			
		||||
       * beginning of the grab_op.
 | 
			
		||||
       */
 | 
			
		||||
      if (!meta_prefs_get_raise_on_click () &&
 | 
			
		||||
          display->grab_threshold_movement_reached)
 | 
			
		||||
          !display->grab_threshold_movement_reached)
 | 
			
		||||
        meta_window_raise (display->grab_window);
 | 
			
		||||
 | 
			
		||||
      meta_window_grab_op_ended (grab_window, grab_op);
 | 
			
		||||
 
 | 
			
		||||
@@ -779,7 +779,8 @@ meta_window_place (MetaWindow        *window,
 | 
			
		||||
 | 
			
		||||
        if (w != window &&
 | 
			
		||||
            meta_window_showing_on_its_workspace (w) &&
 | 
			
		||||
            meta_window_located_on_workspace (w, window->workspace))
 | 
			
		||||
            (window->on_all_workspaces ||
 | 
			
		||||
             meta_window_located_on_workspace (w, window->workspace)))
 | 
			
		||||
          windows = g_list_prepend (windows, w);
 | 
			
		||||
 | 
			
		||||
        tmp = tmp->next;
 | 
			
		||||
 
 | 
			
		||||
@@ -496,15 +496,6 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
 | 
			
		||||
  return guard_window;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Set a black background on the root window so that we don't
 | 
			
		||||
 * see confusing old copies of old windows when debugging
 | 
			
		||||
 * and testing. */
 | 
			
		||||
static void
 | 
			
		||||
meta_screen_set_background (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  XSetWindowBackground (screen->display->xdisplay, screen->xroot, 0x00000000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaScreen*
 | 
			
		||||
meta_screen_new (MetaDisplay *display,
 | 
			
		||||
                 int          number,
 | 
			
		||||
@@ -709,7 +700,6 @@ meta_screen_new (MetaDisplay *display,
 | 
			
		||||
  reload_monitor_infos (screen);
 | 
			
		||||
 | 
			
		||||
  meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
 | 
			
		||||
  meta_screen_set_background (screen);
 | 
			
		||||
 | 
			
		||||
  /* Handle creating a no_focus_window for this screen */
 | 
			
		||||
  screen->no_focus_window =
 | 
			
		||||
@@ -3022,7 +3012,6 @@ check_fullscreen_func (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  MetaScreen *screen = data;
 | 
			
		||||
  MetaWindow *window;
 | 
			
		||||
  GSList *tmp;
 | 
			
		||||
  GSList *fullscreen_monitors = NULL;
 | 
			
		||||
  GSList *obscured_monitors = NULL;
 | 
			
		||||
  gboolean in_fullscreen_changed = FALSE;
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,8 @@ struct _MetaBackground
 | 
			
		||||
  MetaBackgroundPrivate *priv;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void meta_background_refresh_all (void);
 | 
			
		||||
 | 
			
		||||
GType meta_background_get_type (void);
 | 
			
		||||
 | 
			
		||||
MetaBackground *meta_background_new  (MetaScreen *screen);
 | 
			
		||||
 
 | 
			
		||||
@@ -393,10 +393,7 @@ commit_pending_state (MetaWaylandSurface      *surface,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (pending->scale > 0)
 | 
			
		||||
    {
 | 
			
		||||
      surface->scale = pending->scale;
 | 
			
		||||
      meta_surface_actor_wayland_scale_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
 | 
			
		||||
    }
 | 
			
		||||
    surface->scale = pending->scale;
 | 
			
		||||
 | 
			
		||||
  if (!cairo_region_is_empty (pending->damage))
 | 
			
		||||
    surface_process_damage (surface, pending->damage);
 | 
			
		||||
@@ -411,10 +408,14 @@ commit_pending_state (MetaWaylandSurface      *surface,
 | 
			
		||||
    }
 | 
			
		||||
  if (pending->input_region)
 | 
			
		||||
    {
 | 
			
		||||
      pending->input_region = scale_region (pending->input_region, surface->scale);
 | 
			
		||||
      pending->input_region = scale_region (pending->input_region,
 | 
			
		||||
                                            meta_surface_actor_wayland_get_scale (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor)));
 | 
			
		||||
      meta_surface_actor_set_input_region (surface->surface_actor, pending->input_region);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* scale surface texture */
 | 
			
		||||
  meta_surface_actor_wayland_scale_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
 | 
			
		||||
 | 
			
		||||
  /* wl_surface.frame */
 | 
			
		||||
  wl_list_insert_list (&compositor->frame_callbacks, &pending->frame_callback_list);
 | 
			
		||||
  wl_list_init (&pending->frame_callback_list);
 | 
			
		||||
 
 | 
			
		||||
@@ -1073,9 +1073,10 @@ meta_window_x11_move_resize_internal (MetaWindow                *window,
 | 
			
		||||
      /* Compute new frame size */
 | 
			
		||||
      new_w = window->rect.width + borders.invisible.left + borders.invisible.right;
 | 
			
		||||
 | 
			
		||||
      new_h = borders.invisible.top + borders.invisible.bottom;
 | 
			
		||||
      if (!window->shaded)
 | 
			
		||||
        new_h += window->rect.height;
 | 
			
		||||
      if (window->shaded)
 | 
			
		||||
        new_h = borders.total.top + borders.total.bottom;
 | 
			
		||||
      else
 | 
			
		||||
        new_h = window->rect.height + borders.invisible.top + borders.invisible.bottom;
 | 
			
		||||
 | 
			
		||||
      if (new_w != window->frame->rect.width ||
 | 
			
		||||
          new_h != window->frame->rect.height)
 | 
			
		||||
@@ -1684,7 +1685,7 @@ meta_window_x11_update_input_region (MetaWindow *window)
 | 
			
		||||
      /* Translate the set of XShape rectangles that we
 | 
			
		||||
       * get from the X server to a cairo_region. */
 | 
			
		||||
      XRectangle *rects = NULL;
 | 
			
		||||
      int n_rects, ordering;
 | 
			
		||||
      int n_rects = -1, ordering;
 | 
			
		||||
 | 
			
		||||
      meta_error_trap_push (window->display);
 | 
			
		||||
      rects = XShapeGetRectangles (window->display->xdisplay,
 | 
			
		||||
@@ -1694,21 +1695,46 @@ meta_window_x11_update_input_region (MetaWindow *window)
 | 
			
		||||
                                   &ordering);
 | 
			
		||||
      meta_error_trap_pop (window->display);
 | 
			
		||||
 | 
			
		||||
      /* XXX: The x shape extension doesn't provide a way to only test if an
 | 
			
		||||
       * input shape has been specified, so we have to query and throw away the
 | 
			
		||||
       * rectangles. */
 | 
			
		||||
      if (rects)
 | 
			
		||||
        {
 | 
			
		||||
          if (n_rects > 1 ||
 | 
			
		||||
              (n_rects == 1 &&
 | 
			
		||||
               (rects[0].x != 0 ||
 | 
			
		||||
                rects[0].y != 0 ||
 | 
			
		||||
                rects[0].width != priv->client_rect.width ||
 | 
			
		||||
                rects[0].height != priv->client_rect.height)))
 | 
			
		||||
            region = region_create_from_x_rectangles (rects, n_rects);
 | 
			
		||||
      /* XXX: The X Shape specification is quite unfortunately specified.
 | 
			
		||||
       *
 | 
			
		||||
       * By default, the window has a shape the same as its bounding region,
 | 
			
		||||
       * which we consider "NULL".
 | 
			
		||||
       *
 | 
			
		||||
       * If the window sets an empty region, then we'll get n_rects as 0
 | 
			
		||||
       * and rects as NULL, which we need to transform back into an empty
 | 
			
		||||
       * region.
 | 
			
		||||
       *
 | 
			
		||||
       * It would be great to have a less-broken extension for this, but
 | 
			
		||||
       * hey, it's X11!
 | 
			
		||||
       */
 | 
			
		||||
 | 
			
		||||
          XFree (rects);
 | 
			
		||||
      if (n_rects == -1)
 | 
			
		||||
        {
 | 
			
		||||
          /* We had an error. */
 | 
			
		||||
          region = NULL;
 | 
			
		||||
        }
 | 
			
		||||
      else if (n_rects == 0)
 | 
			
		||||
        {
 | 
			
		||||
          /* Client set an empty region. */
 | 
			
		||||
          region = cairo_region_create ();
 | 
			
		||||
        }
 | 
			
		||||
      else if (n_rects == 1 &&
 | 
			
		||||
               (rects[0].x == 0 ||
 | 
			
		||||
                rects[0].y == 0 ||
 | 
			
		||||
                rects[0].width == priv->client_rect.width ||
 | 
			
		||||
                rects[0].height == priv->client_rect.height))
 | 
			
		||||
        {
 | 
			
		||||
          /* This is the bounding region case. Keep the
 | 
			
		||||
           * region as NULL. */
 | 
			
		||||
          region = NULL;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          /* Window has a custom shape. */
 | 
			
		||||
          region = region_create_from_x_rectangles (rects, n_rects);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_XFree (rects);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (region != NULL)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user