OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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. | |
4 | |
5 #include "ui/ozone/platform/wayland/fake_server.h" | |
6 | |
7 #include <sys/socket.h> | |
8 #include <wayland-server.h> | |
9 #include <xdg-shell-unstable-v5-server-protocol.h> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/files/scoped_file.h" | |
13 | |
14 namespace wl { | |
15 namespace { | |
16 | |
17 template <class T> | |
18 void Delete(wl_resource* resource) { | |
spang
2016/02/10 18:58:29
DeleteResourceData?
| |
19 delete static_cast<T*>(wl_resource_get_user_data(resource)); | |
20 } | |
21 | |
22 void DestroyResource(wl_client* client, wl_resource* resource) { | |
23 wl_resource_destroy(resource); | |
24 } | |
25 | |
26 // wl_surface | |
27 | |
28 void Attach(wl_client* client, | |
29 wl_resource* resource, | |
30 wl_resource* buffer_resource, | |
31 int32_t x, | |
32 int32_t y) { | |
33 auto obj = static_cast<FakeSurface*>(wl_resource_get_user_data(resource)); | |
34 if (obj->mock) | |
35 obj->mock->Attach(buffer_resource, x, y); | |
36 } | |
37 | |
38 void Damage(wl_client* client, | |
39 wl_resource* resource, | |
40 int32_t x, | |
41 int32_t y, | |
42 int32_t width, | |
43 int32_t height) { | |
44 auto obj = static_cast<FakeSurface*>(wl_resource_get_user_data(resource)); | |
45 if (obj->mock) | |
46 obj->mock->Damage(x, y, width, height); | |
47 } | |
48 | |
49 void Commit(wl_client* client, wl_resource* resource) { | |
50 auto obj = static_cast<FakeSurface*>(wl_resource_get_user_data(resource)); | |
51 if (obj->mock) | |
52 obj->mock->Commit(); | |
53 } | |
54 | |
55 const struct wl_surface_interface surface_impl = { | |
56 &DestroyResource, &Attach, &Damage, | |
spang
2016/02/10 18:58:29
Can you annotate all of them for consistency?
Michael Forney
2016/02/11 03:38:09
Done.
| |
57 nullptr, // frame | |
58 nullptr, // set_opaque_region | |
59 nullptr, // set_input_region | |
60 &Commit, | |
61 nullptr, // set_buffer_transform | |
62 nullptr, // set_buffer_scale | |
63 }; | |
64 | |
65 // wl_compositor | |
66 | |
67 void CreateSurface(wl_client* client, wl_resource* resource, uint32_t id) { | |
68 wl_resource* surface_resource = | |
69 wl_resource_create(client, &wl_surface_interface, 4, id); | |
spang
2016/02/10 18:58:28
What is 4? Maybe do
static const int kWhatIsF
Michael Forney
2016/02/11 03:38:09
Done.
| |
70 if (!surface_resource) { | |
71 wl_client_post_no_memory(client); | |
72 return; | |
73 } | |
74 wl_resource_set_implementation(surface_resource, &surface_impl, | |
75 new FakeSurface(surface_resource), | |
76 &Delete<FakeSurface>); | |
77 } | |
78 | |
79 const struct wl_compositor_interface compositor_impl = { | |
80 &CreateSurface, | |
81 nullptr, // create_region | |
82 }; | |
83 | |
84 // xdg_surface | |
85 | |
86 void SetTitle(wl_client* client, wl_resource* resource, const char* title) { | |
87 auto obj = static_cast<FakeXdgSurface*>(wl_resource_get_user_data(resource)); | |
88 if (obj->mock) | |
spang
2016/02/10 18:58:29
When is this false?
Michael Forney
2016/02/11 03:38:09
It could be NULL if the implementation makes a req
spang
2016/02/11 16:54:48
Wouldn't forgetting to set the mock immediately be
Michael Forney
2016/02/12 00:49:58
The client essentially owns the server-side FakeSu
| |
89 obj->mock->SetTitle(title); | |
90 } | |
91 | |
92 void SetAppId(wl_client* client, wl_resource* resource, const char* app_id) { | |
93 auto obj = static_cast<FakeXdgSurface*>(wl_resource_get_user_data(resource)); | |
94 if (obj->mock) | |
95 obj->mock->SetAppId(app_id); | |
96 } | |
97 | |
98 void AckConfigure(wl_client* client, wl_resource* resource, uint32_t serial) { | |
99 auto obj = static_cast<FakeXdgSurface*>(wl_resource_get_user_data(resource)); | |
100 if (obj->mock) | |
101 obj->mock->AckConfigure(serial); | |
102 } | |
103 | |
104 void SetMaximized(wl_client* client, wl_resource* resource) { | |
105 auto obj = static_cast<FakeXdgSurface*>(wl_resource_get_user_data(resource)); | |
106 if (obj->mock) | |
107 obj->mock->SetMaximized(); | |
108 } | |
109 | |
110 void UnsetMaximized(wl_client* client, wl_resource* resource) { | |
111 auto obj = static_cast<FakeXdgSurface*>(wl_resource_get_user_data(resource)); | |
112 if (obj->mock) | |
113 obj->mock->UnsetMaximized(); | |
114 } | |
115 | |
116 void SetMinimized(wl_client* client, wl_resource* resource) { | |
117 auto obj = static_cast<FakeXdgSurface*>(wl_resource_get_user_data(resource)); | |
118 if (obj->mock) | |
119 obj->mock->SetMinimized(); | |
120 } | |
121 | |
122 const struct xdg_surface_interface xdg_surface_impl = { | |
123 &DestroyResource, | |
124 nullptr, // set_parent | |
125 &SetTitle, &SetAppId, | |
126 nullptr, // show_window_menu | |
127 nullptr, // move | |
128 nullptr, // resize | |
129 &AckConfigure, | |
130 nullptr, // set_window_geometry | |
131 &SetMaximized, &UnsetMaximized, | |
132 nullptr, // set_fullscreen | |
133 nullptr, // unset_fullscreen | |
134 &SetMinimized, | |
135 }; | |
136 | |
137 // xdg_shell | |
138 | |
139 void UseUnstableVersion(wl_client* client, | |
140 wl_resource* resource, | |
141 int32_t version) { | |
142 auto mock = static_cast<MockXdgShell*>(wl_resource_get_user_data(resource)); | |
143 if (mock) | |
144 mock->UseUnstableVersion(version); | |
145 } | |
146 | |
147 void GetXdgSurface(wl_client* client, | |
148 wl_resource* resource, | |
149 uint32_t id, | |
150 wl_resource* surface_resource) { | |
151 auto surface = | |
152 static_cast<FakeSurface*>(wl_resource_get_user_data(surface_resource)); | |
153 if (surface->xdg_surface) { | |
154 wl_resource_post_error(resource, XDG_SHELL_ERROR_ROLE, | |
155 "surface already has a role"); | |
156 return; | |
157 } | |
158 wl_resource* xdg_surface_resource = | |
159 wl_resource_create(client, &xdg_surface_interface, 1, id); | |
160 if (!xdg_surface_resource) { | |
161 wl_client_post_no_memory(client); | |
162 return; | |
163 } | |
164 wl_resource_set_implementation( | |
165 xdg_surface_resource, &xdg_surface_impl, | |
166 new FakeXdgSurface(xdg_surface_resource, surface), | |
167 &Delete<FakeXdgSurface>); | |
168 } | |
169 | |
170 void Pong(wl_client* client, wl_resource* resource, uint32_t serial) { | |
171 auto mock = static_cast<MockXdgShell*>(wl_resource_get_user_data(resource)); | |
172 if (mock) | |
173 mock->Pong(serial); | |
174 } | |
175 | |
176 const struct xdg_shell_interface xdg_shell_impl = { | |
177 &DestroyResource, | |
178 &UseUnstableVersion, | |
179 &GetXdgSurface, | |
180 nullptr, // get_xdg_popup | |
181 &Pong, | |
182 }; | |
183 | |
184 } // namespace | |
185 | |
186 MockSurface::MockSurface() {} | |
187 | |
188 MockSurface::~MockSurface() {} | |
189 | |
190 MockXdgShell::MockXdgShell() {} | |
191 | |
192 MockXdgShell::~MockXdgShell() {} | |
193 | |
194 MockXdgSurface::MockXdgSurface() {} | |
195 | |
196 MockXdgSurface::~MockXdgSurface() {} | |
197 | |
198 FakeSurface::FakeSurface(wl_resource* resource) : resource(resource) {} | |
199 | |
200 FakeSurface::~FakeSurface() { | |
201 if (xdg_surface) | |
202 wl_resource_destroy(xdg_surface->resource); | |
203 } | |
204 | |
205 // static | |
206 FakeSurface* FakeSurface::FromResource(wl_resource* resource) { | |
207 if (!wl_resource_instance_of(resource, &wl_surface_interface, &surface_impl)) | |
208 return nullptr; | |
209 return static_cast<FakeSurface*>(wl_resource_get_user_data(resource)); | |
210 } | |
211 | |
212 FakeXdgSurface::FakeXdgSurface(wl_resource* resource, FakeSurface* surface) | |
213 : resource(resource), surface(surface) { | |
214 surface->xdg_surface = this; | |
215 } | |
216 | |
217 FakeXdgSurface::~FakeXdgSurface() { | |
218 surface->xdg_surface = nullptr; | |
219 } | |
220 | |
221 void GlobalDeleter::operator()(wl_global* global) { | |
222 wl_global_destroy(global); | |
223 } | |
224 | |
225 Global::Global(const wl_interface* interface, | |
226 const void* implementation, | |
227 uint32_t version, | |
228 void* data) | |
229 : interface_(interface), | |
230 implementation_(implementation), | |
231 version_(version), | |
232 data_(data) {} | |
233 | |
234 Global::~Global() {} | |
235 | |
236 bool Global::Initialize(wl_display* display) { | |
237 global_.reset(wl_global_create(display, interface_, version_, this, &Bind)); | |
238 return global_; | |
239 } | |
240 | |
241 // static | |
242 void Global::Bind(wl_client* client, | |
243 void* data, | |
244 uint32_t version, | |
245 uint32_t id) { | |
246 auto global = static_cast<Global*>(data); | |
247 wl_resource* resource = | |
248 wl_resource_create(client, global->interface_, global->version_, id); | |
249 if (!resource) { | |
250 wl_client_post_no_memory(client); | |
251 return; | |
252 } | |
253 if (!global->resource_) | |
254 global->resource_ = resource; | |
255 wl_resource_set_implementation(resource, global->implementation_, | |
256 global->data_, nullptr); | |
257 } | |
258 | |
259 void DisplayDeleter::operator()(wl_display* display) { | |
260 wl_display_destroy(display); | |
261 } | |
262 | |
263 FakeServer::FakeServer(MockXdgShell* xdg_shell_mock) | |
264 : Thread("fake_wayland_server"), | |
265 compositor_(&wl_compositor_interface, &compositor_impl, 4, nullptr), | |
266 xdg_shell_(&xdg_shell_interface, &xdg_shell_impl, 1, xdg_shell_mock) {} | |
267 | |
268 FakeServer::~FakeServer() { | |
269 Stop(); | |
270 } | |
271 | |
272 bool FakeServer::Start() { | |
273 display_.reset(wl_display_create()); | |
274 if (!display_) | |
275 return false; | |
276 event_loop_ = wl_display_get_event_loop(display_.get()); | |
277 | |
278 int fd[2]; | |
279 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fd) < 0) | |
280 return false; | |
281 base::ScopedFD server_fd(fd[0]); | |
282 base::ScopedFD client_fd(fd[1]); | |
283 | |
284 if (wl_display_init_shm(display_.get()) < 0) | |
285 return false; | |
286 if (!compositor_.Initialize(display_.get())) | |
287 return false; | |
288 if (!xdg_shell_.Initialize(display_.get())) | |
289 return false; | |
290 | |
291 client_ = wl_client_create(display_.get(), server_fd.get()); | |
292 if (!client_) | |
293 return false; | |
294 (void)server_fd.release(); | |
295 | |
296 base::Thread::Options options; | |
297 options.message_pump_factory = | |
298 base::Bind(&FakeServer::CreateMessagePump, base::Unretained(this)); | |
299 if (!base::Thread::StartWithOptions(options)) | |
300 return false; | |
301 | |
302 setenv("WAYLAND_SOCKET", std::to_string(client_fd.release()).c_str(), 1); | |
spang
2016/02/10 18:58:29
std::to_string not allowed yet
See https://chromi
Michael Forney
2016/02/11 03:38:09
Done.
| |
303 | |
304 return true; | |
305 } | |
306 | |
307 void FakeServer::Flush() { | |
308 wl_display_flush_clients(display_.get()); | |
309 } | |
310 | |
311 scoped_ptr<base::MessagePump> FakeServer::CreateMessagePump() { | |
312 auto pump = make_scoped_ptr(new base::MessagePumpLibevent); | |
313 pump->WatchFileDescriptor(wl_event_loop_get_fd(event_loop_), true, | |
314 base::MessagePumpLibevent::WATCH_READ, &controller_, | |
315 this); | |
316 return std::move(pump); | |
317 } | |
318 | |
319 void FakeServer::OnFileCanReadWithoutBlocking(int fd) { | |
320 wl_event_loop_dispatch(event_loop_, 0); | |
321 wl_display_flush_clients(display_.get()); | |
322 } | |
323 | |
324 void FakeServer::OnFileCanWriteWithoutBlocking(int fd) {} | |
325 | |
326 } // namespace wl | |
OLD | NEW |