[Spice-devel] [PATCH spice 09/17] Keep track of clipboard ownership

Arnon Gilboa agilboa at redhat.com
Mon Oct 4 07:11:09 PDT 2010


Hans de Goede wrote:
> Given that all clipboard handling is async, it is possible to for
> example receive a request for clipboard data from the agent
> while the client no longer owns the clipboard (ie a
> VD_AGENT_CLIPBOARD_RELEASE message is in transit to the agent).
>
> Thus it is necessary to keep track of our notion of clipboard ownership
> and check received clipboard messages (both from other apps on the client
> machine and from the agent) to see if they match our notion and if not
> drop, or in case were a counter message is expected nack the clipboard
> message.
> ---
>  client/platform.h           |    9 +++++++++
>  client/red_client.cpp       |   37 +++++++++++++++++++++++++++++++++++++
>  client/red_client.h         |    1 +
>  client/windows/platform.cpp |   13 +++++++++++++
>  client/x11/platform.cpp     |   13 +++++++++++++
>  5 files changed, 73 insertions(+), 0 deletions(-)
>
> diff --git a/client/platform.h b/client/platform.h
> index ff6f38d..af4a0f6 100644
> --- a/client/platform.h
> +++ b/client/platform.h
> @@ -125,6 +125,14 @@ public:
>      static bool on_clipboard_notify(uint32_t type, const uint8_t* data, int32_t size);
>      static bool on_clipboard_request(uint32_t type);
>      static void on_clipboard_release();
> +
> +    enum { owner_none, owner_guest, owner_client };
> +
> +    static void set_clipboard_owner(int new_owner);
> +    static int  get_clipboard_owner() { return _clipboard_owner; }
> +
> +private:
> +    static int _clipboard_owner;
>  };
>  
>  class Platform::EventListener {
> @@ -141,6 +149,7 @@ public:
>      virtual void on_clipboard_grab(uint32_t *types, uint32_t type_count) = 0;
>      virtual void on_clipboard_request(uint32_t type) = 0;
>      virtual void on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size) = 0;
> +    virtual void on_clipboard_release() = 0;
>  };
>  
>  class Platform::RecordClient {
> diff --git a/client/red_client.cpp b/client/red_client.cpp
> index 3f01fb1..a022499 100644
> --- a/client/red_client.cpp
> +++ b/client/red_client.cpp
> @@ -85,10 +85,17 @@ void ClipboardGrabEvent::response(AbstractProcessLoop& events_loop)
>  {
>      static_cast<RedClient*>(events_loop.get_owner())->send_agent_clipboard_message(
>          VD_AGENT_CLIPBOARD_GRAB, _type_count * sizeof(uint32_t), _types);
> +    Platform::set_clipboard_owner(Platform::owner_client);
>  }
>  
>  void ClipboardRequestEvent::response(AbstractProcessLoop& events_loop)
>  {
> +    if (Platform::get_clipboard_owner() != Platform::owner_guest) {
> +        LOG_WARN("received clipboard req from client while clipboard is not owned by guest");
> +        Platform::on_clipboard_notify(VD_AGENT_CLIPBOARD_NONE, NULL, 0);
> +        return;
> +    }
> +
>      VDAgentClipboardRequest request = {_type};
>      static_cast<RedClient*>(events_loop.get_owner())->send_agent_clipboard_message(
>          VD_AGENT_CLIPBOARD_REQUEST, sizeof(request), &request);
> @@ -865,6 +872,11 @@ void RedClient::on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size)
>          DBG(0, "clipboard change is already pending");
>          return;
>      }
> +    if (Platform::get_clipboard_owner() != Platform::owner_client) {
> +        LOG_WARN("received clipboard data from client while clipboard is not owned by client");
> +        type = VD_AGENT_CLIPBOARD_NONE;
> +        size = 0;
> +    }
>      _agent_out_msg_pos = 0;
>      _agent_out_msg_size = sizeof(VDAgentMessage) + sizeof(VDAgentClipboard) + size;
>      _agent_out_msg = (VDAgentMessage*)new uint8_t[_agent_out_msg_size];
> @@ -880,6 +892,12 @@ void RedClient::on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size)
>      }
>  }
>  
> +void RedClient::on_clipboard_release()
> +{
> +    if (Platform::get_clipboard_owner() == Platform::owner_client)
> +        send_agent_clipboard_message(VD_AGENT_CLIPBOARD_RELEASE, 0, NULL);
> +}
> +
>  void RedClient::set_mouse_mode(uint32_t supported_modes, uint32_t current_mode)
>  {
>      if (current_mode != _mouse_mode) {
> @@ -1086,6 +1104,12 @@ void RedClient::dispatch_agent_message(VDAgentMessage* msg, void* data)
>          break;
>      }
>      case VD_AGENT_CLIPBOARD: {
> +        if (Platform::get_clipboard_owner() != Platform::owner_guest) {
> +            LOG_WARN("received clipboard data from guest while clipboard is not owned by guest");
> +            Platform::on_clipboard_notify(VD_AGENT_CLIPBOARD_NONE, NULL, 0);
> +            break;
> +        }
> +
>          VDAgentClipboard* clipboard = (VDAgentClipboard*)data;
>          Platform::on_clipboard_notify(clipboard->type, clipboard->data,
>                                       msg->size - sizeof(VDAgentClipboard));
> @@ -1094,14 +1118,27 @@ void RedClient::dispatch_agent_message(VDAgentMessage* msg, void* data)
>      case VD_AGENT_CLIPBOARD_GRAB:
>          Platform::on_clipboard_grab((uint32_t *)data,
>                                        msg->size / sizeof(uint32_t));
> +        Platform::set_clipboard_owner(Platform::owner_guest);
>          break;
>      case VD_AGENT_CLIPBOARD_REQUEST:
> +        if (Platform::get_clipboard_owner() != Platform::owner_client) {
> +            LOG_WARN("received clipboard req from guest while clipboard is not owned by client");
> +            on_clipboard_notify(VD_AGENT_CLIPBOARD_NONE, NULL, 0);
> +            break;
> +        }
> +
>          if (!Platform::on_clipboard_request(((VDAgentClipboardRequest*)data)->type)) {
>              on_clipboard_notify(VD_AGENT_CLIPBOARD_NONE, NULL, 0);
>          }
>          break;
>      case VD_AGENT_CLIPBOARD_RELEASE:
> +        if (Platform::get_clipboard_owner() != Platform::owner_guest) {
> +            LOG_WARN("received clipboard release from guest while clipboard is not owned by guest");
> +            break;
> +        }
> +
>          Platform::on_clipboard_release();
> +        Platform::set_clipboard_owner(Platform::owner_none);
>          break;
>      default:
>          DBG(0, "Unsupported message type %u size %u", msg->type, msg->size);
> diff --git a/client/red_client.h b/client/red_client.h
> index 2cfce49..15f0617 100644
> --- a/client/red_client.h
> +++ b/client/red_client.h
> @@ -221,6 +221,7 @@ public:
>      void on_clipboard_grab(uint32_t *types, uint32_t type_count);
>      void on_clipboard_request(uint32_t type);
>      void on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size);
> +    void on_clipboard_release();
>  
>      void for_each_channel(ForEachChannelFunc& func);
>      void on_mouse_capture_trigger(RedScreen& screen);
> diff --git a/client/windows/platform.cpp b/client/windows/platform.cpp
> index db6d18a..db47079 100644
> --- a/client/windows/platform.cpp
> +++ b/client/windows/platform.cpp
> @@ -54,6 +54,7 @@ public:
>      virtual void on_clipboard_grab(uint32_t *types, uint32_t type_count) {}
>      virtual void on_clipboard_request(uint32_t type) {}
>      virtual void on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size) {}
> +    virtual void on_clipboard_release() {}
>  };
>  
>  static DefaultClipboardListener default_clipboard_listener;
> @@ -856,6 +857,18 @@ void WinPlatform::exit_modal_loop()
>      modal_loop_active = false;
>  }
>  
> +int Platform::_clipboard_owner = Platform::owner_none;
> +
> +void Platform::set_clipboard_owner(int new_owner)
> +{
> +    if (new_owner == owner_none) {
> +        clipboard_listener->on_clipboard_release();
> +
> +        /* FIXME clear cached clipboard type info and data */
> +    }
> +    _clipboard_owner = new_owner;
> +}
> +
>  bool Platform::on_clipboard_grab(uint32_t *types, uint32_t type_count)
>  {
>      /* FIXME use all types rather then just the first one */
> diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
> index b7216eb..832374a 100644
> --- a/client/x11/platform.cpp
> +++ b/client/x11/platform.cpp
> @@ -154,6 +154,7 @@ public:
>      void on_clipboard_grab(uint32_t *types, uint32_t type_count) {}
>      void on_clipboard_request(uint32_t type) {}
>      void on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size) {}
> +    void on_clipboard_release() {}
>  };
>  
>  static DefaultClipboardListener default_clipboard_listener;
> @@ -3161,6 +3162,18 @@ bool Platform::on_clipboard_grab(uint32_t *types, uint32_t type_count)
>      return true;
>  }
>  
> +int Platform::_clipboard_owner = Platform::owner_none;
> +
> +void Platform::set_clipboard_owner(int new_owner)
> +{
> +    if (new_owner == owner_none) {
> +        clipboard_listener->on_clipboard_release();
> +
> +        /* FIXME clear cached clipboard type info and data */
> +    }
> +    _clipboard_owner = new_owner;
> +}
> +
>  void Platform::set_clipboard_listener(ClipboardListener* listener)
>  {
>      clipboard_listener = listener ? listener : &default_clipboard_listener;
>   
Ack


More information about the Spice-devel mailing list