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