Commit 19ff5882 authored by Daichi Hirono's avatar Daichi Hirono Committed by Commit Bot

Handle selection data source comes from clients.

The CL partially implements the data flow of setting clipboard data from
exo clients.

 1. DataDevice receives a selection event with DataSource from the client
 2. Seat requests DataSource for bytes, updates the clipboard with
    obtained bytes, and keeps holding DataSource instance to cancel it when
    new clipboard data is set.

Follwing CL implements the DataSource part which actually reads bytes
from FD.

Bug: 773978
Test: exo_unittests
Change-Id: I0cde5755dd1ecd28d24a5b17f90590b9a70d4773
Reviewed-on: https://chromium-review.googlesource.com/792410
Commit-Queue: Daichi Hirono <hirono@chromium.org>
Reviewed-by: default avatarDavid Reveman <reveman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#520420}
parent a71cc8fd
......@@ -20,6 +20,7 @@ source_set("exo") {
"data_source.cc",
"data_source.h",
"data_source_delegate.h",
"data_source_observer.h",
"display.cc",
"display.h",
"gaming_seat.cc",
......
......@@ -77,9 +77,9 @@ void DataDevice::StartDrag(const DataSource* source_resource,
NOTIMPLEMENTED();
}
void DataDevice::SetSelection(const DataSource* source, uint32_t serial) {
void DataDevice::SetSelection(DataSource* source, uint32_t serial) {
// TODO(hirono): Check if serial is valid. crbug.com/746111
NOTIMPLEMENTED();
seat_->SetSelection(source);
}
void DataDevice::OnDragEntered(const ui::DropTargetEvent& event) {
......@@ -148,7 +148,7 @@ int DataDevice::OnPerformDrop(const ui::DropTargetEvent& event) {
void DataDevice::OnClipboardDataChanged() {
if (!focused_surface_)
return;
SendSelection();
SetSelectionToCurrentClipboardData();
}
void DataDevice::OnSurfaceFocusing(Surface* surface) {
......@@ -167,7 +167,7 @@ void DataDevice::OnSurfaceFocusing(Surface* surface) {
// Check if the client newly obtained focus.
if (focused_surface_ && !last_focused_surface)
SendSelection();
SetSelectionToCurrentClipboardData();
}
void DataDevice::OnSurfaceFocused(Surface* surface) {}
......@@ -194,7 +194,7 @@ Surface* DataDevice::GetEffectiveTargetForEvent(
return delegate_->CanAcceptDataEventsForSurface(target) ? target : nullptr;
}
void DataDevice::SendSelection() {
void DataDevice::SetSelectionToCurrentClipboardData() {
DataOffer* data_offer = delegate_->OnDataOffer();
data_offer->SetClipboardData(file_helper_,
*ui::Clipboard::GetForCurrentThread());
......
......@@ -59,7 +59,7 @@ class DataDevice : public WMHelper::DragDropObserver,
// Sets selection data to the clipboard.
// |source| represents data comes from the client. |serial| is the unique
// number comes from input events which triggers the drag and drop operation.
void SetSelection(const DataSource* source, uint32_t serial);
void SetSelection(DataSource* source, uint32_t serial);
// Overridden from WMHelper::DragDropObserver:
void OnDragEntered(const ui::DropTargetEvent& event) override;
......@@ -82,7 +82,7 @@ class DataDevice : public WMHelper::DragDropObserver,
private:
Surface* GetEffectiveTargetForEvent(const ui::DropTargetEvent& event) const;
void SendSelection();
void SetSelectionToCurrentClipboardData();
DataDeviceDelegate* const delegate_;
Seat* const seat_;
......
......@@ -5,13 +5,35 @@
#include "components/exo/data_source.h"
#include "components/exo/data_source_delegate.h"
#include "components/exo/data_source_observer.h"
namespace exo {
ScopedDataSource::ScopedDataSource(DataSource* data_source,
DataSourceObserver* observer)
: data_source_(data_source), observer_(observer) {
data_source_->AddObserver(observer_);
}
ScopedDataSource::~ScopedDataSource() {
data_source_->RemoveObserver(observer_);
}
DataSource::DataSource(DataSourceDelegate* delegate) : delegate_(delegate) {}
DataSource::~DataSource() {
delegate_->OnDataSourceDestroying(this);
for (DataSourceObserver& observer : observers_) {
observer.OnDataSourceDestroying(this);
}
}
void DataSource::AddObserver(DataSourceObserver* observer) {
observers_.AddObserver(observer);
}
void DataSource::RemoveObserver(DataSourceObserver* observer) {
observers_.RemoveObserver(observer);
}
void DataSource::Offer(const std::string& mime_type) {
......@@ -22,4 +44,12 @@ void DataSource::SetActions(const base::flat_set<DndAction>& dnd_actions) {
NOTIMPLEMENTED();
}
void DataSource::Cancelled() {
NOTIMPLEMENTED();
}
void DataSource::ReadData(ReadDataCallback callback) {
NOTIMPLEMENTED();
}
} // namespace exo
......@@ -7,12 +7,15 @@
#include <string>
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/observer_list.h"
namespace exo {
class DataSourceDelegate;
class DataSourceObserver;
enum class DndAction;
// Object representing transferred data offered by a client.
......@@ -21,6 +24,9 @@ class DataSource {
explicit DataSource(DataSourceDelegate* delegate);
~DataSource();
void AddObserver(DataSourceObserver* observer);
void RemoveObserver(DataSourceObserver* observer);
// Notifies to DataSource that the client offers new mime type.
void Offer(const std::string& mime_type);
......@@ -28,12 +34,37 @@ class DataSource {
// DataSource.
void SetActions(const base::flat_set<DndAction>& dnd_actions);
// Notifies the data source is cancelled. e.g. Replaced with another data
// source.
void Cancelled();
// Reads data from the source. Then |callback| is invoked with read
// data. If Cancelled() is invoked or DataSource is destroyed before
// completion, the callback is never called.
using ReadDataCallback =
base::OnceCallback<void(const std::vector<uint8_t>&)>;
void ReadData(ReadDataCallback callback);
private:
DataSourceDelegate* const delegate_;
base::ObserverList<DataSourceObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(DataSource);
};
class ScopedDataSource {
public:
ScopedDataSource(DataSource* data_source, DataSourceObserver* observer);
~ScopedDataSource();
DataSource* get() { return data_source_; }
private:
DataSource* const data_source_;
DataSourceObserver* const observer_;
DISALLOW_COPY_AND_ASSIGN(ScopedDataSource);
};
} // namespace exo
#endif // COMPONENTS_EXO_DATA_SOURCE_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_EXO_DATA_SOURCE_OBSERVER_H_
#define COMPONENTS_EXO_DATA_SOURCE_OBSERVER_H_
#include <string>
namespace exo {
class DataSource;
// Handles events on data devices in context-specific ways.
class DataSourceObserver {
public:
// Called at the top of the data device's destructor, to give observers a
// chance to remove themselves.
virtual void OnDataSourceDestroying(DataSource* source) = 0;
protected:
virtual ~DataSourceObserver() {}
};
} // namespace exo
#endif // COMPONENTS_EXO_DATA_SOURCE_OBSERVER_H_
......@@ -5,11 +5,16 @@
#include "components/exo/seat.h"
#include "ash/shell.h"
#include "base/auto_reset.h"
#include "base/strings/utf_string_conversions.h"
#include "components/exo/data_source.h"
#include "components/exo/keyboard.h"
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
#include "components/exo/wm_helper.h"
#include "ui/aura/client/focus_client.h"
#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
namespace exo {
namespace {
......@@ -29,16 +34,19 @@ Surface* GetEffectiveFocus(aura::Window* window) {
} // namespace
Seat::Seat() {
Seat::Seat() : changing_clipboard_data_to_selection_source_(false) {
aura::client::GetFocusClient(ash::Shell::Get()->GetPrimaryRootWindow())
->AddObserver(this);
WMHelper::GetInstance()->AddPreTargetHandler(this);
ui::ClipboardMonitor::GetInstance()->AddObserver(this);
}
Seat::~Seat() {
DCHECK(!selection_source_) << "DataSource must be released before Seat";
aura::client::GetFocusClient(ash::Shell::Get()->GetPrimaryRootWindow())
->RemoveObserver(this);
WMHelper::GetInstance()->RemovePreTargetHandler(this);
ui::ClipboardMonitor::GetInstance()->RemoveObserver(this);
}
void Seat::AddObserver(SeatObserver* observer) {
......@@ -53,6 +61,30 @@ Surface* Seat::GetFocusedSurface() {
return GetEffectiveFocus(WMHelper::GetInstance()->GetFocusedWindow());
}
void Seat::SetSelection(DataSource* source) {
DCHECK(source);
if (selection_source_) {
if (selection_source_->get() == source)
return;
selection_source_->get()->Cancelled();
}
selection_source_ = std::make_unique<ScopedDataSource>(source, this);
// Unretained is safe as Seat always outlives DataSource.
source->ReadData(base::Bind(&Seat::OnDataRead, base::Unretained(this)));
}
void Seat::OnDataRead(const std::vector<uint8_t>& data) {
base::AutoReset<bool> auto_reset(
&changing_clipboard_data_to_selection_source_, true);
ui::ScopedClipboardWriter writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
writer.WriteText(base::UTF8ToUTF16(base::StringPiece(
reinterpret_cast<const char*>(data.data()), data.size())));
}
////////////////////////////////////////////////////////////////////////////////
// aura::client::FocusChangeObserver overrides:
......@@ -84,4 +116,22 @@ void Seat::OnKeyEvent(ui::KeyEvent* event) {
}
}
////////////////////////////////////////////////////////////////////////////////
// ui::ClipboardObserver overrides:
void Seat::OnClipboardDataChanged() {
if (!selection_source_ || changing_clipboard_data_to_selection_source_)
return;
selection_source_->get()->Cancelled();
selection_source_.reset();
}
////////////////////////////////////////////////////////////////////////////////
// DataSourceObserver overrides:
void Seat::OnDataSourceDestroying(DataSource* source) {
if (selection_source_ && selection_source_->get() == source)
selection_source_.reset();
}
} // namespace exo
......@@ -6,9 +6,12 @@
#define COMPONENTS_EXO_SEAT_H_
#include "base/containers/flat_set.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "components/exo/data_source_observer.h"
#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/client/focus_change_observer.h"
#include "ui/base/clipboard/clipboard_observer.h"
#include "ui/events/event_handler.h"
namespace ui {
......@@ -17,12 +20,16 @@ class KeyEvent;
} // namespace ui
namespace exo {
class ScopedDataSource;
class SeatObserver;
class Surface;
// Seat object represent a group of input devices such as keyboard, pointer and
// touch devices and keeps track of input focus.
class Seat : public aura::client::FocusChangeObserver, public ui::EventHandler {
class Seat : public aura::client::FocusChangeObserver,
public ui::EventHandler,
public ui::ClipboardObserver,
public DataSourceObserver {
public:
Seat();
~Seat() override;
......@@ -39,6 +46,9 @@ class Seat : public aura::client::FocusChangeObserver, public ui::EventHandler {
return pressed_keys_;
}
// Sets clipboard data from |source|.
void SetSelection(DataSource* source);
// Overridden from aura::client::FocusChangeObserver:
void OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) override;
......@@ -46,10 +56,27 @@ class Seat : public aura::client::FocusChangeObserver, public ui::EventHandler {
// Overridden from ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
// Overridden from ui::ClipboardObserver:
void OnClipboardDataChanged() override;
// Overridden from DataSourceObserver:
void OnDataSourceDestroying(DataSource* source) override;
private:
// Called when data is read from FD passed from a client.
// |data| is read data. |source| is source of the data, or nullptr if
// DataSource has already been destroyed.
void OnDataRead(const std::vector<uint8_t>& data);
base::ObserverList<SeatObserver> observers_;
base::flat_set<ui::DomCode> pressed_keys_;
// Data source being used as a clipboard content.
std::unique_ptr<ScopedDataSource> selection_source_;
// True while Seat is updating clipboard data to selection source.
bool changing_clipboard_data_to_selection_source_;
DISALLOW_COPY_AND_ASSIGN(Seat);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment