xserver: Branch 'master' - 5 commits

Adam Jackson ajax at kemper.freedesktop.org
Thu Feb 23 18:51:49 UTC 2017


 dix/property.c         |   23 ++++--
 hw/xwayland/xwayland.c |  177 ++++++++++++++++++++++++++++++++++++++++++-------
 hw/xwayland/xwayland.h |    3 
 include/property.h     |    8 ++
 4 files changed, 181 insertions(+), 30 deletions(-)

New commits:
commit 9f4d308cdad957a354912f17febe5bcad7f44812
Author: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
Date:   Wed Nov 23 13:30:53 2016 +0200

    xwayland: use _XWAYLAND_ALLOW_COMMITS property
    
    The X11 window manager (XWM) of a Wayland compositor can use the
    _XWAYLAND_ALLOW_COMMITS property to control when Xwayland sends
    wl_surface.commit requests. If the property is not set, the behaviour
    remains what it was.
    
    XWM uses the property to inhibit commits until the window is ready to be
    shown. This gives XWM time to set up the window decorations and internal
    state before Xwayland does the first commit. XWM can use this to ensure
    the first commit carries fully drawn decorations and the window
    management state is correct when the window becomes visible.
    
    Setting the property to zero inhibits further commits, and setting it to
    non-zero allows commits. Deleting the property allows commits.
    
    When the property is changed from zero to non-zero, there will be a
    commit on next block_handler() call provided that some damage has been
    recorded.
    
    Without this patch (i.e. with the old behaviour) Xwayland can and will
    commit the surface very soon as the application window has been realized
    and drawn into.  This races with XWM and may cause visible glitches.
    
    v3:
    - introduced a simple setter for xwl_window::allow_commits
    - split xwl_window_property_allow_commits() out of
      xwl_property_callback()
    - check MakeAtom(_XWAYLAND_ALLOW_COMMITS)
    
    v2:
    - use PropertyStateCallback instead of XACE, based on the patch
      "xwayland: Track per-window support for netwm frame sync" by
      Adam Jackson
    - check property type is XA_CARDINAL
    - drop a useless memcpy()
    
    Weston Bug: https://phabricator.freedesktop.org/T7622
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 9d79554..ed60035 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -27,6 +27,7 @@
 
 #include <stdio.h>
 
+#include <X11/Xatom.h>
 #include <selection.h>
 #include <micmap.h>
 #include <misyncshm.h>
@@ -34,6 +35,7 @@
 #include <glx_extinit.h>
 #include <os.h>
 #include <xserver_poll.h>
+#include <propertyst.h>
 
 #ifdef XF86VIDMODE
 #include <X11/extensions/xf86vmproto.h>
@@ -115,6 +117,94 @@ xwl_screen_get(ScreenPtr screen)
     return dixLookupPrivate(&screen->devPrivates, &xwl_screen_private_key);
 }
 
+static void
+xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow,
+                             const char *debug_msg)
+{
+    xwl_window->allow_commits = allow;
+    DebugF("xwayland: win %d allow_commits = %d (%s)\n",
+           xwl_window->window->drawable.id, allow, debug_msg);
+}
+
+static void
+xwl_window_set_allow_commits_from_property(struct xwl_window *xwl_window,
+                                           PropertyPtr prop)
+{
+    static Bool warned = FALSE;
+    CARD32 *propdata;
+
+    if (prop->propertyName != xwl_window->xwl_screen->allow_commits_prop)
+        FatalError("Xwayland internal error: prop mismatch in %s.\n", __func__);
+
+    if (prop->type != XA_CARDINAL || prop->format != 32 || prop->size != 1) {
+        /* Not properly set, so fall back to safe and glitchy */
+        xwl_window_set_allow_commits(xwl_window, TRUE, "WM fault");
+
+        if (!warned) {
+            LogMessage(X_WARNING, "Window manager is misusing property %s.\n",
+                       NameForAtom(prop->propertyName));
+            warned = TRUE;
+        }
+        return;
+    }
+
+    propdata = prop->data;
+    xwl_window_set_allow_commits(xwl_window, !!propdata[0], "from property");
+}
+
+static void
+xwl_window_property_allow_commits(struct xwl_window *xwl_window,
+                                  PropertyStateRec *propstate)
+{
+    Bool old_allow_commits = xwl_window->allow_commits;
+
+    switch (propstate->state) {
+    case PropertyNewValue:
+        xwl_window_set_allow_commits_from_property(xwl_window, propstate->prop);
+        break;
+
+    case PropertyDelete:
+        xwl_window_set_allow_commits(xwl_window, TRUE, "property deleted");
+        break;
+
+    default:
+        break;
+    }
+
+    /* If allow_commits turned from off to on, discard any frame
+     * callback we might be waiting for so that a new buffer is posted
+     * immediately through block_handler() if there is damage to post.
+     */
+    if (!old_allow_commits && xwl_window->allow_commits) {
+        if (xwl_window->frame_callback) {
+            wl_callback_destroy(xwl_window->frame_callback);
+            xwl_window->frame_callback = NULL;
+        }
+    }
+}
+
+static void
+xwl_property_callback(CallbackListPtr *pcbl, void *closure,
+                      void *calldata)
+{
+    ScreenPtr screen = closure;
+    PropertyStateRec *rec = calldata;
+    struct xwl_screen *xwl_screen;
+    struct xwl_window *xwl_window;
+
+    if (rec->win->drawable.pScreen != screen)
+        return;
+
+    xwl_window = xwl_window_get(rec->win);
+    if (!xwl_window)
+        return;
+
+    xwl_screen = xwl_screen_get(screen);
+
+    if (rec->prop->propertyName == xwl_screen->allow_commits_prop)
+        xwl_window_property_allow_commits(xwl_window, rec);
+}
+
 static Bool
 xwl_close_screen(ScreenPtr screen)
 {
@@ -122,6 +212,8 @@ xwl_close_screen(ScreenPtr screen)
     struct xwl_output *xwl_output, *next_xwl_output;
     struct xwl_seat *xwl_seat, *next_xwl_seat;
 
+    DeleteCallback(&PropertyStateCallback, xwl_property_callback, screen);
+
     xorg_list_for_each_entry_safe(xwl_output, next_xwl_output,
                                   &xwl_screen->output_list, link)
         xwl_output_destroy(xwl_output);
@@ -262,6 +354,21 @@ xwl_pixmap_get(PixmapPtr pixmap)
 }
 
 static void
