1 // Copyright 2019 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/host/xdg_surface_wrapper_impl.h"
6
7 #include <xdg-decoration-unstable-v1-client-protocol.h>
8 #include <xdg-shell-client-protocol.h>
9 #include <xdg-shell-unstable-v6-client-protocol.h>
10
11 #include "base/strings/utf_string_conversions.h"
12 #include "ui/base/hit_test.h"
13 #include "ui/ozone/platform/wayland/common/wayland_util.h"
14 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
15 #include "ui/ozone/platform/wayland/host/wayland_window.h"
16
17 namespace ui {
18
XDGSurfaceWrapperImpl(WaylandWindow * wayland_window,WaylandConnection * connection)19 XDGSurfaceWrapperImpl::XDGSurfaceWrapperImpl(WaylandWindow* wayland_window,
20 WaylandConnection* connection)
21 : wayland_window_(wayland_window), connection_(connection) {}
22
~XDGSurfaceWrapperImpl()23 XDGSurfaceWrapperImpl::~XDGSurfaceWrapperImpl() {}
24
Initialize(bool with_toplevel)25 bool XDGSurfaceWrapperImpl::Initialize(bool with_toplevel) {
26 if (connection_->shell())
27 return InitializeStable(with_toplevel);
28 else if (connection_->shell_v6())
29 return InitializeV6(with_toplevel);
30 NOTREACHED() << "Wrong shell protocol";
31 return false;
32 }
33
SetMaximized()34 void XDGSurfaceWrapperImpl::SetMaximized() {
35 if (xdg_toplevel_) {
36 xdg_toplevel_set_maximized(xdg_toplevel_.get());
37 } else {
38 DCHECK(zxdg_toplevel_v6_);
39 zxdg_toplevel_v6_set_maximized(zxdg_toplevel_v6_.get());
40 }
41 }
42
UnSetMaximized()43 void XDGSurfaceWrapperImpl::UnSetMaximized() {
44 if (xdg_toplevel_) {
45 xdg_toplevel_unset_maximized(xdg_toplevel_.get());
46 } else {
47 DCHECK(zxdg_toplevel_v6_);
48 zxdg_toplevel_v6_unset_maximized(zxdg_toplevel_v6_.get());
49 }
50 }
51
SetFullscreen()52 void XDGSurfaceWrapperImpl::SetFullscreen() {
53 if (xdg_toplevel_) {
54 xdg_toplevel_set_fullscreen(xdg_toplevel_.get(), nullptr);
55 } else {
56 DCHECK(zxdg_toplevel_v6_);
57 zxdg_toplevel_v6_set_fullscreen(zxdg_toplevel_v6_.get(), nullptr);
58 }
59 }
60
UnSetFullscreen()61 void XDGSurfaceWrapperImpl::UnSetFullscreen() {
62 if (xdg_toplevel_) {
63 xdg_toplevel_unset_fullscreen(xdg_toplevel_.get());
64 } else {
65 DCHECK(zxdg_toplevel_v6_);
66 zxdg_toplevel_v6_unset_fullscreen(zxdg_toplevel_v6_.get());
67 }
68 }
69
SetMinimized()70 void XDGSurfaceWrapperImpl::SetMinimized() {
71 if (xdg_toplevel_) {
72 xdg_toplevel_set_minimized(xdg_toplevel_.get());
73 } else {
74 DCHECK(zxdg_toplevel_v6_);
75 zxdg_toplevel_v6_set_minimized(zxdg_toplevel_v6_.get());
76 }
77 }
78
SurfaceMove(WaylandConnection * connection)79 void XDGSurfaceWrapperImpl::SurfaceMove(WaylandConnection* connection) {
80 if (xdg_toplevel_) {
81 xdg_toplevel_move(xdg_toplevel_.get(), connection_->seat(),
82 connection_->serial());
83 } else {
84 DCHECK(zxdg_toplevel_v6_);
85 zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection_->seat(),
86 connection_->serial());
87 }
88 }
89
SurfaceResize(WaylandConnection * connection,uint32_t hittest)90 void XDGSurfaceWrapperImpl::SurfaceResize(WaylandConnection* connection,
91 uint32_t hittest) {
92 if (xdg_toplevel_) {
93 xdg_toplevel_resize(xdg_toplevel_.get(), connection_->seat(),
94 connection_->serial(),
95 wl::IdentifyDirection(*connection, hittest));
96 } else {
97 DCHECK(zxdg_toplevel_v6_);
98 zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection_->seat(),
99 connection_->serial(),
100 wl::IdentifyDirection(*connection, hittest));
101 }
102 }
103
SetTitle(const base::string16 & title)104 void XDGSurfaceWrapperImpl::SetTitle(const base::string16& title) {
105 if (xdg_toplevel_) {
106 xdg_toplevel_set_title(xdg_toplevel_.get(),
107 base::UTF16ToUTF8(title).c_str());
108 } else {
109 DCHECK(zxdg_toplevel_v6_);
110 zxdg_toplevel_v6_set_title(zxdg_toplevel_v6_.get(),
111 base::UTF16ToUTF8(title).c_str());
112 }
113 }
114
AckConfigure()115 void XDGSurfaceWrapperImpl::AckConfigure() {
116 if (xdg_surface_) {
117 xdg_surface_ack_configure(xdg_surface_.get(), pending_configure_serial_);
118 } else {
119 DCHECK(zxdg_surface_v6_);
120 zxdg_surface_v6_ack_configure(zxdg_surface_v6_.get(),
121 pending_configure_serial_);
122 }
123 connection_->wayland_window_manager()->NotifyWindowConfigured(
124 wayland_window_);
125 }
126
SetWindowGeometry(const gfx::Rect & bounds)127 void XDGSurfaceWrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) {
128 if (xdg_surface_) {
129 xdg_surface_set_window_geometry(xdg_surface_.get(), bounds.x(), bounds.y(),
130 bounds.width(), bounds.height());
131 } else {
132 DCHECK(zxdg_surface_v6_);
133 zxdg_surface_v6_set_window_geometry(zxdg_surface_v6_.get(), bounds.x(),
134 bounds.y(), bounds.width(),
135 bounds.height());
136 }
137 }
138
SetMinSize(int32_t width,int32_t height)139 void XDGSurfaceWrapperImpl::SetMinSize(int32_t width, int32_t height) {
140 if (xdg_toplevel_) {
141 xdg_toplevel_set_min_size(xdg_toplevel_.get(), width, height);
142 } else {
143 DCHECK(zxdg_toplevel_v6_);
144 zxdg_toplevel_v6_set_min_size(zxdg_toplevel_v6_.get(), width, height);
145 }
146 }
147
SetMaxSize(int32_t width,int32_t height)148 void XDGSurfaceWrapperImpl::SetMaxSize(int32_t width, int32_t height) {
149 if (xdg_toplevel_) {
150 xdg_toplevel_set_max_size(xdg_toplevel_.get(), width, height);
151 } else {
152 DCHECK(zxdg_toplevel_v6_);
153 zxdg_toplevel_v6_set_max_size(zxdg_toplevel_v6_.get(), width, height);
154 }
155 }
156
SetAppId(const std::string & app_id)157 void XDGSurfaceWrapperImpl::SetAppId(const std::string& app_id) {
158 if (xdg_toplevel_) {
159 xdg_toplevel_set_app_id(xdg_toplevel_.get(), app_id.c_str());
160 } else {
161 DCHECK(zxdg_toplevel_v6_);
162 zxdg_toplevel_v6_set_app_id(zxdg_toplevel_v6_.get(), app_id.c_str());
163 }
164 }
165
166 // static
ConfigureStable(void * data,struct xdg_surface * xdg_surface,uint32_t serial)167 void XDGSurfaceWrapperImpl::ConfigureStable(void* data,
168 struct xdg_surface* xdg_surface,
169 uint32_t serial) {
170 auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
171 DCHECK(surface);
172 surface->pending_configure_serial_ = serial;
173
174 surface->AckConfigure();
175 }
176
177 // static
ConfigureTopLevelStable(void * data,struct xdg_toplevel * xdg_toplevel,int32_t width,int32_t height,struct wl_array * states)178 void XDGSurfaceWrapperImpl::ConfigureTopLevelStable(
179 void* data,
180 struct xdg_toplevel* xdg_toplevel,
181 int32_t width,
182 int32_t height,
183 struct wl_array* states) {
184 auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
185 DCHECK(surface);
186
187 bool is_maximized =
188 CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_MAXIMIZED);
189 bool is_fullscreen =
190 CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_FULLSCREEN);
191 bool is_activated =
192 CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_ACTIVATED);
193
194 surface->wayland_window_->HandleSurfaceConfigure(width, height, is_maximized,
195 is_fullscreen, is_activated);
196 }
197
198 // static
CloseTopLevelStable(void * data,struct xdg_toplevel * xdg_toplevel)199 void XDGSurfaceWrapperImpl::CloseTopLevelStable(
200 void* data,
201 struct xdg_toplevel* xdg_toplevel) {
202 auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
203 DCHECK(surface);
204 surface->wayland_window_->OnCloseRequest();
205 }
206
SetTopLevelDecorationMode(zxdg_toplevel_decoration_v1_mode requested_mode)207 void XDGSurfaceWrapperImpl::SetTopLevelDecorationMode(
208 zxdg_toplevel_decoration_v1_mode requested_mode) {
209 if (requested_mode == decoration_mode_)
210 return;
211
212 decoration_mode_ = requested_mode;
213 zxdg_toplevel_decoration_v1_set_mode(zxdg_toplevel_decoration_.get(),
214 requested_mode);
215 }
216
217 // static
ConfigureV6(void * data,struct zxdg_surface_v6 * zxdg_surface_v6,uint32_t serial)218 void XDGSurfaceWrapperImpl::ConfigureV6(void* data,
219 struct zxdg_surface_v6* zxdg_surface_v6,
220 uint32_t serial) {
221 auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
222 DCHECK(surface);
223 surface->pending_configure_serial_ = serial;
224
225 surface->AckConfigure();
226 }
227
228 // static
ConfigureTopLevelV6(void * data,struct zxdg_toplevel_v6 * zxdg_toplevel_v6,int32_t width,int32_t height,struct wl_array * states)229 void XDGSurfaceWrapperImpl::ConfigureTopLevelV6(
230 void* data,
231 struct zxdg_toplevel_v6* zxdg_toplevel_v6,
232 int32_t width,
233 int32_t height,
234 struct wl_array* states) {
235 auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
236 DCHECK(surface);
237
238 bool is_maximized =
239 CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED);
240 bool is_fullscreen =
241 CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN);
242 bool is_activated =
243 CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_ACTIVATED);
244
245 surface->wayland_window_->HandleSurfaceConfigure(width, height, is_maximized,
246 is_fullscreen, is_activated);
247 }
248
249 // static
CloseTopLevelV6(void * data,struct zxdg_toplevel_v6 * zxdg_toplevel_v6)250 void XDGSurfaceWrapperImpl::CloseTopLevelV6(
251 void* data,
252 struct zxdg_toplevel_v6* zxdg_toplevel_v6) {
253 auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
254 DCHECK(surface);
255 surface->wayland_window_->OnCloseRequest();
256 }
257
zxdg_surface() const258 zxdg_surface_v6* XDGSurfaceWrapperImpl::zxdg_surface() const {
259 DCHECK(zxdg_surface_v6_);
260 return zxdg_surface_v6_.get();
261 }
262
xdg_surface() const263 xdg_surface* XDGSurfaceWrapperImpl::xdg_surface() const {
264 DCHECK(xdg_surface_);
265 return xdg_surface_.get();
266 }
267
268 // static
ConfigureDecoration(void * data,struct zxdg_toplevel_decoration_v1 * decoration,uint32_t mode)269 void XDGSurfaceWrapperImpl::ConfigureDecoration(
270 void* data,
271 struct zxdg_toplevel_decoration_v1* decoration,
272 uint32_t mode) {
273 auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
274 DCHECK(surface);
275 surface->SetTopLevelDecorationMode(
276 static_cast<zxdg_toplevel_decoration_v1_mode>(mode));
277 }
278
InitializeStable(bool with_toplevel)279 bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) {
280 static const xdg_surface_listener xdg_surface_listener = {
281 &XDGSurfaceWrapperImpl::ConfigureStable,
282 };
283 static const xdg_toplevel_listener xdg_toplevel_listener = {
284 &XDGSurfaceWrapperImpl::ConfigureTopLevelStable,
285 &XDGSurfaceWrapperImpl::CloseTopLevelStable,
286 };
287
288 // if this surface is created for the popup role, mark that it requires
289 // configuration acknowledgement on each configure event.
290 surface_for_popup_ = !with_toplevel;
291
292 xdg_surface_.reset(xdg_wm_base_get_xdg_surface(
293 connection_->shell(), wayland_window_->root_surface()->surface()));
294 if (!xdg_surface_) {
295 LOG(ERROR) << "Failed to create xdg_surface";
296 return false;
297 }
298 xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this);
299 // XDGPopup requires a separate surface to be created, so this is just a
300 // request to get an xdg_surface for it.
301 if (surface_for_popup_) {
302 connection_->ScheduleFlush();
303 return true;
304 }
305
306 xdg_toplevel_.reset(xdg_surface_get_toplevel(xdg_surface_.get()));
307 if (!xdg_toplevel_) {
308 LOG(ERROR) << "Failed to create xdg_toplevel";
309 return false;
310 }
311
312 xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this);
313
314 InitializeXdgDecoration();
315
316 wayland_window_->root_surface()->Commit();
317 connection_->ScheduleFlush();
318 return true;
319 }
320
InitializeV6(bool with_toplevel)321 bool XDGSurfaceWrapperImpl::InitializeV6(bool with_toplevel) {
322 static const zxdg_surface_v6_listener zxdg_surface_v6_listener = {
323 &XDGSurfaceWrapperImpl::ConfigureV6,
324 };
325 static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
326 &XDGSurfaceWrapperImpl::ConfigureTopLevelV6,
327 &XDGSurfaceWrapperImpl::CloseTopLevelV6,
328 };
329
330 // if this surface is created for the popup role, mark that it requires
331 // configuration acknowledgement on each configure event.
332 surface_for_popup_ = !with_toplevel;
333
334 zxdg_surface_v6_.reset(zxdg_shell_v6_get_xdg_surface(
335 connection_->shell_v6(), wayland_window_->root_surface()->surface()));
336 if (!zxdg_surface_v6_) {
337 LOG(ERROR) << "Failed to create zxdg_surface";
338 return false;
339 }
340 zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(),
341 &zxdg_surface_v6_listener, this);
342 // XDGPopupV6 requires a separate surface to be created, so this is just a
343 // request to get an xdg_surface for it.
344 if (surface_for_popup_) {
345 connection_->ScheduleFlush();
346 return true;
347 }
348
349 zxdg_toplevel_v6_.reset(zxdg_surface_v6_get_toplevel(zxdg_surface_v6_.get()));
350 if (!zxdg_toplevel_v6_) {
351 LOG(ERROR) << "Failed to create zxdg_toplevel";
352 return false;
353 }
354 zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
355 &zxdg_toplevel_v6_listener, this);
356
357 wayland_window_->root_surface()->Commit();
358 connection_->ScheduleFlush();
359 return true;
360 }
361
InitializeXdgDecoration()362 void XDGSurfaceWrapperImpl::InitializeXdgDecoration() {
363 if (connection_->xdg_decoration_manager_v1()) {
364 DCHECK(!zxdg_toplevel_decoration_);
365 static const zxdg_toplevel_decoration_v1_listener decoration_listener = {
366 &XDGSurfaceWrapperImpl::ConfigureDecoration,
367 };
368 zxdg_toplevel_decoration_.reset(
369 zxdg_decoration_manager_v1_get_toplevel_decoration(
370 connection_->xdg_decoration_manager_v1(), xdg_toplevel_.get()));
371 zxdg_toplevel_decoration_v1_add_listener(zxdg_toplevel_decoration_.get(),
372 &decoration_listener, this);
373 }
374 }
375
376 } // namespace ui
377