Implementing the dispatch of the swipe gesture for one-finger touch swipes.
[chromium-blink-merge.git] / ui / base / x / selection_requestor.cc
bloba946787d355feb5b4fea1ab5d4f5c4bd2fd41d02
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/base/x/selection_requestor.h"
7 #include "base/run_loop.h"
8 #include "ui/base/x/selection_utils.h"
9 #include "ui/base/x/x11_util.h"
10 #include "ui/events/platform/platform_event_dispatcher.h"
11 #include "ui/events/platform/platform_event_source.h"
12 #include "ui/gfx/x/x11_types.h"
14 namespace ui {
16 namespace {
18 const char kChromeSelection[] = "CHROME_SELECTION";
20 const char* kAtomsToCache[] = {
21 kChromeSelection,
22 NULL
25 } // namespace
27 SelectionRequestor::SelectionRequestor(Display* x_display,
28 Window x_window,
29 Atom selection_name,
30 PlatformEventDispatcher* dispatcher)
31 : x_display_(x_display),
32 x_window_(x_window),
33 selection_name_(selection_name),
34 dispatcher_(dispatcher),
35 atom_cache_(x_display_, kAtomsToCache) {
38 SelectionRequestor::~SelectionRequestor() {}
40 bool SelectionRequestor::PerformBlockingConvertSelection(
41 Atom target,
42 scoped_refptr<base::RefCountedMemory>* out_data,
43 size_t* out_data_bytes,
44 size_t* out_data_items,
45 Atom* out_type) {
46 // The name of the property that we are either:
47 // - Passing as a parameter with the XConvertSelection() request.
48 // OR
49 // - Asking the selection owner to set on |x_window_|.
50 Atom property = atom_cache_.GetAtom(kChromeSelection);
52 XConvertSelection(x_display_,
53 selection_name_,
54 target,
55 property,
56 x_window_,
57 CurrentTime);
59 // Now that we've thrown our message off to the X11 server, we block waiting
60 // for a response.
61 PendingRequest pending_request(target);
62 BlockTillSelectionNotifyForRequest(&pending_request);
64 bool success = false;
65 if (pending_request.returned_property == property) {
66 success = ui::GetRawBytesOfProperty(x_window_,
67 pending_request.returned_property,
68 out_data, out_data_bytes,
69 out_data_items, out_type);
71 if (pending_request.returned_property != None)
72 XDeleteProperty(x_display_, x_window_, pending_request.returned_property);
73 return success;
76 void SelectionRequestor::PerformBlockingConvertSelectionWithParameter(
77 Atom target,
78 const std::vector< ::Atom>& parameter) {
79 SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter);
80 PerformBlockingConvertSelection(target, NULL, NULL, NULL, NULL);
83 SelectionData SelectionRequestor::RequestAndWaitForTypes(
84 const std::vector< ::Atom>& types) {
85 for (std::vector< ::Atom>::const_iterator it = types.begin();
86 it != types.end(); ++it) {
87 scoped_refptr<base::RefCountedMemory> data;
88 size_t data_bytes = 0;
89 ::Atom type = None;
90 if (PerformBlockingConvertSelection(*it,
91 &data,
92 &data_bytes,
93 NULL,
94 &type) &&
95 type == *it) {
96 return SelectionData(type, data);
100 return SelectionData();
103 void SelectionRequestor::OnSelectionNotify(const XSelectionEvent& event) {
104 // Find the PendingRequest for the corresponding XConvertSelection call. If
105 // there are multiple pending requests on the same target, satisfy them in
106 // FIFO order.
107 PendingRequest* request_notified = NULL;
108 if (selection_name_ == event.selection) {
109 for (std::list<PendingRequest*>::iterator iter = pending_requests_.begin();
110 iter != pending_requests_.end(); ++iter) {
111 PendingRequest* request = *iter;
112 if (request->returned)
113 continue;
114 if (request->target != event.target)
115 continue;
116 request_notified = request;
117 break;
121 // This event doesn't correspond to any XConvertSelection calls that we
122 // issued in PerformBlockingConvertSelection. This shouldn't happen, but any
123 // client can send any message, so it can happen.
124 if (!request_notified) {
125 // ICCCM requires us to delete the property passed into SelectionNotify. If
126 // |request_notified| is true, the property will be deleted when the run
127 // loop has quit.
128 if (event.property != None)
129 XDeleteProperty(x_display_, x_window_, event.property);
130 return;
133 request_notified->returned_property = event.property;
134 request_notified->returned = true;
136 if (!request_notified->quit_closure.is_null())
137 request_notified->quit_closure.Run();
140 void SelectionRequestor::BlockTillSelectionNotifyForRequest(
141 PendingRequest* request) {
142 pending_requests_.push_back(request);
144 const int kMaxWaitTimeForClipboardResponse = 300;
145 if (PlatformEventSource::GetInstance()) {
146 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
147 base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
148 base::RunLoop run_loop;
150 request->quit_closure = run_loop.QuitClosure();
151 loop->PostDelayedTask(
152 FROM_HERE,
153 request->quit_closure,
154 base::TimeDelta::FromMilliseconds(kMaxWaitTimeForClipboardResponse));
156 run_loop.Run();
157 } else {
158 // This occurs if PerformBlockingConvertSelection() is called during
159 // shutdown and the PlatformEventSource has already been destroyed.
160 base::TimeTicks start = base::TimeTicks::Now();
161 while (!request->returned) {
162 if (XPending(x_display_)) {
163 XEvent event;
164 XNextEvent(x_display_, &event);
165 dispatcher_->DispatchEvent(&event);
167 base::TimeDelta wait_time = base::TimeTicks::Now() - start;
168 if (wait_time.InMilliseconds() > kMaxWaitTimeForClipboardResponse)
169 break;
173 DCHECK(!pending_requests_.empty());
174 DCHECK_EQ(request, pending_requests_.back());
175 pending_requests_.pop_back();
178 SelectionRequestor::PendingRequest::PendingRequest(Atom target)
179 : target(target),
180 returned_property(None),
181 returned(false) {
184 SelectionRequestor::PendingRequest::~PendingRequest() {
187 } // namespace ui