1 // Copyright 2015 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/server.h"
6
7 #include <alpha-compositing-unstable-v1-server-protocol.h>
8 #include <aura-shell-server-protocol.h>
9 #include <color-space-unstable-v1-server-protocol.h>
10 #include <cursor-shapes-unstable-v1-server-protocol.h>
11 #include <gaming-input-unstable-v2-server-protocol.h>
12 #include <grp.h>
13 #include <input-timestamps-unstable-v1-server-protocol.h>
14 #include <keyboard-configuration-unstable-v1-server-protocol.h>
15 #include <keyboard-extension-unstable-v1-server-protocol.h>
16 #include <linux-explicit-synchronization-unstable-v1-server-protocol.h>
17 #include <notification-shell-unstable-v1-server-protocol.h>
18 #include <pointer-constraints-unstable-v1-server-protocol.h>
19 #include <pointer-gestures-unstable-v1-server-protocol.h>
20 #include <presentation-time-server-protocol.h>
21 #include <relative-pointer-unstable-v1-server-protocol.h>
22 #include <remote-shell-unstable-v1-server-protocol.h>
23 #include <secure-output-unstable-v1-server-protocol.h>
24 #include <stylus-tools-unstable-v1-server-protocol.h>
25 #include <stylus-unstable-v2-server-protocol.h>
26 #include <text-input-unstable-v1-server-protocol.h>
27 #include <viewporter-server-protocol.h>
28 #include <vsync-feedback-unstable-v1-server-protocol.h>
29 #include <wayland-server-core.h>
30 #include <wayland-server-protocol-core.h>
31 #include <xdg-shell-unstable-v6-server-protocol.h>
32
33 #include <memory>
34 #include <string>
35 #include <utility>
36
37 #include "base/command_line.h"
38 #include "base/files/file_path.h"
39 #include "base/files/file_util.h"
40 #include "base/posix/eintr_wrapper.h"
41 #include "components/exo/display.h"
42 #include "components/exo/wayland/serial_tracker.h"
43 #include "components/exo/wayland/wayland_display_output.h"
44 #include "components/exo/wayland/wl_compositor.h"
45 #include "components/exo/wayland/wl_data_device_manager.h"
46 #include "components/exo/wayland/wl_output.h"
47 #include "components/exo/wayland/wl_seat.h"
48 #include "components/exo/wayland/wl_shm.h"
49 #include "components/exo/wayland/wl_subcompositor.h"
50 #include "components/exo/wayland/wp_presentation.h"
51 #include "components/exo/wayland/wp_viewporter.h"
52 #include "components/exo/wayland/zaura_shell.h"
53 #include "components/exo/wayland/zcr_alpha_compositing.h"
54 #include "components/exo/wayland/zcr_secure_output.h"
55 #include "components/exo/wayland/zcr_stylus.h"
56 #include "components/exo/wayland/zcr_vsync_feedback.h"
57 #include "components/exo/wayland/zwp_linux_explicit_synchronization.h"
58 #include "ui/display/display.h"
59 #include "ui/display/screen.h"
60
61 #if defined(OS_CHROMEOS)
62 #include "components/exo/wayland/wl_shell.h"
63 #include "components/exo/wayland/zcr_color_space.h"
64 #include "components/exo/wayland/zcr_cursor_shapes.h"
65 #include "components/exo/wayland/zcr_gaming_input.h"
66 #include "components/exo/wayland/zcr_keyboard_configuration.h"
67 #include "components/exo/wayland/zcr_keyboard_extension.h"
68 #include "components/exo/wayland/zcr_notification_shell.h"
69 #include "components/exo/wayland/zcr_remote_shell.h"
70 #include "components/exo/wayland/zcr_stylus_tools.h"
71 #include "components/exo/wayland/zwp_input_timestamps_manager.h"
72 #include "components/exo/wayland/zwp_pointer_constraints.h"
73 #include "components/exo/wayland/zwp_pointer_gestures.h"
74 #include "components/exo/wayland/zwp_relative_pointer_manager.h"
75 #include "components/exo/wayland/zwp_text_input_manager.h"
76 #include "components/exo/wayland/zxdg_shell.h"
77 #endif
78
79 #if defined(USE_OZONE)
80 #include <linux-dmabuf-unstable-v1-server-protocol.h>
81 #include "components/exo/wayland/zwp_linux_dmabuf.h"
82 #endif
83
84 #if defined(USE_FULLSCREEN_SHELL)
85 #include <fullscreen-shell-unstable-v1-server-protocol.h>
86 #include "components/exo/wayland/zwp_fullscreen_shell.h"
87 #endif
88
89 namespace exo {
90 namespace wayland {
91 namespace switches {
92
93 // This flag can be used to override the default wayland socket name. It is
94 // useful when another wayland server is already running and using the
95 // default name.
96 constexpr char kWaylandServerSocket[] = "wayland-server-socket";
97 }
98
99 namespace {
100
101 // Default wayland socket name.
102 const base::FilePath::CharType kSocketName[] = FILE_PATH_LITERAL("wayland-0");
103
104 // Group used for wayland socket.
105 const char kWaylandSocketGroup[] = "wayland";
106
107 } // namespace
108
109 ////////////////////////////////////////////////////////////////////////////////
110 // Server, public:
111
Server(Display * display)112 Server::Server(Display* display)
113 : display_(display),
114 wl_display_(wl_display_create()),
115 serial_tracker_(std::make_unique<SerialTracker>(wl_display_.get())) {
116 wl_global_create(wl_display_.get(), &wl_compositor_interface,
117 kWlCompositorVersion, display_, bind_compositor);
118 wl_global_create(wl_display_.get(), &wl_shm_interface, 1, display_, bind_shm);
119 #if defined(USE_OZONE)
120 wl_global_create(wl_display_.get(), &zwp_linux_dmabuf_v1_interface,
121 kZwpLinuxDmabufVersion, display_, bind_linux_dmabuf);
122 #endif
123 wl_global_create(wl_display_.get(), &wl_subcompositor_interface, 1, display_,
124 bind_subcompositor);
125 display::Screen::GetScreen()->AddObserver(this);
126 for (const auto& display : display::Screen::GetScreen()->GetAllDisplays())
127 OnDisplayAdded(display);
128 wl_global_create(wl_display_.get(), &zcr_vsync_feedback_v1_interface, 1,
129 display_, bind_vsync_feedback);
130
131 data_device_manager_data_ = std::make_unique<WaylandDataDeviceManager>(
132 display_, serial_tracker_.get());
133 wl_global_create(wl_display_.get(), &wl_data_device_manager_interface,
134 kWlDataDeviceManagerVersion, data_device_manager_data_.get(),
135 bind_data_device_manager);
136
137 wl_global_create(wl_display_.get(), &wp_viewporter_interface, 1, display_,
138 bind_viewporter);
139 wl_global_create(wl_display_.get(), &wp_presentation_interface, 1, display_,
140 bind_presentation);
141 wl_global_create(wl_display_.get(), &zcr_secure_output_v1_interface, 1,
142 display_, bind_secure_output);
143 wl_global_create(wl_display_.get(), &zcr_alpha_compositing_v1_interface, 1,
144 display_, bind_alpha_compositing);
145 wl_global_create(wl_display_.get(), &zcr_stylus_v2_interface, 1, display_,
146 bind_stylus_v2);
147
148 seat_data_ =
149 std::make_unique<WaylandSeat>(display_->seat(), serial_tracker_.get());
150 wl_global_create(wl_display_.get(), &wl_seat_interface, kWlSeatVersion,
151 seat_data_.get(), bind_seat);
152
153 wl_global_create(wl_display_.get(),
154 &zwp_linux_explicit_synchronization_v1_interface, 1,
155 display_, bind_linux_explicit_synchronization);
156 wl_global_create(wl_display_.get(), &zaura_shell_interface,
157 kZAuraShellVersion, display_, bind_aura_shell);
158 #if defined(OS_CHROMEOS)
159 wl_global_create(wl_display_.get(), &wl_shell_interface, 1, display_,
160 bind_shell);
161 wl_global_create(wl_display_.get(), &zcr_cursor_shapes_v1_interface, 1,
162 display_, bind_cursor_shapes);
163 wl_global_create(wl_display_.get(), &zcr_gaming_input_v2_interface, 1,
164 display_, bind_gaming_input);
165 wl_global_create(wl_display_.get(), &zcr_keyboard_configuration_v1_interface,
166 kZcrKeyboardConfigurationVersion, display_,
167 bind_keyboard_configuration);
168 wl_global_create(wl_display_.get(), &zcr_keyboard_extension_v1_interface, 1,
169 display_, bind_keyboard_extension);
170 wl_global_create(wl_display_.get(), &zcr_notification_shell_v1_interface, 1,
171 display_, bind_notification_shell);
172 wl_global_create(wl_display_.get(), &zcr_remote_shell_v1_interface,
173 kZcrRemoteShellVersion, display_, bind_remote_shell);
174 wl_global_create(wl_display_.get(), &zcr_stylus_tools_v1_interface, 1,
175 display_, bind_stylus_tools);
176 wl_global_create(wl_display_.get(),
177 &zwp_input_timestamps_manager_v1_interface, 1, display_,
178 bind_input_timestamps_manager);
179 wl_global_create(wl_display_.get(), &zwp_pointer_gestures_v1_interface, 1,
180 display_, bind_pointer_gestures);
181 wl_global_create(wl_display_.get(), &zwp_pointer_constraints_v1_interface, 1,
182 display_, bind_pointer_constraints);
183 wl_global_create(wl_display_.get(),
184 &zwp_relative_pointer_manager_v1_interface, 1, display_,
185 bind_relative_pointer_manager);
186 wl_global_create(wl_display_.get(), &zcr_color_space_v1_interface, 1,
187 display_, bind_color_space);
188
189 zwp_text_manager_data_ =
190 std::make_unique<WaylandTextInputManager>(serial_tracker_.get());
191 wl_global_create(wl_display_.get(), &zwp_text_input_manager_v1_interface, 1,
192 zwp_text_manager_data_.get(), bind_text_input_manager);
193
194 xdg_shell_data_ =
195 std::make_unique<WaylandXdgShell>(display_, serial_tracker_.get());
196 wl_global_create(wl_display_.get(), &zxdg_shell_v6_interface, 1,
197 xdg_shell_data_.get(), bind_xdg_shell_v6);
198 #endif
199
200 #if defined(USE_FULLSCREEN_SHELL)
201 wl_global_create(wl_display_.get(), &zwp_fullscreen_shell_v1_interface, 1,
202 display_, bind_fullscreen_shell);
203 #endif
204 }
205
~Server()206 Server::~Server() {
207 display::Screen::GetScreen()->RemoveObserver(this);
208 }
209
210 // static
Create(Display * display)211 std::unique_ptr<Server> Server::Create(Display* display) {
212 std::unique_ptr<Server> server(new Server(display));
213
214 char* runtime_dir = getenv("XDG_RUNTIME_DIR");
215 if (!runtime_dir) {
216 LOG(ERROR) << "XDG_RUNTIME_DIR not set in the environment";
217 return nullptr;
218 }
219
220 std::string socket_name(kSocketName);
221 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
222 if (command_line->HasSwitch(switches::kWaylandServerSocket)) {
223 socket_name =
224 command_line->GetSwitchValueASCII(switches::kWaylandServerSocket);
225 }
226
227 if (!server->AddSocket(socket_name.c_str())) {
228 LOG(ERROR) << "Failed to add socket: " << socket_name;
229 return nullptr;
230 }
231
232 base::FilePath socket_path = base::FilePath(runtime_dir).Append(socket_name);
233
234 // Change permissions on the socket.
235 struct group wayland_group;
236 struct group* wayland_group_res = nullptr;
237 char buf[10000];
238 if (HANDLE_EINTR(getgrnam_r(kWaylandSocketGroup, &wayland_group, buf,
239 sizeof(buf), &wayland_group_res)) < 0) {
240 PLOG(ERROR) << "getgrnam_r";
241 return nullptr;
242 }
243 if (wayland_group_res) {
244 if (HANDLE_EINTR(chown(socket_path.MaybeAsASCII().c_str(), -1,
245 wayland_group.gr_gid)) < 0) {
246 PLOG(ERROR) << "chown";
247 return nullptr;
248 }
249 } else {
250 LOG(WARNING) << "Group '" << kWaylandSocketGroup << "' not found";
251 }
252
253 if (!base::SetPosixFilePermissions(socket_path, 0660)) {
254 PLOG(ERROR) << "Could not set permissions: " << socket_path.value();
255 return nullptr;
256 }
257
258 return server;
259 }
260
AddSocket(const std::string name)261 bool Server::AddSocket(const std::string name) {
262 DCHECK(!name.empty());
263 return !wl_display_add_socket(wl_display_.get(), name.c_str());
264 }
265
GetFileDescriptor() const266 int Server::GetFileDescriptor() const {
267 wl_event_loop* event_loop = wl_display_get_event_loop(wl_display_.get());
268 DCHECK(event_loop);
269 return wl_event_loop_get_fd(event_loop);
270 }
271
Dispatch(base::TimeDelta timeout)272 void Server::Dispatch(base::TimeDelta timeout) {
273 wl_event_loop* event_loop = wl_display_get_event_loop(wl_display_.get());
274 DCHECK(event_loop);
275 wl_event_loop_dispatch(event_loop, timeout.InMilliseconds());
276 }
277
Flush()278 void Server::Flush() {
279 wl_display_flush_clients(wl_display_.get());
280 }
281
OnDisplayAdded(const display::Display & new_display)282 void Server::OnDisplayAdded(const display::Display& new_display) {
283 auto output = std::make_unique<WaylandDisplayOutput>(new_display.id());
284 output->set_global(wl_global_create(wl_display_.get(), &wl_output_interface,
285 kWlOutputVersion, output.get(),
286 bind_output));
287 DCHECK_EQ(outputs_.count(new_display.id()), 0u);
288 outputs_.insert(std::make_pair(new_display.id(), std::move(output)));
289 }
290
OnDisplayRemoved(const display::Display & old_display)291 void Server::OnDisplayRemoved(const display::Display& old_display) {
292 DCHECK_EQ(outputs_.count(old_display.id()), 1u);
293 outputs_.erase(old_display.id());
294 }
295
296 } // namespace wayland
297 } // namespace exo
298