1 // Copyright 2018 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 "components/exo/wayland/zxdg_shell.h"
6
7 #include <wayland-server-core.h>
8 #include <wayland-server-protocol-core.h>
9 #include <xdg-shell-unstable-v6-server-protocol.h>
10
11 #include "ash/public/cpp/shell_window_ids.h"
12 #include "ash/public/cpp/window_properties.h"
13 #include "ash/public/cpp/window_state_type.h"
14 #include "base/bind.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "components/exo/display.h"
17 #include "components/exo/wayland/serial_tracker.h"
18 #include "components/exo/wayland/server_util.h"
19 #include "components/exo/wayland/wayland_positioner.h"
20 #include "components/exo/xdg_shell_surface.h"
21 #include "ui/aura/window_observer.h"
22 #include "ui/base/hit_test.h"
23 #include "ui/display/screen.h"
24 #include "ui/views/widget/widget.h"
25 #include "ui/wm/core/coordinate_conversion.h"
26
27 namespace exo {
28 namespace wayland {
29 namespace {
30
31 ////////////////////////////////////////////////////////////////////////////////
32 // xdg_positioner_interface:
33
xdg_positioner_v6_destroy(wl_client * client,wl_resource * resource)34 void xdg_positioner_v6_destroy(wl_client* client, wl_resource* resource) {
35 wl_resource_destroy(resource);
36 }
37
xdg_positioner_v6_set_size(wl_client * client,wl_resource * resource,int32_t width,int32_t height)38 void xdg_positioner_v6_set_size(wl_client* client,
39 wl_resource* resource,
40 int32_t width,
41 int32_t height) {
42 if (width < 1 || height < 1) {
43 wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
44 "width and height must be positive and non-zero");
45 return;
46 }
47
48 GetUserDataAs<WaylandPositioner>(resource)->SetSize(gfx::Size(width, height));
49 }
50
xdg_positioner_v6_set_anchor_rect(wl_client * client,wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)51 void xdg_positioner_v6_set_anchor_rect(wl_client* client,
52 wl_resource* resource,
53 int32_t x,
54 int32_t y,
55 int32_t width,
56 int32_t height) {
57 if (width < 1 || height < 1) {
58 wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
59 "width and height must be positive and non-zero");
60 return;
61 }
62
63 GetUserDataAs<WaylandPositioner>(resource)->SetAnchorRect(
64 gfx::Rect(x, y, width, height));
65 }
66
xdg_positioner_v6_set_anchor(wl_client * client,wl_resource * resource,uint32_t anchor)67 void xdg_positioner_v6_set_anchor(wl_client* client,
68 wl_resource* resource,
69 uint32_t anchor) {
70 if (((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) &&
71 (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT)) ||
72 ((anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) &&
73 (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM))) {
74 wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
75 "same-axis values are not allowed");
76 return;
77 }
78
79 GetUserDataAs<WaylandPositioner>(resource)->SetAnchor(anchor);
80 }
81
xdg_positioner_v6_set_gravity(wl_client * client,wl_resource * resource,uint32_t gravity)82 void xdg_positioner_v6_set_gravity(wl_client* client,
83 wl_resource* resource,
84 uint32_t gravity) {
85 if (((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) &&
86 (gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT)) ||
87 ((gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) &&
88 (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM))) {
89 wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
90 "same-axis values are not allowed");
91 return;
92 }
93
94 GetUserDataAs<WaylandPositioner>(resource)->SetGravity(gravity);
95 }
96
xdg_positioner_v6_set_constraint_adjustment(wl_client * client,wl_resource * resource,uint32_t adjustment)97 void xdg_positioner_v6_set_constraint_adjustment(wl_client* client,
98 wl_resource* resource,
99 uint32_t adjustment) {
100 GetUserDataAs<WaylandPositioner>(resource)->SetAdjustment(adjustment);
101 }
102
xdg_positioner_v6_set_offset(wl_client * client,wl_resource * resource,int32_t x,int32_t y)103 void xdg_positioner_v6_set_offset(wl_client* client,
104 wl_resource* resource,
105 int32_t x,
106 int32_t y) {
107 GetUserDataAs<WaylandPositioner>(resource)->SetOffset(gfx::Vector2d(x, y));
108 }
109
110 const struct zxdg_positioner_v6_interface xdg_positioner_v6_implementation = {
111 xdg_positioner_v6_destroy,
112 xdg_positioner_v6_set_size,
113 xdg_positioner_v6_set_anchor_rect,
114 xdg_positioner_v6_set_anchor,
115 xdg_positioner_v6_set_gravity,
116 xdg_positioner_v6_set_constraint_adjustment,
117 xdg_positioner_v6_set_offset};
118
119 ////////////////////////////////////////////////////////////////////////////////
120 // xdg_toplevel_interface:
121
XdgToplevelV6ResizeComponent(uint32_t edges)122 int XdgToplevelV6ResizeComponent(uint32_t edges) {
123 switch (edges) {
124 case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP:
125 return HTTOP;
126 case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM:
127 return HTBOTTOM;
128 case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT:
129 return HTLEFT;
130 case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT:
131 return HTTOPLEFT;
132 case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT:
133 return HTBOTTOMLEFT;
134 case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT:
135 return HTRIGHT;
136 case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT:
137 return HTTOPRIGHT;
138 case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT:
139 return HTBOTTOMRIGHT;
140 default:
141 return HTBOTTOMRIGHT;
142 }
143 }
144
145 using XdgSurfaceConfigureCallback =
146 base::RepeatingCallback<void(const gfx::Size& size,
147 ash::WindowStateType state_type,
148 bool resizing,
149 bool activated)>;
150
HandleXdgSurfaceV6ConfigureCallback(wl_resource * resource,SerialTracker * serial_tracker,const XdgSurfaceConfigureCallback & callback,const gfx::Size & size,ash::WindowStateType state_type,bool resizing,bool activated,const gfx::Vector2d & origin_offset)151 uint32_t HandleXdgSurfaceV6ConfigureCallback(
152 wl_resource* resource,
153 SerialTracker* serial_tracker,
154 const XdgSurfaceConfigureCallback& callback,
155 const gfx::Size& size,
156 ash::WindowStateType state_type,
157 bool resizing,
158 bool activated,
159 const gfx::Vector2d& origin_offset) {
160 uint32_t serial =
161 serial_tracker->GetNextSerial(SerialTracker::EventType::OTHER_EVENT);
162 callback.Run(size, state_type, resizing, activated);
163 zxdg_surface_v6_send_configure(resource, serial);
164 wl_client_flush(wl_resource_get_client(resource));
165 return serial;
166 }
167
168 struct WaylandXdgSurface {
WaylandXdgSurfaceexo::wayland::__anon01ddaa170111::WaylandXdgSurface169 WaylandXdgSurface(std::unique_ptr<XdgShellSurface> shell_surface,
170 SerialTracker* const serial_tracker)
171 : shell_surface(std::move(shell_surface)),
172 serial_tracker(serial_tracker) {}
173
174 std::unique_ptr<XdgShellSurface> shell_surface;
175
176 // Owned by Server, which always outlives this surface.
177 SerialTracker* const serial_tracker;
178
179 DISALLOW_COPY_AND_ASSIGN(WaylandXdgSurface);
180 };
181
182 // Wrapper around shell surface that allows us to handle the case where the
183 // xdg surface resource is destroyed before the toplevel resource.
184 class WaylandToplevel : public aura::WindowObserver {
185 public:
WaylandToplevel(wl_resource * resource,wl_resource * surface_resource)186 WaylandToplevel(wl_resource* resource, wl_resource* surface_resource)
187 : resource_(resource),
188 shell_surface_data_(
189 GetUserDataAs<WaylandXdgSurface>(surface_resource)) {
190 shell_surface_data_->shell_surface->host_window()->AddObserver(this);
191 shell_surface_data_->shell_surface->set_close_callback(base::BindRepeating(
192 &WaylandToplevel::OnClose, weak_ptr_factory_.GetWeakPtr()));
193 shell_surface_data_->shell_surface->set_configure_callback(
194 base::BindRepeating(
195 &HandleXdgSurfaceV6ConfigureCallback, surface_resource,
196 shell_surface_data_->serial_tracker,
197 base::BindRepeating(&WaylandToplevel::OnConfigure,
198 weak_ptr_factory_.GetWeakPtr())));
199 }
~WaylandToplevel()200 ~WaylandToplevel() override {
201 if (shell_surface_data_)
202 shell_surface_data_->shell_surface->host_window()->RemoveObserver(this);
203 }
204
205 // Overridden from aura::WindowObserver:
OnWindowDestroying(aura::Window * window)206 void OnWindowDestroying(aura::Window* window) override {
207 shell_surface_data_ = nullptr;
208 }
209
SetParent(WaylandToplevel * parent)210 void SetParent(WaylandToplevel* parent) {
211 if (!shell_surface_data_)
212 return;
213
214 if (!parent) {
215 shell_surface_data_->shell_surface->SetParent(nullptr);
216 return;
217 }
218
219 // This is a no-op if parent is not mapped.
220 if (parent->shell_surface_data_ &&
221 parent->shell_surface_data_->shell_surface->GetWidget())
222 shell_surface_data_->shell_surface->SetParent(
223 parent->shell_surface_data_->shell_surface.get());
224 }
225
SetTitle(const base::string16 & title)226 void SetTitle(const base::string16& title) {
227 if (shell_surface_data_)
228 shell_surface_data_->shell_surface->SetTitle(title);
229 }
230
SetApplicationId(const char * application_id)231 void SetApplicationId(const char* application_id) {
232 if (shell_surface_data_)
233 shell_surface_data_->shell_surface->SetApplicationId(application_id);
234 }
235
Move()236 void Move() {
237 if (shell_surface_data_)
238 shell_surface_data_->shell_surface->StartMove();
239 }
240
Resize(int component)241 void Resize(int component) {
242 if (!shell_surface_data_)
243 return;
244
245 if (component != HTNOWHERE)
246 shell_surface_data_->shell_surface->StartResize(component);
247 }
248
SetMaximumSize(const gfx::Size & size)249 void SetMaximumSize(const gfx::Size& size) {
250 if (shell_surface_data_)
251 shell_surface_data_->shell_surface->SetMaximumSize(size);
252 }
253
SetMinimumSize(const gfx::Size & size)254 void SetMinimumSize(const gfx::Size& size) {
255 if (shell_surface_data_)
256 shell_surface_data_->shell_surface->SetMinimumSize(size);
257 }
258
Maximize()259 void Maximize() {
260 if (shell_surface_data_)
261 shell_surface_data_->shell_surface->Maximize();
262 }
263
Restore()264 void Restore() {
265 if (shell_surface_data_)
266 shell_surface_data_->shell_surface->Restore();
267 }
268
SetFullscreen(bool fullscreen)269 void SetFullscreen(bool fullscreen) {
270 if (shell_surface_data_)
271 shell_surface_data_->shell_surface->SetFullscreen(fullscreen);
272 }
273
Minimize()274 void Minimize() {
275 if (shell_surface_data_)
276 shell_surface_data_->shell_surface->Minimize();
277 }
278
279 private:
OnClose()280 void OnClose() {
281 zxdg_toplevel_v6_send_close(resource_);
282 wl_client_flush(wl_resource_get_client(resource_));
283 }
284
AddState(wl_array * states,zxdg_toplevel_v6_state state)285 static void AddState(wl_array* states, zxdg_toplevel_v6_state state) {
286 zxdg_toplevel_v6_state* value = static_cast<zxdg_toplevel_v6_state*>(
287 wl_array_add(states, sizeof(zxdg_toplevel_v6_state)));
288 DCHECK(value);
289 *value = state;
290 }
291
OnConfigure(const gfx::Size & size,ash::WindowStateType state_type,bool resizing,bool activated)292 void OnConfigure(const gfx::Size& size,
293 ash::WindowStateType state_type,
294 bool resizing,
295 bool activated) {
296 wl_array states;
297 wl_array_init(&states);
298 if (state_type == ash::WindowStateType::kMaximized)
299 AddState(&states, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED);
300 if (state_type == ash::WindowStateType::kFullscreen)
301 AddState(&states, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN);
302 if (resizing)
303 AddState(&states, ZXDG_TOPLEVEL_V6_STATE_RESIZING);
304 if (activated)
305 AddState(&states, ZXDG_TOPLEVEL_V6_STATE_ACTIVATED);
306 zxdg_toplevel_v6_send_configure(resource_, size.width(), size.height(),
307 &states);
308 wl_array_release(&states);
309 }
310
311 wl_resource* const resource_;
312 WaylandXdgSurface* shell_surface_data_;
313 base::WeakPtrFactory<WaylandToplevel> weak_ptr_factory_{this};
314
315 DISALLOW_COPY_AND_ASSIGN(WaylandToplevel);
316 };
317
xdg_toplevel_v6_destroy(wl_client * client,wl_resource * resource)318 void xdg_toplevel_v6_destroy(wl_client* client, wl_resource* resource) {
319 wl_resource_destroy(resource);
320 }
321
xdg_toplevel_v6_set_parent(wl_client * client,wl_resource * resource,wl_resource * parent)322 void xdg_toplevel_v6_set_parent(wl_client* client,
323 wl_resource* resource,
324 wl_resource* parent) {
325 WaylandToplevel* parent_surface = nullptr;
326 if (parent)
327 parent_surface = GetUserDataAs<WaylandToplevel>(parent);
328
329 GetUserDataAs<WaylandToplevel>(resource)->SetParent(parent_surface);
330 }
331
xdg_toplevel_v6_set_title(wl_client * client,wl_resource * resource,const char * title)332 void xdg_toplevel_v6_set_title(wl_client* client,
333 wl_resource* resource,
334 const char* title) {
335 GetUserDataAs<WaylandToplevel>(resource)->SetTitle(
336 base::string16(base::UTF8ToUTF16(title)));
337 }
338
xdg_toplevel_v6_set_app_id(wl_client * client,wl_resource * resource,const char * app_id)339 void xdg_toplevel_v6_set_app_id(wl_client* client,
340 wl_resource* resource,
341 const char* app_id) {
342 GetUserDataAs<WaylandToplevel>(resource)->SetApplicationId(app_id);
343 }
344
xdg_toplevel_v6_show_window_menu(wl_client * client,wl_resource * resource,wl_resource * seat,uint32_t serial,int32_t x,int32_t y)345 void xdg_toplevel_v6_show_window_menu(wl_client* client,
346 wl_resource* resource,
347 wl_resource* seat,
348 uint32_t serial,
349 int32_t x,
350 int32_t y) {
351 NOTIMPLEMENTED();
352 }
353
xdg_toplevel_v6_move(wl_client * client,wl_resource * resource,wl_resource * seat,uint32_t serial)354 void xdg_toplevel_v6_move(wl_client* client,
355 wl_resource* resource,
356 wl_resource* seat,
357 uint32_t serial) {
358 GetUserDataAs<WaylandToplevel>(resource)->Move();
359 }
360
xdg_toplevel_v6_resize(wl_client * client,wl_resource * resource,wl_resource * seat,uint32_t serial,uint32_t edges)361 void xdg_toplevel_v6_resize(wl_client* client,
362 wl_resource* resource,
363 wl_resource* seat,
364 uint32_t serial,
365 uint32_t edges) {
366 GetUserDataAs<WaylandToplevel>(resource)->Resize(
367 XdgToplevelV6ResizeComponent(edges));
368 }
369
xdg_toplevel_v6_set_max_size(wl_client * client,wl_resource * resource,int32_t width,int32_t height)370 void xdg_toplevel_v6_set_max_size(wl_client* client,
371 wl_resource* resource,
372 int32_t width,
373 int32_t height) {
374 GetUserDataAs<WaylandToplevel>(resource)->SetMaximumSize(
375 gfx::Size(width, height));
376 }
377
xdg_toplevel_v6_set_min_size(wl_client * client,wl_resource * resource,int32_t width,int32_t height)378 void xdg_toplevel_v6_set_min_size(wl_client* client,
379 wl_resource* resource,
380 int32_t width,
381 int32_t height) {
382 GetUserDataAs<WaylandToplevel>(resource)->SetMinimumSize(
383 gfx::Size(width, height));
384 }
385
xdg_toplevel_v6_set_maximized(wl_client * client,wl_resource * resource)386 void xdg_toplevel_v6_set_maximized(wl_client* client, wl_resource* resource) {
387 GetUserDataAs<WaylandToplevel>(resource)->Maximize();
388 }
389
xdg_toplevel_v6_unset_maximized(wl_client * client,wl_resource * resource)390 void xdg_toplevel_v6_unset_maximized(wl_client* client, wl_resource* resource) {
391 GetUserDataAs<WaylandToplevel>(resource)->Restore();
392 }
393
xdg_toplevel_v6_set_fullscreen(wl_client * client,wl_resource * resource,wl_resource * output)394 void xdg_toplevel_v6_set_fullscreen(wl_client* client,
395 wl_resource* resource,
396 wl_resource* output) {
397 GetUserDataAs<WaylandToplevel>(resource)->SetFullscreen(true);
398 }
399
xdg_toplevel_v6_unset_fullscreen(wl_client * client,wl_resource * resource)400 void xdg_toplevel_v6_unset_fullscreen(wl_client* client,
401 wl_resource* resource) {
402 GetUserDataAs<WaylandToplevel>(resource)->SetFullscreen(false);
403 }
404
xdg_toplevel_v6_set_minimized(wl_client * client,wl_resource * resource)405 void xdg_toplevel_v6_set_minimized(wl_client* client, wl_resource* resource) {
406 GetUserDataAs<WaylandToplevel>(resource)->Minimize();
407 }
408
409 const struct zxdg_toplevel_v6_interface xdg_toplevel_v6_implementation = {
410 xdg_toplevel_v6_destroy, xdg_toplevel_v6_set_parent,
411 xdg_toplevel_v6_set_title, xdg_toplevel_v6_set_app_id,
412 xdg_toplevel_v6_show_window_menu, xdg_toplevel_v6_move,
413 xdg_toplevel_v6_resize, xdg_toplevel_v6_set_max_size,
414 xdg_toplevel_v6_set_min_size, xdg_toplevel_v6_set_maximized,
415 xdg_toplevel_v6_unset_maximized, xdg_toplevel_v6_set_fullscreen,
416 xdg_toplevel_v6_unset_fullscreen, xdg_toplevel_v6_set_minimized};
417
418 ////////////////////////////////////////////////////////////////////////////////
419 // xdg_popup_interface:
420
421 // Wrapper around shell surface that allows us to handle the case where the
422 // xdg surface resource is destroyed before the popup resource.
423 class WaylandPopup : aura::WindowObserver {
424 public:
WaylandPopup(wl_resource * resource,wl_resource * surface_resource)425 WaylandPopup(wl_resource* resource, wl_resource* surface_resource)
426 : resource_(resource),
427 shell_surface_data_(
428 GetUserDataAs<WaylandXdgSurface>(surface_resource)) {
429 shell_surface_data_->shell_surface->host_window()->AddObserver(this);
430 shell_surface_data_->shell_surface->set_close_callback(base::BindRepeating(
431 &WaylandPopup::OnClose, weak_ptr_factory_.GetWeakPtr()));
432 shell_surface_data_->shell_surface->set_configure_callback(
433 base::BindRepeating(
434 &HandleXdgSurfaceV6ConfigureCallback, surface_resource,
435 shell_surface_data_->serial_tracker,
436 base::BindRepeating(&WaylandPopup::OnConfigure,
437 weak_ptr_factory_.GetWeakPtr())));
438 }
~WaylandPopup()439 ~WaylandPopup() override {
440 if (shell_surface_data_)
441 shell_surface_data_->shell_surface->host_window()->RemoveObserver(this);
442 }
443
Grab()444 void Grab() {
445 if (!shell_surface_data_) {
446 wl_resource_post_error(resource_, ZXDG_POPUP_V6_ERROR_INVALID_GRAB,
447 "the surface has already been destroyed");
448 return;
449 }
450 if (shell_surface_data_->shell_surface->GetWidget()) {
451 wl_resource_post_error(resource_, ZXDG_POPUP_V6_ERROR_INVALID_GRAB,
452 "grab must be called before construction");
453 return;
454 }
455 shell_surface_data_->shell_surface->Grab();
456 }
457
458 // Overridden from aura::WindowObserver:
OnWindowDestroying(aura::Window * window)459 void OnWindowDestroying(aura::Window* window) override {
460 shell_surface_data_ = nullptr;
461 }
462
463 private:
OnClose()464 void OnClose() {
465 zxdg_popup_v6_send_popup_done(resource_);
466 wl_client_flush(wl_resource_get_client(resource_));
467 }
468
OnConfigure(const gfx::Size & size,ash::WindowStateType state_type,bool resizing,bool activated)469 void OnConfigure(const gfx::Size& size,
470 ash::WindowStateType state_type,
471 bool resizing,
472 bool activated) {
473 // Nothing to do here as popups don't have additional configure state.
474 }
475
476 wl_resource* const resource_;
477 WaylandXdgSurface* shell_surface_data_;
478 base::WeakPtrFactory<WaylandPopup> weak_ptr_factory_{this};
479
480 DISALLOW_COPY_AND_ASSIGN(WaylandPopup);
481 };
482
xdg_popup_v6_destroy(wl_client * client,wl_resource * resource)483 void xdg_popup_v6_destroy(wl_client* client, wl_resource* resource) {
484 wl_resource_destroy(resource);
485 }
486
xdg_popup_v6_grab(wl_client * client,wl_resource * resource,wl_resource * seat,uint32_t serial)487 void xdg_popup_v6_grab(wl_client* client,
488 wl_resource* resource,
489 wl_resource* seat,
490 uint32_t serial) {
491 GetUserDataAs<WaylandPopup>(resource)->Grab();
492 }
493
494 const struct zxdg_popup_v6_interface xdg_popup_v6_implementation = {
495 xdg_popup_v6_destroy, xdg_popup_v6_grab};
496
497 ////////////////////////////////////////////////////////////////////////////////
498 // xdg_surface_interface:
499
xdg_surface_v6_destroy(wl_client * client,wl_resource * resource)500 void xdg_surface_v6_destroy(wl_client* client, wl_resource* resource) {
501 wl_resource_destroy(resource);
502 }
503
xdg_surface_v6_get_toplevel(wl_client * client,wl_resource * resource,uint32_t id)504 void xdg_surface_v6_get_toplevel(wl_client* client,
505 wl_resource* resource,
506 uint32_t id) {
507 auto* shell_surface_data = GetUserDataAs<WaylandXdgSurface>(resource);
508 if (shell_surface_data->shell_surface->GetEnabled()) {
509 wl_resource_post_error(resource, ZXDG_SURFACE_V6_ERROR_ALREADY_CONSTRUCTED,
510 "surface has already been constructed");
511 return;
512 }
513
514 shell_surface_data->shell_surface->SetCanMinimize(true);
515 shell_surface_data->shell_surface->SetEnabled(true);
516
517 wl_resource* xdg_toplevel_resource =
518 wl_resource_create(client, &zxdg_toplevel_v6_interface, 1, id);
519
520 SetImplementation(
521 xdg_toplevel_resource, &xdg_toplevel_v6_implementation,
522 std::make_unique<WaylandToplevel>(xdg_toplevel_resource, resource));
523 }
524
xdg_surface_v6_get_popup(wl_client * client,wl_resource * resource,uint32_t id,wl_resource * parent_resource,wl_resource * positioner_resource)525 void xdg_surface_v6_get_popup(wl_client* client,
526 wl_resource* resource,
527 uint32_t id,
528 wl_resource* parent_resource,
529 wl_resource* positioner_resource) {
530 auto* shell_surface_data = GetUserDataAs<WaylandXdgSurface>(resource);
531 if (shell_surface_data->shell_surface->GetEnabled()) {
532 wl_resource_post_error(resource, ZXDG_SURFACE_V6_ERROR_ALREADY_CONSTRUCTED,
533 "surface has already been constructed");
534 return;
535 }
536
537 auto* parent_data = GetUserDataAs<WaylandXdgSurface>(parent_resource);
538 if (!parent_data->shell_surface->GetWidget()) {
539 wl_resource_post_error(resource, ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
540 "popup parent not constructed");
541 return;
542 }
543
544 if (shell_surface_data->shell_surface->GetWidget()) {
545 wl_resource_post_error(resource, ZXDG_SURFACE_V6_ERROR_ALREADY_CONSTRUCTED,
546 "get_popup is called after constructed");
547 return;
548 }
549
550 display::Display display =
551 display::Screen::GetScreen()->GetDisplayNearestWindow(
552 parent_data->shell_surface->GetWidget()->GetNativeWindow());
553 gfx::Rect work_area = display.work_area();
554 wm::ConvertRectFromScreen(
555 parent_data->shell_surface->GetWidget()->GetNativeWindow(), &work_area);
556
557 // Try layout using parent's flip state.
558 WaylandPositioner* positioner =
559 GetUserDataAs<WaylandPositioner>(positioner_resource);
560 WaylandPositioner::Result position = positioner->CalculatePosition(
561 work_area, parent_data->shell_surface->x_flipped(),
562 parent_data->shell_surface->y_flipped());
563
564 // Remember the new flip state for its child popups.
565 shell_surface_data->shell_surface->set_x_flipped(position.x_flipped);
566 shell_surface_data->shell_surface->set_y_flipped(position.y_flipped);
567
568 // |position| is relative to the parent's contents view origin, and |origin|
569 // is in screen coordinates.
570 gfx::Point origin = position.origin;
571 views::View::ConvertPointToScreen(parent_data->shell_surface->GetWidget()
572 ->widget_delegate()
573 ->GetContentsView(),
574 &origin);
575 shell_surface_data->shell_surface->SetOrigin(origin);
576 shell_surface_data->shell_surface->SetSize(position.size);
577 shell_surface_data->shell_surface->DisableMovement();
578 shell_surface_data->shell_surface->SetActivatable(false);
579 shell_surface_data->shell_surface->SetCanMinimize(false);
580 shell_surface_data->shell_surface->SetParent(
581 parent_data->shell_surface.get());
582 shell_surface_data->shell_surface->SetPopup();
583 shell_surface_data->shell_surface->SetEnabled(true);
584
585 wl_resource* xdg_popup_resource =
586 wl_resource_create(client, &zxdg_popup_v6_interface, 1, id);
587
588 SetImplementation(
589 xdg_popup_resource, &xdg_popup_v6_implementation,
590 std::make_unique<WaylandPopup>(xdg_popup_resource, resource));
591
592 // We send the configure event here as this event needs x,y coordinates
593 // relative to the parent window.
594 zxdg_popup_v6_send_configure(xdg_popup_resource, position.origin.x(),
595 position.origin.y(), position.size.width(),
596 position.size.height());
597 }
598
xdg_surface_v6_set_window_geometry(wl_client * client,wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)599 void xdg_surface_v6_set_window_geometry(wl_client* client,
600 wl_resource* resource,
601 int32_t x,
602 int32_t y,
603 int32_t width,
604 int32_t height) {
605 GetUserDataAs<WaylandXdgSurface>(resource)->shell_surface->SetGeometry(
606 gfx::Rect(x, y, width, height));
607 }
608
xdg_surface_v6_ack_configure(wl_client * client,wl_resource * resource,uint32_t serial)609 void xdg_surface_v6_ack_configure(wl_client* client,
610 wl_resource* resource,
611 uint32_t serial) {
612 GetUserDataAs<WaylandXdgSurface>(resource)
613 ->shell_surface->AcknowledgeConfigure(serial);
614 }
615
616 const struct zxdg_surface_v6_interface xdg_surface_v6_implementation = {
617 xdg_surface_v6_destroy, xdg_surface_v6_get_toplevel,
618 xdg_surface_v6_get_popup, xdg_surface_v6_set_window_geometry,
619 xdg_surface_v6_ack_configure};
620
621 ////////////////////////////////////////////////////////////////////////////////
622 // xdg_shell_interface:
623
xdg_shell_v6_destroy(wl_client * client,wl_resource * resource)624 void xdg_shell_v6_destroy(wl_client* client, wl_resource* resource) {
625 // Nothing to do here.
626 }
627
xdg_shell_v6_create_positioner(wl_client * client,wl_resource * resource,uint32_t id)628 void xdg_shell_v6_create_positioner(wl_client* client,
629 wl_resource* resource,
630 uint32_t id) {
631 wl_resource* positioner_resource =
632 wl_resource_create(client, &zxdg_positioner_v6_interface, 1, id);
633
634 SetImplementation(positioner_resource, &xdg_positioner_v6_implementation,
635 std::make_unique<WaylandPositioner>());
636 }
637
xdg_shell_v6_get_xdg_surface(wl_client * client,wl_resource * resource,uint32_t id,wl_resource * surface)638 void xdg_shell_v6_get_xdg_surface(wl_client* client,
639 wl_resource* resource,
640 uint32_t id,
641 wl_resource* surface) {
642 auto* data = GetUserDataAs<WaylandXdgShell>(resource);
643 std::unique_ptr<XdgShellSurface> shell_surface =
644 data->display->CreateXdgShellSurface(GetUserDataAs<Surface>(surface));
645 if (!shell_surface) {
646 wl_resource_post_error(resource, ZXDG_SHELL_V6_ERROR_ROLE,
647 "surface has already been assigned a role");
648 return;
649 }
650
651 // Xdg shell v6 surfaces are initially disabled and needs to be explicitly
652 // mapped before they are enabled and can become visible.
653 shell_surface->SetEnabled(false);
654
655 std::unique_ptr<WaylandXdgSurface> wayland_shell_surface =
656 std::make_unique<WaylandXdgSurface>(std::move(shell_surface),
657 data->serial_tracker);
658
659 wl_resource* xdg_surface_resource =
660 wl_resource_create(client, &zxdg_surface_v6_interface, 1, id);
661
662 SetImplementation(xdg_surface_resource, &xdg_surface_v6_implementation,
663 std::move(wayland_shell_surface));
664 }
665
xdg_shell_v6_pong(wl_client * client,wl_resource * resource,uint32_t serial)666 void xdg_shell_v6_pong(wl_client* client,
667 wl_resource* resource,
668 uint32_t serial) {
669 NOTIMPLEMENTED();
670 }
671
672 const struct zxdg_shell_v6_interface xdg_shell_v6_implementation = {
673 xdg_shell_v6_destroy, xdg_shell_v6_create_positioner,
674 xdg_shell_v6_get_xdg_surface, xdg_shell_v6_pong};
675
676 } // namespace
677
bind_xdg_shell_v6(wl_client * client,void * data,uint32_t version,uint32_t id)678 void bind_xdg_shell_v6(wl_client* client,
679 void* data,
680 uint32_t version,
681 uint32_t id) {
682 wl_resource* resource =
683 wl_resource_create(client, &zxdg_shell_v6_interface, 1, id);
684
685 wl_resource_set_implementation(resource, &xdg_shell_v6_implementation, data,
686 nullptr);
687 }
688
689 } // namespace wayland
690 } // namespace exo
691