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