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