+xwl_window_init_allow_commits(struct xwl_window *xwl_window)
+{
+    PropertyPtr prop = NULL;
+    int ret;
+
+    ret = dixLookupProperty(&prop, xwl_window->window,
+                            xwl_window->xwl_screen->allow_commits_prop,
+                            serverClient, DixReadAccess);
+    if (ret == Success && prop)
+        xwl_window_set_allow_commits_from_property(xwl_window, prop);
+    else
+        xwl_window_set_allow_commits(xwl_window, TRUE, "no property");
+}
+
+static void
 send_surface_id_event(struct xwl_window *xwl_window)
 {
     static const char atom_name[] = "WL_SURFACE_ID";
@@ -376,6 +483,8 @@ xwl_realize_window(WindowPtr window)
     dixSetPrivate(&window->devPrivates, &xwl_window_private_key, xwl_window);
     xorg_list_init(&xwl_window->link_damage);
 
+    xwl_window_init_allow_commits(xwl_window);
+
     return ret;
 
 err_surf:
@@ -505,6 +614,9 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen)
         if (xwl_window->frame_callback)
             continue;
 
+        if (!xwl_window->allow_commits)
+            continue;
+
         xwl_window_post_damage(xwl_window);
     }
 }
@@ -694,6 +806,7 @@ wm_selection_callback(CallbackListPtr *p, void *data, void *arg)
 static Bool
 xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
 {
+    static const char allow_commits[] = "_XWAYLAND_ALLOW_COMMITS";
     struct xwl_screen *xwl_screen;
     Pixel red_mask, blue_mask, green_mask;
     int ret, bpc, green_bpc, i;
@@ -849,6 +962,14 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     pScreen->CursorWarpedTo = xwl_cursor_warped_to;
     pScreen->CursorConfinedTo = xwl_cursor_confined_to;
 
+    xwl_screen->allow_commits_prop = MakeAtom(allow_commits,
+                                              strlen(allow_commits),
+                                              TRUE);
+    if (xwl_screen->allow_commits_prop == BAD_RESOURCE)
+        return FALSE;
+
+    AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen);
+
     return ret;
 }
 
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 5e5624b..91b7620 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -99,6 +99,8 @@ struct xwl_screen {
     void *egl_display, *egl_context;
     struct gbm_device *gbm;
     struct glamor_context *glamor_ctx;
+
+    Atom allow_commits_prop;
 };
 
 struct xwl_window {
@@ -109,6 +111,7 @@ struct xwl_window {
     DamagePtr damage;
     struct xorg_list link_damage;
     struct wl_callback *frame_callback;
+    Bool allow_commits;
 };
 
 #define MODIFIER_META 0x01
commit a6308cea602f688ac653e3466cd57767e02093a9
Author: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
Date:   Thu Nov 24 11:54:44 2016 +0200

    xwayland: fix 'buffer' may be used uninitialized warning
    
    Fix the following warning due to --disable-glamor:
    
      CC       Xwayland-xwayland.o
    In file included from /home/pq/local/include/wayland-client.h:40:0,
                     from xwayland.h:35,
                     from xwayland.c:26:
    xwayland.c: In function ‘block_handler’:
    /home/pq/local/include/wayland-client-protocol.h:3446:2: warning: ‘buffer’ may be used uninitialized in this function [-Wmaybe-uninitialized]
      wl_proxy_marshal((struct wl_proxy *) wl_surface,
      ^
    xwayland.c:466:23: note: ‘buffer’ was declared here
         struct wl_buffer *buffer;
                           ^
    
    Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>

diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index c2ac4b3..9d79554 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -474,8 +474,8 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
 #if GLAMOR_HAS_GBM
     if (xwl_screen->glamor)
         buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap);
+    else
 #endif
-    if (!xwl_screen->glamor)
         buffer = xwl_shm_pixmap_get_wl_buffer(pixmap);
 
     wl_surface_attach(xwl_window->surface, buffer, 0, 0);
commit f7b8560f23ac5582e2f97dc9f6de32a42e61e520
Author: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
Date:   Thu Nov 24 11:45:25 2016 +0200

    xwayland: refactor into xwl_window_post_damage()
    
    Refactor xwl_screen_post_damage() and split the window specific code
    into a new function xwl_window_post_damage().
    
    This is a pure refactoring, there are no behavioral changes. An assert
    is added to xwl_window_post_damage() to ensure frame callbacks are not
    leaked if a future patch changes the call.
    
    Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>

diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 9e1ecf8..c2ac4b3 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -458,44 +458,54 @@ static const struct wl_callback_listener frame_listener = {
 };
 
 static void
-xwl_screen_post_damage(struct xwl_screen *xwl_screen)
+xwl_window_post_damage(struct xwl_window *xwl_window)
 {
-    struct xwl_window *xwl_window, *next_xwl_window;
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     RegionPtr region;
     BoxPtr box;
     struct wl_buffer *buffer;
     PixmapPtr pixmap;
 
-    xorg_list_for_each_entry_safe(xwl_window, next_xwl_window,
-                                  &xwl_screen->damage_window_list, link_damage) {
-        /* If we're waiting on a frame callback from the server,
-         * don't attach a new buffer. */
-        if (xwl_window->frame_callback)
-            continue;
+    assert(!xwl_window->frame_callback);
 
-        region = DamageRegion(xwl_window->damage);
-        pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window);
+    region = DamageRegion(xwl_window->damage);
+    pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window);
 
 #if GLAMOR_HAS_GBM
-        if (xwl_screen->glamor)
-            buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap);
+    if (xwl_screen->glamor)
+        buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap);
 #endif
