#include "ui/base/x/selection_requestor.h"
-#include "base/message_loop/message_pump_x11.h"
#include "base/run_loop.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/x/x11_types.h"
namespace ui {
SelectionRequestor::SelectionRequestor(Display* x_display,
Window x_window,
- Atom selection_name)
+ Atom selection_name,
+ PlatformEventDispatcher* dispatcher)
: x_display_(x_display),
x_window_(x_window),
selection_name_(selection_name),
+ dispatcher_(dispatcher),
atom_cache_(x_display_, kAtomsToCache) {
}
size_t* out_data_bytes,
size_t* out_data_items,
Atom* out_type) {
- // The name of the property we're asking to be set on |x_window_|.
- Atom property_to_set = atom_cache_.GetAtom(kChromeSelection);
+ // The name of the property that we are either:
+ // - Passing as a parameter with the XConvertSelection() request.
+ // OR
+ // - Asking the selection owner to set on |x_window_|.
+ Atom property = atom_cache_.GetAtom(kChromeSelection);
XConvertSelection(x_display_,
selection_name_,
target,
- property_to_set,
+ property,
x_window_,
CurrentTime);
// Now that we've thrown our message off to the X11 server, we block waiting
// for a response.
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
- base::RunLoop run_loop;
-
- // Stop waiting for a response after a certain amount of time.
- const int kMaxWaitTimeForClipboardResponse = 300;
- loop->PostDelayedTask(
- FROM_HERE,
- run_loop.QuitClosure(),
- base::TimeDelta::FromMilliseconds(kMaxWaitTimeForClipboardResponse));
-
- PendingRequest pending_request(target, run_loop.QuitClosure());
- pending_requests_.push_back(&pending_request);
- run_loop.Run();
- DCHECK(!pending_requests_.empty());
- DCHECK_EQ(&pending_request, pending_requests_.back());
- pending_requests_.pop_back();
+ PendingRequest pending_request(target);
+ BlockTillSelectionNotifyForRequest(&pending_request);
bool success = false;
- if (pending_request.returned_property == property_to_set) {
+ if (pending_request.returned_property == property) {
success = ui::GetRawBytesOfProperty(x_window_,
pending_request.returned_property,
out_data, out_data_bytes,
return success;
}
+void SelectionRequestor::PerformBlockingConvertSelectionWithParameter(
+ Atom target,
+ const std::vector< ::Atom>& parameter) {
+ SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter);
+ PerformBlockingConvertSelection(target, NULL, NULL, NULL, NULL);
+}
+
SelectionData SelectionRequestor::RequestAndWaitForTypes(
const std::vector< ::Atom>& types) {
for (std::vector< ::Atom>::const_iterator it = types.begin();
request_notified->returned_property = event.property;
request_notified->returned = true;
- request_notified->quit_closure.Run();
+
+ if (!request_notified->quit_closure.is_null())
+ request_notified->quit_closure.Run();
+}
+
+void SelectionRequestor::BlockTillSelectionNotifyForRequest(
+ PendingRequest* request) {
+ pending_requests_.push_back(request);
+
+ const int kMaxWaitTimeForClipboardResponse = 300;
+ if (PlatformEventSource::GetInstance()) {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
+ base::RunLoop run_loop;
+
+ request->quit_closure = run_loop.QuitClosure();
+ loop->PostDelayedTask(
+ FROM_HERE,
+ request->quit_closure,
+ base::TimeDelta::FromMilliseconds(kMaxWaitTimeForClipboardResponse));
+
+ run_loop.Run();
+ } else {
+ // This occurs if PerformBlockingConvertSelection() is called during
+ // shutdown and the PlatformEventSource has already been destroyed.
+ base::TimeTicks start = base::TimeTicks::Now();
+ while (!request->returned) {
+ if (XPending(x_display_)) {
+ XEvent event;
+ XNextEvent(x_display_, &event);
+ dispatcher_->DispatchEvent(&event);
+ }
+ base::TimeDelta wait_time = base::TimeTicks::Now() - start;
+ if (wait_time.InMilliseconds() > kMaxWaitTimeForClipboardResponse)
+ break;
+ }
+ }
+
+ DCHECK(!pending_requests_.empty());
+ DCHECK_EQ(request, pending_requests_.back());
+ pending_requests_.pop_back();
}
-SelectionRequestor::PendingRequest::PendingRequest(Atom target,
- base::Closure quit_closure)
+SelectionRequestor::PendingRequest::PendingRequest(Atom target)
: target(target),
- quit_closure(quit_closure),
returned_property(None),
returned(false) {
}