<div dir="auto">Hi,<br>
<br>
On Sun, Mar 24, 2019 at 7:45 PM Marc-André Lureau <<a href="mailto:marcandre.lureau@gmail.com" target="_blank" rel="noreferrer">marcandre.lureau@gmail.com</a>> wrote:<br>
><br>
> Hi<br>
><br>
> On Sun, Mar 24, 2019 at 6:49 PM Jakub Janku <<a href="mailto:jjanku@redhat.com" target="_blank" rel="noreferrer">jjanku@redhat.com</a>> wrote:<br>
> ><br>
> > Hi,<br>
> ><br>
> > On Thu, Mar 21, 2019 at 1:21 PM <<a href="mailto:marcandre.lureau@redhat.com" target="_blank" rel="noreferrer">marcandre.lureau@redhat.com</a>> wrote:<br>
> > ><br>
> > > From: Marc-André Lureau <<a href="mailto:marcandre.lureau@redhat.com" target="_blank" rel="noreferrer">marcandre.lureau@redhat.com</a>><br>
> > ><br>
> > > Delay the release events for 0.5 sec. If no further grab comes in,<br>
> > > then release the grab. Otherwise, let's skip the release. This avoids<br>
> > > some races with clipboard managers.<br>
> > ><br>
> > > Related to:<br>
> > > <a href="https://gitlab.freedesktop.org/spice/spice-gtk/issues/82" rel="noreferrer noreferrer" target="_blank">https://gitlab.freedesktop.org/spice/spice-gtk/issues/82</a><br>
> > ><br>
> > > Signed-off-by: Marc-André Lureau <<a href="mailto:marcandre.lureau@redhat.com" target="_blank" rel="noreferrer">marcandre.lureau@redhat.com</a>><br>
> ><br>
> > In the 0.5 second period, any requests from apps in the client for<br>
> > clipboard data should be ignored since the vdagent can't provide the<br>
> > data any more, so we shouldn't request it.<br>
> > So I would add a condition to clipboard_get():<br>
> >     if (s->clipboard_release_delay[selection]) {<br>
> >         SPICE_DEBUG("...");<br>
> >         return;<br>
> >     }<br>
><br>
> yes, thanks<br>
><br>
> > > ---<br>
> > >  src/spice-gtk-session.c | 80 ++++++++++++++++++++++++++++++++++++-----<br>
> > >  1 file changed, 72 insertions(+), 8 deletions(-)<br>
> > ><br>
> > > diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c<br>
> > > index 0e748b6..d73a44b 100644<br>
> > > --- a/src/spice-gtk-session.c<br>
> > > +++ b/src/spice-gtk-session.c<br>
> > > @@ -59,6 +59,7 @@ struct _SpiceGtkSessionPrivate {<br>
> > >      gboolean                clip_hasdata[CLIPBOARD_LAST];<br>
> > >      gboolean                clip_grabbed[CLIPBOARD_LAST];<br>
> > >      gboolean                clipboard_by_guest[CLIPBOARD_LAST];<br>
> > > +    guint                   clipboard_release_delay[CLIPBOARD_LAST];<br>
> > >      /* auto-usbredir related */<br>
> > >      gboolean                auto_usbredir_enable;<br>
> > >      int                     auto_usbredir_reqs;<br>
> > > @@ -95,6 +96,7 @@ struct _SpiceGtkSessionPrivate {<br>
> > ><br>
> > >  /* ------------------------------------------------------------------ */<br>
> > >  /* Prototypes for private functions */<br>
> > > +static void clipboard_release(SpiceGtkSession *self, guint selection);<br>
> > >  static void clipboard_owner_change(GtkClipboard *clipboard,<br>
> > >                                     GdkEventOwnerChange *event,<br>
> > >                                     gpointer user_data);<br>
> > > @@ -247,6 +249,23 @@ static void spice_gtk_session_dispose(GObject *gobject)<br>
> > >          G_OBJECT_CLASS(spice_gtk_session_parent_class)->dispose(gobject);<br>
> > >  }<br>
> > ><br>
> > > +static void clipboard_release_delay_remove(SpiceGtkSession *self, guint selection,<br>
> > > +                                           gboolean release_if_delayed)<br>
> > > +{<br>
> > > +    SpiceGtkSessionPrivate *s = self->priv;<br>
> > > +<br>
> > > +    if (!s->clipboard_release_delay[selection])<br>
> > > +        return;<br>
> > > +<br>
> > > +    if (release_if_delayed) {<br>
> > > +        SPICE_DEBUG("delayed clipboard release, sel:%u", selection);<br>
> > > +        clipboard_release(self, selection);<br>
> > > +    }<br>
> > > +<br>
> > > +    g_source_remove(s->clipboard_release_delay[selection]);<br>
> > > +    s->clipboard_release_delay[selection] = 0;<br>
> > > +}<br>
> > > +<br>
> > >  static void spice_gtk_session_finalize(GObject *gobject)<br>
> > >  {<br>
> > >      SpiceGtkSession *self = SPICE_GTK_SESSION(gobject);<br>
> > > @@ -256,6 +275,7 @@ static void spice_gtk_session_finalize(GObject *gobject)<br>
> > >      /* release stuff */<br>
> > >      for (i = 0; i < CLIPBOARD_LAST; ++i) {<br>
> > >          g_clear_pointer(&s->clip_targets[i], g_free);<br>
> > > +        clipboard_release_delay_remove(self, i, true);<br>
> > >      }<br>
> > ><br>
> > >      /* Chain up to the parent class */<br>
> > > @@ -815,6 +835,8 @@ static gboolean clipboard_grab(SpiceMainChannel *main, guint selection,<br>
> > >      int m, n;<br>
> > >      int num_targets = 0;<br>
> > ><br>
> > > +    clipboard_release_delay_remove(self, selection, false);<br>
> > > +<br>
> > >      cb = get_clipboard_from_selection(s, selection);<br>
> > >      g_return_val_if_fail(cb != NULL, FALSE);<br>
> > ><br>
> > > @@ -1044,17 +1066,12 @@ static gboolean clipboard_request(SpiceMainChannel *main, guint selection,<br>
> > >      return TRUE;<br>
> > >  }<br>
> > ><br>
> > > -static void clipboard_release(SpiceMainChannel *main, guint selection,<br>
> > > -                              gpointer user_data)<br>
> > > +static void clipboard_release(SpiceGtkSession *self, guint selection)<br>
> > >  {<br>
> > > -    g_return_if_fail(SPICE_IS_GTK_SESSION(user_data));<br>
> > > -<br>
> > > -    SpiceGtkSession *self = user_data;<br>
> > >      SpiceGtkSessionPrivate *s = self->priv;<br>
> > >      GtkClipboard* clipboard = get_clipboard_from_selection(s, selection);<br>
> > ><br>
> > > -    if (!clipboard)<br>
> > > -        return;<br>
> > > +    g_return_if_fail(clipboard != NULL);<br>
> > ><br>
> > >      s->nclip_targets[selection] = 0;<br>
> > ><br>
> > > @@ -1064,6 +1081,53 @@ static void clipboard_release(SpiceMainChannel *main, guint selection,<br>
> > >      s->clipboard_by_guest[selection] = FALSE;<br>
> > >  }<br>
> > ><br>
> > > +typedef struct SpiceGtkClipboardRelease {<br>
> > > +    SpiceGtkSession *self;<br>
> > > +    guint selection;<br>
> > > +} SpiceGtkClipboardRelease;<br>
> > > +<br>
> > > +static gboolean clipboard_release_timeout(gpointer user_data)<br>
> > > +{<br>
> > > +    SpiceGtkClipboardRelease *rel = user_data;<br>
> > > +<br>
> > > +    clipboard_release_delay_remove(rel->self, rel->selection, true);<br>
> > > +<br>
> > > +    return G_SOURCE_REMOVE;<br>
> > > +}<br>
> > > +<br>
> > > +/*<br>
> > > + * The agents send release between two grabs. This may trigger<br>
> > > + * clipboard managers trying to grab the clipboard. We end up with two<br>
> > > + * sides, client and remote, racing for the clipboard grab, and<br>
> > > + * believing each other is the owner.<br>
> > > + *<br>
> > > + * Workaround this problem by delaying the release event by 0.5 sec.<br>
> > > + * FIXME: protocol change to solve the conflict and set client priority.<br>
> > > + */<br>
> > > +#define CLIPBOARD_RELEASE_DELAY 500 /* ms */<br>
> > > +<br>
> > > +static void clipboard_release_delay(SpiceMainChannel *main, guint selection,<br>
> > > +                                    gpointer user_data)<br>
> > > +{<br>
> > > +    SpiceGtkSession *self = SPICE_GTK_SESSION(user_data);<br>
> > > +    SpiceGtkSessionPrivate *s = self->priv;<br>
> > > +    GtkClipboard* clipboard = get_clipboard_from_selection(s, selection);<br>
> > > +    SpiceGtkClipboardRelease *rel;<br>
> > > +<br>
> > > +    if (!clipboard)<br>
> > > +        return;<br>
> > > +<br>
> > > +    clipboard_release_delay_remove(self, selection, true);<br>
> > > +<br>
> > > +    rel = g_new0(SpiceGtkClipboardRelease, 1);<br>
> > > +    rel->self = self;<br>
> > > +    rel->selection = selection;<br>
> > > +    s->clipboard_release_delay[selection] =<br>
> > > +        g_timeout_add_full(G_PRIORITY_DEFAULT, CLIPBOARD_RELEASE_DELAY,<br>
> > > +                           clipboard_release_timeout, rel, g_free);<br>
> > > +<br>
> > > +}<br>
> > > +<br>
> > >  static void channel_new(SpiceSession *session, SpiceChannel *channel,<br>
> > >                          gpointer user_data)<br>
> > >  {<br>
> > > @@ -1080,7 +1144,7 @@ static void channel_new(SpiceSession *session, SpiceChannel *channel,<br>
> > >          g_signal_connect(channel, "main-clipboard-selection-request",<br>
> > >                           G_CALLBACK(clipboard_request), self);<br>
> > >          g_signal_connect(channel, "main-clipboard-selection-release",<br>
> > > -                         G_CALLBACK(clipboard_release), self);<br>
> > > +                         G_CALLBACK(clipboard_release_delay), self);<br>
> ><br>
> > I find the naming you're introducing here rather confusing.<br>
> > I wouldn't change the signal handler name to "clipboard_release_delay".<br>
><br>
> yes, let's not rename it. With<br>
> VD_AGENT_CAP_CLIPBOARD_NO_RELEASE_ON_REGRAB implementation, it won't<br>
> be delayed either.<br>
><br>
> > What about using the word "pending" instead of "delay"?<br>
> > So:<br>
> > clipboard_release_delay --> clipboard_release_pending<br>
><br>
> Delay or pending doesn't make much difference to me.<br>
><br>
> > clipboard_release_delay_remove --> clipboard_release_pending_clear<br>
><br>
> Again I don't care much. I prefer "remove", since that's the term used<br>
> for GSources. But if you feel strongly about "clear", that works for<br>
> me too.<br>
<br>I prefer "pending" a bit more. Both "clear" and "remove" seem fine, up to you which one you use.<div dir="auto"><br></div><div dir="auto">Thanks,</div><div dir="auto">Jakub<br>
><br>
><br>
> ><br>
> > >      }<br>
> > >      if (SPICE_IS_INPUTS_CHANNEL(channel)) {<br>
> > >          spice_g_signal_connect_object(channel, "inputs-modifiers",<br>
> > > --<br>
> > > 2.21.0.4.g36eb1cb9cf<br>
> > ><br>
> > _______________________________________________<br>
> > Spice-devel mailing list<br>
> > <a href="mailto:Spice-devel@lists.freedesktop.org" target="_blank" rel="noreferrer">Spice-devel@lists.freedesktop.org</a><br>
> > <a href="https://lists.freedesktop.org/mailman/listinfo/spice-devel" rel="noreferrer noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/spice-devel</a><br>
><br>
><br>
><br>
> --<br>
> Marc-André Lureau<br></div></div>