-        if (!xwl_screen->glamor)
-            buffer = xwl_shm_pixmap_get_wl_buffer(pixmap);
+    if (!xwl_screen->glamor)
+        buffer = xwl_shm_pixmap_get_wl_buffer(pixmap);
 
-        wl_surface_attach(xwl_window->surface, buffer, 0, 0);
+    wl_surface_attach(xwl_window->surface, buffer, 0, 0);
 
-        box = RegionExtents(region);
-        wl_surface_damage(xwl_window->surface, box->x1, box->y1,
-                          box->x2 - box->x1, box->y2 - box->y1);
+    box = RegionExtents(region);
+    wl_surface_damage(xwl_window->surface, box->x1, box->y1,
+                        box->x2 - box->x1, box->y2 - box->y1);
 
-        xwl_window->frame_callback = wl_surface_frame(xwl_window->surface);
-        wl_callback_add_listener(xwl_window->frame_callback, &frame_listener, xwl_window);
+    xwl_window->frame_callback = wl_surface_frame(xwl_window->surface);
+    wl_callback_add_listener(xwl_window->frame_callback, &frame_listener, xwl_window);
 
-        wl_surface_commit(xwl_window->surface);
-        DamageEmpty(xwl_window->damage);
+    wl_surface_commit(xwl_window->surface);
+    DamageEmpty(xwl_window->damage);
 
-        xorg_list_del(&xwl_window->link_damage);
+    xorg_list_del(&xwl_window->link_damage);
+}
+
+static void
+xwl_screen_post_damage(struct xwl_screen *xwl_screen)
+{
+    struct xwl_window *xwl_window, *next_xwl_window;
+
+    xorg_list_for_each_entry_safe(xwl_window, next_xwl_window,
+                                  &xwl_screen->damage_window_list, link_damage) {
+        /* If we're waiting on a frame callback from the server,
+         * don't attach a new buffer. */
+        if (xwl_window->frame_callback)
+            continue;
+
+        xwl_window_post_damage(xwl_window);
     }
 }
 
