1 // Copyright 2014 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/memory/ref_counted_memory.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "ui/base/x/selection_utils.h"
12 #include "ui/base/x/x11_util.h"
13 #include "ui/events/platform/platform_event_source.h"
14 #include "ui/gfx/x/x11_atom_cache.h"
15 #include "ui/gfx/x/x11_types.h"
23 const char* kAtomsToCache
[] = {
30 class SelectionRequestorTest
: public testing::Test
{
32 SelectionRequestorTest()
33 : x_display_(gfx::GetXDisplay()),
35 atom_cache_(gfx::GetXDisplay(), kAtomsToCache
) {
36 atom_cache_
.allow_uncached_atoms();
39 ~SelectionRequestorTest() override
{}
41 // Responds to the SelectionRequestor's XConvertSelection() request by
42 // - Setting the property passed into the XConvertSelection() request to
44 // - Sending a SelectionNotify event.
45 void SendSelectionNotify(XAtom selection
,
47 const std::string
& value
) {
48 ui::SetStringProperty(x_window_
,
49 requestor_
->x_property_
,
50 atom_cache_
.GetAtom("STRING"),
54 xev
.type
= SelectionNotify
;
55 xev
.xselection
.serial
= 0u;
56 xev
.xselection
.display
= x_display_
;
57 xev
.xselection
.requestor
= x_window_
;
58 xev
.xselection
.selection
= selection
;
59 xev
.xselection
.target
= target
;
60 xev
.xselection
.property
= requestor_
->x_property_
;
61 xev
.xselection
.time
= CurrentTime
;
62 xev
.xselection
.type
= SelectionNotify
;
63 requestor_
->OnSelectionNotify(xev
);
67 void SetUp() override
{
68 // Make X11 synchronous for our display connection.
69 XSynchronize(x_display_
, True
);
71 // Create a window for the selection requestor to use.
72 x_window_
= XCreateWindow(x_display_
,
73 DefaultRootWindow(x_display_
),
74 0, 0, 10, 10, // x, y, width, height
76 CopyFromParent
, // depth
78 CopyFromParent
, // visual
82 event_source_
= ui::PlatformEventSource::CreateDefault();
83 CHECK(ui::PlatformEventSource::GetInstance());
84 requestor_
.reset(new SelectionRequestor(x_display_
, x_window_
, NULL
));
87 void TearDown() override
{
89 event_source_
.reset();
90 XDestroyWindow(x_display_
, x_window_
);
91 XSynchronize(x_display_
, False
);
96 // |requestor_|'s window.
99 scoped_ptr
<ui::PlatformEventSource
> event_source_
;
100 scoped_ptr
<SelectionRequestor
> requestor_
;
102 base::MessageLoopForUI message_loop_
;
103 X11AtomCache atom_cache_
;
106 DISALLOW_COPY_AND_ASSIGN(SelectionRequestorTest
);
111 // Converts |selection| to |target| and checks the returned values.
112 void PerformBlockingConvertSelection(SelectionRequestor
* requestor
,
113 X11AtomCache
* atom_cache
,
116 const std::string
& expected_data
) {
117 scoped_refptr
<base::RefCountedMemory
> out_data
;
118 size_t out_data_items
= 0u;
119 XAtom out_type
= None
;
120 EXPECT_TRUE(requestor
->PerformBlockingConvertSelection(
121 selection
, target
, &out_data
, &out_data_items
, &out_type
));
122 EXPECT_EQ(expected_data
, ui::RefCountedMemoryToString(out_data
));
123 EXPECT_EQ(expected_data
.size(), out_data_items
);
124 EXPECT_EQ(atom_cache
->GetAtom("STRING"), out_type
);
129 // Test that SelectionRequestor correctly handles receiving a request while it
130 // is processing another request.
131 TEST_F(SelectionRequestorTest
, NestedRequests
) {
132 // Assume that |selection| will have no owner. If there is an owner, the owner
133 // will set the property passed into the XConvertSelection() request which is
135 XAtom selection
= atom_cache_
.GetAtom("FAKE_SELECTION");
137 XAtom target1
= atom_cache_
.GetAtom("TARGET1");
138 XAtom target2
= atom_cache_
.GetAtom("TARGET2");
140 base::MessageLoopForUI
* loop
= base::MessageLoopForUI::current();
141 loop
->PostTask(FROM_HERE
,
142 base::Bind(&PerformBlockingConvertSelection
,
143 base::Unretained(requestor_
.get()),
144 base::Unretained(&atom_cache_
),
148 loop
->PostTask(FROM_HERE
,
149 base::Bind(&SelectionRequestorTest::SendSelectionNotify
,
150 base::Unretained(this),
154 loop
->PostTask(FROM_HERE
,
155 base::Bind(&SelectionRequestorTest::SendSelectionNotify
,
156 base::Unretained(this),
160 PerformBlockingConvertSelection(
161 requestor_
.get(), &atom_cache_
, selection
, target1
, "Data1");