commit 8e3f9ce6c06e7605832c55dfd180396f66ec8b66
Author: Adam Jackson <ajax at redhat.com>
Date:   Sat Jul 12 12:45:23 2014 -0400

    dix: Add a callback chain for window property state change
    
    This will be used by in-server features that need to react to property
    changes. The first one will be _XWAYLAND_ALLOW_COMMITS.
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>
    [Pekka: add commit message body]
    Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

diff --git a/dix/property.c b/dix/property.c
index 3447bca..ff1d669 100644
--- a/dix/property.c
+++ b/dix/property.c
@@ -105,10 +105,17 @@ dixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom propertyName,
     return rc;
 }
 
+CallbackListPtr PropertyStateCallback;
+
 static void
 deliverPropertyNotifyEvent(WindowPtr pWin, int state, PropertyPtr pProp)
 {
     xEvent event;
+    PropertyStateRec rec = {
+        .win = pWin,
+        .prop = pProp,
+        .state = state
+    };
     UpdateCurrentTimeIf();
     event = (xEvent) {
         .u.property.window = pWin->drawable.id,
@@ -117,6 +124,8 @@ deliverPropertyNotifyEvent(WindowPtr pWin, int state, PropertyPtr pProp)
         .u.property.time = currentTime.milliseconds,
     };
     event.u.u.type = PropertyNotify;
+
+    CallCallbacks(&PropertyStateCallback, &rec);
     DeliverEvents(pWin, &event, 1, (WindowPtr) NULL);
 }
 
diff --git a/include/property.h b/include/property.h
index be875e9..d7ccff3 100644
--- a/include/property.h
+++ b/include/property.h
@@ -51,6 +51,14 @@ SOFTWARE.
 
 typedef struct _Property *PropertyPtr;
 
+typedef struct _PropertyStateRec {
+    WindowPtr win;
+    PropertyPtr prop;
+    int state;
+} PropertyStateRec;
+
+extern CallbackListPtr PropertyStateCallback;
+
 extern _X_EXPORT int dixLookupProperty(PropertyPtr * /*result */ ,
                                        WindowPtr /*pWin */ ,
                                        Atom /*proprty */ ,
commit 50bcea8be337ea983e464f2b5b8b2dc6d1024532
Author: Adam Jackson <ajax at redhat.com>
Date:   Sat Jul 12 12:39:21 2014 -0400

    dix: Pass the whole property into deliverPropertyNotifyEvent
    
    Instead of just the atom.  No functional change.
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

diff --git a/dix/property.c b/dix/property.c
index fa4da2d..3447bca 100644
--- a/dix/property.c
+++ b/dix/property.c
@@ -106,14 +106,14 @@ dixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom propertyName,
 }
 
 static void
-deliverPropertyNotifyEvent(WindowPtr pWin, int state, Atom atom)
+deliverPropertyNotifyEvent(WindowPtr pWin, int state, PropertyPtr pProp)
 {
     xEvent event;
     UpdateCurrentTimeIf();
     event = (xEvent) {
         .u.property.window = pWin->drawable.id,
         .u.property.state = state,
-        .u.property.atom = atom,
+        .u.property.atom = pProp->propertyName,
         .u.property.time = currentTime.milliseconds,
     };
     event.u.u.type = PropertyNotify;
@@ -175,7 +175,7 @@ ProcRotateProperties(ClientPtr client)
             delta += stuff->nAtoms;
         for (i = 0; i < stuff->nAtoms; i++) {
             j = (i + delta) % stuff->nAtoms;
-            deliverPropertyNotifyEvent(pWin, PropertyNewValue, atoms[i]);
+            deliverPropertyNotifyEvent(pWin, PropertyNewValue, props[i]);
 
             /* Preserve name and devPrivates */
             props[j]->type = saved[i].type;
@@ -351,7 +351,7 @@ dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
         return rc;
 
     if (sendevent)
-        deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp->propertyName);
+        deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp);
 
     return Success;
 }
@@ -380,7 +380,7 @@ DeleteProperty(ClientPtr client, WindowPtr pWin, Atom propName)
             prevProp->next = pProp->next;
         }
 
-        deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
+        deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp);
         free(pProp->data);
         dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
     }
@@ -394,7 +394,7 @@ DeleteAllWindowProperties(WindowPtr pWin)
 
     pProp = wUserProps(pWin);
     while (pProp) {
-        deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
+        deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp);
         pNextProp = pProp->next;
         free(pProp->data);
         dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
@@ -517,7 +517,7 @@ ProcGetProperty(ClientPtr client)
     };
 
     if (stuff->delete && (reply.bytesAfter == 0))
-        deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
+        deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp);
 
     WriteReplyToClient(client, sizeof(xGenericReply), &reply);
     if (len) {


More information about the xorg-commit mailing list