├── .clang-format ├── .gitignore ├── .gn ├── OWNERS ├── README.md ├── demos ├── wayland_demo.cc └── x11_demo.cc ├── linux └── virtwl.h ├── meson.build ├── meson_options.txt ├── protocol ├── aura-shell.xml ├── drm.xml ├── gtk-shell.xml ├── keyboard-extension-unstable-v1.xml ├── linux-dmabuf-unstable-v1.xml ├── meson.build ├── pointer-constraints-unstable-v1.xml ├── relative-pointer-unstable-v1.xml ├── text-input-unstable-v1.xml ├── viewporter.xml └── xdg-shell.xml ├── sommelier-compositor.c ├── sommelier-data-device-manager.c ├── sommelier-display.c ├── sommelier-drm.c ├── sommelier-gtk-shell.c ├── sommelier-output.c ├── sommelier-pointer-constraints.c ├── sommelier-relative-pointer-manager.c ├── sommelier-seat.c ├── sommelier-shell.c ├── sommelier-shm.c ├── sommelier-subcompositor.c ├── sommelier-text-input.c ├── sommelier-viewporter.c ├── sommelier-xdg-shell.c ├── sommelier.c ├── sommelier.gyp ├── sommelier.h ├── wayland-protocol.gypi └── wayland_protocol.gni /.clang-format: -------------------------------------------------------------------------------- 1 | # Copyright 2017 The Chromium OS 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 | # Defines the Chromium OS style for automatic reformatting. 6 | # http://clang.llvm.org/docs/ClangFormatStyleOptions.html 7 | # Please keep all directives after this one sorted alphabetically. 8 | BasedOnStyle: Chromium 9 | 10 | # This is permitted by the Google and Chromium style guides, and existing code 11 | # uses it heavily. 12 | AllowAllParametersOfDeclarationOnNextLine: true 13 | 14 | # NOLINT(reason) is used heavily by existing code. 15 | CommentPragmas: 'NOLINT:.*' 16 | 17 | # cpplint.py does smarter #include sorting than clang-format (the former ignores 18 | # case and changes '-' to '_'). 19 | SortIncludes: false 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE! Please use 'git ls-files -i --exclude-standard' 3 | # command after changing this file, to see if there are 4 | # any tracked files which get ignored after the change. 5 | # 6 | 7 | # Temp files (e.g. editors). 8 | *~ 9 | *.sw[op] 10 | 11 | # Compiled objects. 12 | *.a 13 | *.o 14 | *.l[ao] 15 | *.so 16 | *.exe 17 | 18 | *.d 19 | *.depends 20 | .deps 21 | .libs 22 | 23 | *.gch 24 | *.gcda 25 | *.gcno 26 | 27 | # Common output files. 28 | *.dump 29 | *.out 30 | *.test 31 | 32 | # Protobuf files. 33 | *.pb.cc 34 | *.pb.h 35 | 36 | # Python files. 37 | *.pyc 38 | 39 | # Debug (e.g. gdb). 40 | .gdb_history 41 | .gdbinit 42 | 43 | core 44 | cscope.* 45 | tags 46 | tags_sorted_by_file 47 | 48 | # Patch files. 49 | *.diff 50 | *.patch 51 | *.orig 52 | *.rej 53 | 54 | # Nested git repos. 55 | /glbench/images/ 56 | 57 | # Cargo build directories. 58 | target/ 59 | -------------------------------------------------------------------------------- /.gn: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Chromium OS 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 | buildconfig = "//common-mk/BUILDCONFIG.gn" 6 | root = "//common-mk/gn_root/:" 7 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | set noparent 2 | reveman@chromium.org 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Notes for this Fork 2 | 3 | This runs a nested Wayland compositor that presents unscaled pixels to a new XWayland instance. Programs run under this X session look sharp. You can use it to achive per-app scaling with both X11 and native wayland clients. 4 | 5 | ## To build 6 | 7 | sudo apt install -y pkg-config git make xwayland libwayland-dev libgbm-dev gcc libx11-xcb-dev \ 8 | libsystemd-dev libxcb-composite0-dev libxkbcommon-dev libxrender-dev libxtst-dev libpixman-1-dev libdrm-dev 9 | 10 | meson out 11 | cd out 12 | ninja 13 | meson install 14 | 15 | ## Usage Examples 16 | 17 | per-app scaling with GTK: 18 | 19 | GDK_BACKEND=x11 GDK_SCALE=2 sommelier -X --scale=2 gedit -s --gdk-debug=misc 20 | 21 | shared X server: 22 | 23 | sommelier -X --scale=2 --x-display=2 --no-exit-with-child true 24 | export DISPLAY=:2 25 | 26 | intellij-idea-ultimate 27 | 28 | ## Issues 29 | 30 | vs-code: 31 | 32 | GDK_SCALE=2 sommelier -X --scale=2 code -w 33 | 34 | error: zxdg_surface_v6@35: error 3: xdg_surface has never been configured 35 | 36 | ## References 37 | 38 | - [virtwl.h source](https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/refs/heads/master/sys-kernel/linux-headers/files/0010-virtwl-add-virtwl-driver.patch) 39 | - [upstream source](https://chromium.googlesource.com/chromiumos/platform2/+/master/vm_tools/sommelier/) 40 | 41 | Original readme follows: 42 | 43 | # Sommelier - Nested Wayland compositor with support for X11 forwarding 44 | 45 | Sommelier is an implementation of a Wayland compositor that delegates 46 | compositing to a 'host' compositor. Sommelier includes a set of features that 47 | allows it to run inside a tight jail or virtual machine. 48 | 49 | Sommelier can run as service or as a wrapper around the execution of a 50 | program. As a service, it spawns new processes as needed to service clients. 51 | The parent process is called the master sommelier. 52 | 53 | ## Sommeliers 54 | 55 | ### Master Sommelier 56 | 57 | The master sommelier instance will create a wayland socket in XDG_RUNTIME_DIR 58 | and accept connections from regular wayland clients. Each connection will be 59 | serviced by spawning a child sommelier process. 60 | 61 | ### X11 Sommelier 62 | 63 | An X11 sommelier instance provides X11 forwarding. Xwayland is used to 64 | accomplish this. A single X11 sommelier instance is typically shared across 65 | all X11 clients as they often expect that they can use a shared X server for 66 | communication. If the X11 sommelier instance crashes in this setup, it takes 67 | all running X11 programs down with it. Multiple X11 sommelier instances 68 | can be used for improved isolation or when per-client configuration is 69 | needed, but it will be at the cost of losing the ability for programs to use 70 | the X server for communication between each other. 71 | 72 | ### Peer Sommelier 73 | 74 | Each Linux program that support the Wayland protocol can have its own sommelier. 75 | This provides better use of multiple cores when servicing clients, and it 76 | prevents errors in one client from causing other clients to crash. 77 | 78 | ## Host Compositor Channel 79 | 80 | Sommelier needs a channel to the host compositor in order to serve Wayland 81 | clients inside a container. If the container environment provides a socket 82 | that can be used to establish a connection to the host compositor, then 83 | pointing sommelier to this socket using the `--display=DISPLAY` flag is 84 | sufficient. 85 | 86 | ### VirtWL 87 | 88 | The VirtWL device can be used to establish a new connection when no socket 89 | is available (typically when running inside a VM). If a VirtWL device has been 90 | specified (e.g. `--virtwl-device=/dev/wl0`) then sommelier will use this 91 | mechanism by default to establish new channels between the host compositor and 92 | sommelier instances. Data is forwarded between the VirtWL device and the core 93 | Wayland dispatch mechanism using non-blocking I/O multiplexing. 94 | 95 | ## Shared Memory Drivers 96 | 97 | Shared memory allocated inside a container cannot always be shared with the 98 | host compositor. Sommelier provides a shared memory driver option as a 99 | solution for this. What's the most appropriate option depends on the host 100 | compositor and device drivers available for allocating buffers. 101 | 102 | ### Noop 103 | 104 | The `noop` shared memory driver simply forwards buffers to the host without 105 | any special processing. This requires that the client inside the container is 106 | using memory that can be shared with the host compositor. 107 | 108 | ### VirtWL 109 | 110 | The `virtwl` driver creates a set of intermediate virtwl buffers for each 111 | surface, and copies minimal damaged areas from the client’s standard shared 112 | memory buffers into the virtwl buffers that can be shared with the host 113 | compositor. 114 | 115 | ### VirtWL-DMABuf 116 | 117 | The `virtwl-dmabuf` works the same way as the `virtwl` driver but allocates 118 | buffers that can be shared with the host compositor using the linux_dmabuf 119 | protocol. The benefits of using this driver over the basic `virtwl` driver 120 | are: 121 | 122 | * Larger set of supported formats (E.g NV12). 123 | * Host compositor can avoid expensive texture uploads. 124 | * HW overlays can be used for presentation if support by the host compositor. 125 | 126 | ### DMABuf 127 | 128 | The `dmabuf` driver is similar to the `virtwl-dmabuf` driver. It creates a set 129 | of intermediate buffers for each surface and copies minimal damaged areas from 130 | the client’s standard shared memory buffer into the DMABuf buffer. However, 131 | the buffer is allocated using a DRM device and a prime FD is used to access 132 | buffer memory inside the container. Intermediate buffers are shared with the 133 | host compositor using the linux_dmabuf protocol. 134 | 135 | ## Damage Tracking 136 | 137 | Shared memory drivers that use intermediate buffers require some form of 138 | damage tracking in order to update intermediate buffers. 139 | 140 | ### Surface Buffer Queue 141 | 142 | Each client surface in sommelier is associated with a buffer queue. Each 143 | buffer in the buffer queue has a region (list of rectangles) that describes 144 | the part of the buffer that is damaged compared to the last frame submitted 145 | by the client. This provides high precision damage tracking across multiple 146 | frames. Each new frame from the client adds damage to existing buffers. When 147 | submitting a frame to the host compositor, the next available buffer is 148 | dequeued and updated to not contain any damage. This is done by copying 149 | contents from the current client buffer into the dequeued buffer. 150 | 151 | The client's buffer is released as soon as this copy operation described above 152 | is complete and the client can then reuse the shared memory buffer for another 153 | frame. 154 | 155 | Note: It is important to release the buffer immediately as clients don’t 156 | expect it to be held by the compositor for long when using shared memory. 157 | 158 | ### Back Pressure 159 | 160 | Sommelier doesn’t provide any back pressure for when the client is producing 161 | contents faster than the host compositor can consume it. The size of the 162 | buffer queue can as a result grow large. This is not a problem as Xwayland 163 | and other clients handle back pressure themselves using Wayland frame 164 | callbacks or similar mechanism. 165 | 166 | ## Data Drivers 167 | 168 | Socket pairs created inside a container cannot always be shared with the 169 | host compositor. Sommelier provides a data driver option as a solution 170 | for this. 171 | 172 | ### Noop 173 | 174 | The `noop` driver simply forwards socket pair FDs to the host without any 175 | special processing. This requires that the client inside the container is 176 | using socket pairs that can be shared with the host compositor. 177 | 178 | ### VirtWL 179 | 180 | The `virtwl` driver creates a special pipe that can be shared with the host 181 | compositor and forwards all data received over this pipe to the client FD. 182 | Forwarding is done using non-blocking I/O multiplexing. 183 | 184 | ## Flags and Settings 185 | 186 | Sommelier has two forms of configuration. Command line flags and environment 187 | variables. Standard practice is to expose each option both as a command line 188 | flag and as an environment variable. Command line flags will always override 189 | the configuration provided by environment variables. This makes it easy to 190 | run sommelier as a systemd service and allow the system-wide configuration 191 | to be overridden using a local user provided systemd override file. 192 | 193 | ## Density and Scaling 194 | 195 | A protocol aware proxy compositor between the client and the host compositor 196 | makes it easier to support Linux programs that lack good HiDPI support. 197 | It can also be used to adjust the scale of contents to support the dynamic 198 | density changes that Chrome OS UI provide, and it gives the user an option 199 | override any density decisions made by the host compositor. For example, 200 | HiDPI aware programs can run at native display resolution, while some older 201 | programs can use half of that resolution. 202 | 203 | ### Contents Scaling 204 | 205 | Contents scaling can be applied to both native wayland clients and X11 206 | clients. It can be controlled using the `--scale=SCALE` flag or 207 | `SOMMELIER_SCALE=SCALE` variable. Where `SCALE` is a display density 208 | multiplier. For example, if the default density is 200 DPI, then using 209 | `--scale=0.5` will result in contents produced for 100 DPI. 210 | 211 | ### Scale Factor 212 | 213 | An optimal scale factor is calculated for Wayland clients based on contents 214 | scale setting and the current host compositor scaling. This allows Wayland 215 | clients to produce contents at an optimal resolution for all combinations of 216 | scaling used by sommelier and the host compositor. 217 | 218 | ### DPI 219 | 220 | An exact value for DPI is calculated by sommelier. However, many Linux 221 | programs expect DPI to be one out of a well known set of values. Sommelier 222 | solves this by adjusting DPI using a set of buckets. For example, given the 223 | set of buckets (72, 96, 160, 240), Sommelier will use 96 as DPI when the 224 | exact value is 112, or 160 when exact value is 188. The DPI buckets that 225 | sommelier should use can be specified with `--dpi=[DPI[,DPI...]]`. Where, 226 | `--dpi=””` will result in sommelier exposing the exact DPI value to clients 227 | (this is the default behaviour). 228 | 229 | ### XCursor 230 | 231 | Sommelier will set `XCURSOR_SIZE` environment variable automatically based on 232 | the contents scale and preferred host compositor scale factor. 233 | 234 | ## Accelerators 235 | 236 | If the host compositor support dynamic handling of keyboard events, then 237 | keyboard shortcuts are forwarded to the Linux program by default. A small set 238 | of shortcuts are expected to be reserved by the host compositor. A list of 239 | reserved shortcuts on Chrome OS can be found 240 | [here](https://chromium.googlesource.com/chromium/src/+/master/ash/accelerators/accelerator_table.h#22). 241 | 242 | There’s unfortunately no reliable way to detect if a Linux program handled a 243 | key event or not. This means that all non-reserved shortcuts that the user 244 | want the host compositor to handle needs to be explicitly listed as an 245 | accelerator. For example, on Chrome OS, the launcher can be brought up using 246 | the "launcher" button during normal usage. The "launcher" button event is 247 | forwarded to Linux programs by default so it won’t work when a Linux program 248 | has keyboard focus unless this shortcut is explicitly listed as an accelerator. 249 | 250 | Sommelier provides the `--accelerator=ACCELERATORS` flag for this purpose. 251 | `ACCELERATORS` is a comma separated list of accelerators that shouldn’t be 252 | forwarded to the Linux program but instead handled by the host compositor. 253 | Each accelerator can contain a list of modifiers (e.g. ``) and 254 | must be followed by an XKB keysym. The `xev` utility can be used to determine 255 | what the XKB keysym is for a specific key. Given the launcher button example 256 | above (which happens to have XKB keysym `Super_L` on the Chromebook Pixel), 257 | `--accelerators=Super_L` needs to be passed to sommelier for the this button to 258 | bring up the application launcher when Linux programs have keyboard focus. 259 | 260 | Consistent with other flags, `SOMMELIER_ACCELERATORS` environment variable can 261 | be used as an alternative to the command line flag. 262 | 263 | ## Examples 264 | 265 | Start master sommelier and use wayland-1 as name of socket to listen on: 266 | 267 | ``` 268 | sommelier --master --socket=wayland-1 269 | ``` 270 | 271 | Start sommelier that runs weston-terminal with density scale multiplier 1.5: 272 | 273 | ``` 274 | sommelier --scale=1.5 weston-terminal 275 | ``` 276 | 277 | Start sommelier that runs inkscape with density scale multiplier 0.75 and 120 278 | dots per inch (note that -X is specified as inkscape is an X11 client and 279 | requires X11 forwarding): 280 | 281 | ``` 282 | sommelier -X --scale=0.75 --dpi=120 inkscape 283 | ``` 284 | 285 | Start sommelier that runs gedit with some accelerators reserved to the host 286 | compositor instead of being sent to gedit: 287 | 288 | ``` 289 | sommelier --accelerators="Bracketright,Bracketleft" gedit 290 | ``` 291 | -------------------------------------------------------------------------------- /demos/wayland_demo.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "base/command_line.h" 13 | #include "base/logging.h" 14 | #include "base/memory/shared_memory.h" 15 | #include "base/strings/string_number_conversions.h" 16 | #include "brillo/syslog_logging.h" 17 | 18 | constexpr char kBgColorFlag[] = "bgcolor"; 19 | constexpr char kWidthFlag[] = "width"; 20 | constexpr char kHeightFlag[] = "height"; 21 | constexpr char kTitleFlag[] = "title"; 22 | 23 | struct demo_data { 24 | uint32_t bgcolor; 25 | uint32_t width; 26 | uint32_t height; 27 | std::string title; 28 | int scale; 29 | struct wl_compositor* compositor; 30 | struct wl_shell* shell; 31 | struct wl_shm* shm; 32 | struct wl_surface* surface; 33 | struct wl_shell_surface* shell_surface; 34 | struct wl_buffer* buffer; 35 | struct wl_callback* callback; 36 | struct wl_callback_listener* callback_listener; 37 | struct wl_output* output; 38 | struct wl_output_listener* output_listener; 39 | struct wl_keyboard_listener* keyboard_listener; 40 | void* shm_ptr; 41 | bool done; 42 | }; 43 | 44 | void keyboard_keymap(void* data, 45 | struct wl_keyboard* keyboard, 46 | uint32_t format, 47 | int32_t fd, 48 | uint32_t size) {} 49 | 50 | void keyboard_enter(void* data, 51 | struct wl_keyboard* keyboard, 52 | uint32_t serial, 53 | struct wl_surface* surface, 54 | struct wl_array* keys) {} 55 | 56 | void keyboard_leave(void* data, 57 | struct wl_keyboard* keyboard, 58 | uint32_t serial, 59 | struct wl_surface* surface) {} 60 | 61 | void keyboard_key(void* data, 62 | struct wl_keyboard* keyboard, 63 | uint32_t serial, 64 | uint32_t time, 65 | uint32_t key, 66 | uint32_t state) { 67 | struct demo_data* data_ptr = reinterpret_cast(data); 68 | // Key pressed. 69 | if (state == 1) { 70 | LOG(INFO) << "wayland_demo application detected keypress"; 71 | data_ptr->done = true; 72 | } 73 | } 74 | 75 | void keyboard_modifiers(void* data, 76 | struct wl_keyboard* keyboard, 77 | uint32_t serial, 78 | uint32_t mods_depressed, 79 | uint32_t mods_latched, 80 | uint32_t mods_locked, 81 | uint32_t group) {} 82 | 83 | void keyboard_repeat_info(void* data, 84 | struct wl_keyboard* keyboard, 85 | int32_t rate, 86 | int32_t delay) {} 87 | 88 | void demo_registry_listener(void* data, 89 | struct wl_registry* registry, 90 | uint32_t id, 91 | const char* interface, 92 | uint32_t version) { 93 | struct demo_data* data_ptr = reinterpret_cast(data); 94 | if (!strcmp("wl_compositor", interface)) { 95 | data_ptr->compositor = reinterpret_cast( 96 | wl_registry_bind(registry, id, &wl_compositor_interface, version)); 97 | } else if (!strcmp("wl_shell", interface)) { 98 | data_ptr->shell = reinterpret_cast( 99 | wl_registry_bind(registry, id, &wl_shell_interface, version)); 100 | } else if (!strcmp("wl_shm", interface)) { 101 | data_ptr->shm = reinterpret_cast( 102 | wl_registry_bind(registry, id, &wl_shm_interface, version)); 103 | } else if (!strcmp("wl_output", interface)) { 104 | data_ptr->output = reinterpret_cast( 105 | wl_registry_bind(registry, id, &wl_output_interface, version)); 106 | wl_output_add_listener(data_ptr->output, data_ptr->output_listener, 107 | data_ptr); 108 | } else if (!strcmp("wl_seat", interface)) { 109 | struct wl_seat* seat = reinterpret_cast( 110 | wl_registry_bind(registry, id, &wl_seat_interface, version)); 111 | wl_keyboard_add_listener(wl_seat_get_keyboard(seat), 112 | data_ptr->keyboard_listener, data_ptr); 113 | } 114 | } 115 | 116 | void demo_registry_remover(void* data, 117 | struct wl_registry* registry, 118 | uint32_t id) {} 119 | 120 | void shell_surface_ping(void* data, 121 | struct wl_shell_surface* shell_surface, 122 | uint32_t serial) { 123 | wl_shell_surface_pong(shell_surface, serial); 124 | } 125 | 126 | void shell_surface_configure(void* data, 127 | struct wl_shell_surface* shell_surface, 128 | uint32_t edges, 129 | int32_t width, 130 | int32_t height) {} 131 | 132 | void shell_surface_popup_done(void* data, 133 | struct wl_shell_surface* shell_surface) {} 134 | 135 | void demo_draw(void* data, struct wl_callback* callback, uint32_t time) { 136 | struct demo_data* data_ptr = reinterpret_cast(data); 137 | wl_callback_destroy(data_ptr->callback); 138 | wl_surface_damage(data_ptr->surface, 0, 0, data_ptr->width, data_ptr->height); 139 | uint32_t* surface_data = reinterpret_cast(data_ptr->shm_ptr); 140 | for (int i = 0; i < data_ptr->width * data_ptr->height; ++i) { 141 | surface_data[i] = data_ptr->bgcolor; 142 | } 143 | data_ptr->callback = wl_surface_frame(data_ptr->surface); 144 | wl_surface_attach(data_ptr->surface, data_ptr->buffer, 0, 0); 145 | wl_callback_add_listener(data_ptr->callback, data_ptr->callback_listener, 146 | data_ptr); 147 | wl_surface_commit(data_ptr->surface); 148 | } 149 | 150 | void output_geometry(void* data, 151 | struct wl_output* output, 152 | int32_t x, 153 | int32_t y, 154 | int32_t physical_width, 155 | int32_t physical_height, 156 | int32_t subpixel, 157 | const char* make, 158 | const char* model, 159 | int32_t transform) {} 160 | 161 | void output_mode(void* data, 162 | struct wl_output* output, 163 | uint32_t flags, 164 | int32_t width, 165 | int32_t height, 166 | int32_t refresh) { 167 | struct demo_data* data_ptr = reinterpret_cast(data); 168 | if (data_ptr->width == 0) { 169 | data_ptr->width = width; 170 | if (data_ptr->scale != 0) { 171 | data_ptr->width /= data_ptr->scale; 172 | } 173 | } 174 | if (data_ptr->height == 0) { 175 | data_ptr->height = height; 176 | if (data_ptr->scale != 0) { 177 | data_ptr->height /= data_ptr->scale; 178 | } 179 | } 180 | } 181 | 182 | void output_done(void* data, struct wl_output* output) {} 183 | 184 | void output_scale(void* data, struct wl_output* output, int32_t factor) { 185 | struct demo_data* data_ptr = reinterpret_cast(data); 186 | data_ptr->scale = factor; 187 | if (data_ptr->width != 0) { 188 | data_ptr->width /= factor; 189 | } 190 | if (data_ptr->height != 0) { 191 | data_ptr->height /= factor; 192 | } 193 | } 194 | 195 | int main(int argc, char* argv[]) { 196 | brillo::InitLog(brillo::kLogToSyslog); 197 | LOG(INFO) << "Starting wayland_demo application"; 198 | 199 | base::CommandLine::Init(argc, argv); 200 | base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); 201 | struct demo_data data; 202 | memset(&data, 0, sizeof(data)); 203 | data.done = false; 204 | 205 | data.bgcolor = 0x3388DD; 206 | if (cl->HasSwitch(kBgColorFlag)) { 207 | data.bgcolor = 208 | strtoul(cl->GetSwitchValueASCII(kBgColorFlag).c_str(), nullptr, 0); 209 | } 210 | if (cl->HasSwitch(kWidthFlag)) { 211 | if (!base::StringToUint(cl->GetSwitchValueASCII(kWidthFlag), &data.width)) { 212 | LOG(ERROR) << "Invalid width parameter passed"; 213 | return -1; 214 | } 215 | } 216 | if (cl->HasSwitch(kHeightFlag)) { 217 | if (!base::StringToUint(cl->GetSwitchValueASCII(kHeightFlag), 218 | &data.height)) { 219 | LOG(ERROR) << "Invalid height parameter passed"; 220 | return -1; 221 | } 222 | } 223 | data.title = "wayland_demo"; 224 | if (cl->HasSwitch(kTitleFlag)) { 225 | data.title = cl->GetSwitchValueASCII(kTitleFlag); 226 | } 227 | 228 | struct wl_display* display = wl_display_connect(nullptr); 229 | if (!display) { 230 | LOG(ERROR) << "Failed connecting to display"; 231 | return -1; 232 | } 233 | 234 | struct wl_output_listener output_listener = {output_geometry, output_mode, 235 | output_done, output_scale}; 236 | data.output_listener = &output_listener; 237 | struct wl_registry_listener registry_listener = { 238 | demo_registry_listener, demo_registry_remover, 239 | }; 240 | struct wl_keyboard_listener keyboard_listener = { 241 | keyboard_keymap, keyboard_enter, keyboard_leave, 242 | keyboard_key, keyboard_modifiers, keyboard_repeat_info}; 243 | data.keyboard_listener = &keyboard_listener; 244 | 245 | struct wl_registry* registry = wl_display_get_registry(display); 246 | wl_registry_add_listener(registry, ®istry_listener, &data); 247 | 248 | wl_display_dispatch(display); 249 | wl_display_roundtrip(display); 250 | 251 | if (!data.compositor) { 252 | LOG(ERROR) << "Failed to find compositor"; 253 | return -1; 254 | } 255 | if (!data.output) { 256 | LOG(ERROR) << "Failed to get output"; 257 | return -1; 258 | } 259 | 260 | // Do another roundtrip to ensure we get the wl_output callbacks. 261 | wl_display_roundtrip(display); 262 | 263 | data.surface = wl_compositor_create_surface(data.compositor); 264 | if (!data.surface) { 265 | LOG(ERROR) << "Failed creating surface"; 266 | return -1; 267 | } 268 | if (!data.shell) { 269 | LOG(ERROR) << "Failed getting shell"; 270 | return -1; 271 | } 272 | 273 | data.shell_surface = wl_shell_get_shell_surface(data.shell, data.surface); 274 | if (!data.shell_surface) { 275 | LOG(ERROR) << "Failed getting shell surface"; 276 | return -1; 277 | } 278 | const struct wl_shell_surface_listener shell_surface_listener = { 279 | shell_surface_ping, shell_surface_configure, shell_surface_popup_done}; 280 | wl_shell_surface_add_listener(data.shell_surface, &shell_surface_listener, 281 | nullptr); 282 | 283 | wl_shell_surface_set_toplevel(data.shell_surface); 284 | wl_shell_surface_set_class(data.shell_surface, data.title.c_str()); 285 | wl_shell_surface_set_title(data.shell_surface, data.title.c_str()); 286 | data.callback = wl_surface_frame(data.surface); 287 | struct wl_callback_listener callback_listener = {demo_draw}; 288 | data.callback_listener = &callback_listener; 289 | wl_callback_add_listener(data.callback, data.callback_listener, &data); 290 | 291 | if (!data.shm) { 292 | LOG(ERROR) << "Failed getting shared memory"; 293 | return -1; 294 | } 295 | 296 | size_t stride = data.width * 4 /* 32bpp */; 297 | size_t shm_size = stride * data.height; 298 | base::SharedMemory shared_mem; 299 | shared_mem.CreateAndMapAnonymous(shm_size); 300 | data.shm_ptr = shared_mem.memory(); 301 | 302 | struct wl_shm_pool* pool = 303 | wl_shm_create_pool(data.shm, shared_mem.handle().fd, shm_size); 304 | data.buffer = wl_shm_pool_create_buffer(pool, 0, data.width, data.height, 305 | stride, WL_SHM_FORMAT_XRGB8888); 306 | wl_shm_pool_destroy(pool); 307 | 308 | wl_surface_attach(data.surface, data.buffer, 0, 0); 309 | wl_surface_commit(data.surface); 310 | 311 | demo_draw(&data, nullptr, 0); 312 | LOG(INFO) << "wayland_demo application displaying, waiting for keypress"; 313 | do { 314 | } while (wl_display_dispatch(display) != -1 && !data.done); 315 | 316 | wl_display_disconnect(display); 317 | LOG(INFO) << "wayland_demo application exiting"; 318 | return 0; 319 | } 320 | -------------------------------------------------------------------------------- /demos/x11_demo.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "base/command_line.h" 12 | #include "base/logging.h" 13 | #include "base/strings/string_number_conversions.h" 14 | #include "brillo/syslog_logging.h" 15 | 16 | constexpr char kBgColorFlag[] = "bgcolor"; 17 | constexpr char kWidthFlag[] = "width"; 18 | constexpr char kHeightFlag[] = "height"; 19 | constexpr char kTitleFlag[] = "title"; 20 | 21 | // Creates an X window the same size as the display and fills its background 22 | // with a solid color that can be specified as the only parameter (in hex or 23 | // base 10). Closes on any keypress. 24 | int main(int argc, char* argv[]) { 25 | brillo::InitLog(brillo::kLogToSyslog); 26 | LOG(INFO) << "Starting x11_demo application"; 27 | 28 | base::CommandLine::Init(argc, argv); 29 | base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); 30 | uint32_t bgcolor = 0x99EE44; 31 | if (cl->HasSwitch(kBgColorFlag)) { 32 | bgcolor = 33 | strtoul(cl->GetSwitchValueASCII(kBgColorFlag).c_str(), nullptr, 0); 34 | } 35 | std::string title = "x11_demo"; 36 | if (cl->HasSwitch(kTitleFlag)) { 37 | title = cl->GetSwitchValueASCII(kTitleFlag); 38 | } 39 | 40 | Display* dpy = XOpenDisplay(nullptr); 41 | if (!dpy) { 42 | LOG(ERROR) << "Failed opening display"; 43 | return -1; 44 | } 45 | 46 | int screen = DefaultScreen(dpy); 47 | Window win; 48 | int x, y; 49 | unsigned int width, height, border, depth; 50 | if (XGetGeometry(dpy, RootWindow(dpy, screen), &win, &x, &y, &width, &height, 51 | &border, &depth) == 0) { 52 | LOG(ERROR) << "Failed getting screen geometry"; 53 | return -1; 54 | } 55 | if (cl->HasSwitch(kWidthFlag)) { 56 | if (!base::StringToUint(cl->GetSwitchValueASCII(kWidthFlag), &width)) { 57 | LOG(ERROR) << "Invalid width parameter passed"; 58 | return -1; 59 | } 60 | } 61 | if (cl->HasSwitch(kHeightFlag)) { 62 | if (!base::StringToUint(cl->GetSwitchValueASCII(kHeightFlag), &height)) { 63 | LOG(ERROR) << "Invalid height parameter passed"; 64 | return -1; 65 | } 66 | } 67 | win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), x, y, width, height, 68 | 0, 0 /* black */, bgcolor); 69 | 70 | XClassHint* wmclass_hint = XAllocClassHint(); 71 | wmclass_hint->res_name = wmclass_hint->res_class = strdup(title.c_str()); 72 | XSetClassHint(dpy, win, wmclass_hint); 73 | XSelectInput(dpy, win, KeyPressMask); 74 | XMapWindow(dpy, win); 75 | XStoreName(dpy, win, title.c_str()); 76 | 77 | LOG(INFO) << "x11_demo application displaying, waiting for keypress"; 78 | XEvent evt; 79 | for (;;) { 80 | XNextEvent(dpy, &evt); 81 | if (evt.type == KeyPress) { 82 | LOG(INFO) << "x11_demo application detected keypress"; 83 | break; 84 | } 85 | } 86 | 87 | XCloseDisplay(dpy); 88 | LOG(INFO) << "x11_demo application exiting"; 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /linux/virtwl.h: -------------------------------------------------------------------------------- 1 | #ifndef _LINUX_VIRTWL_H 2 | #define _LINUX_VIRTWL_H 3 | 4 | #ifdef __linux__ 5 | #include 6 | #include 7 | #elif defined(__FreeBSD__) 8 | #include 9 | #include 10 | #endif 11 | 12 | #define VIRTWL_SEND_MAX_ALLOCS 28 13 | 14 | #define VIRTWL_IOCTL_BASE 'w' 15 | #define VIRTWL_IO(nr) _IO(VIRTWL_IOCTL_BASE,nr) 16 | #define VIRTWL_IOR(nr,type) _IOR(VIRTWL_IOCTL_BASE,nr,type) 17 | #define VIRTWL_IOW(nr,type) _IOW(VIRTWL_IOCTL_BASE,nr,type) 18 | #define VIRTWL_IOWR(nr,type) _IOWR(VIRTWL_IOCTL_BASE,nr,type) 19 | 20 | enum virtwl_ioctl_new_type { 21 | VIRTWL_IOCTL_NEW_CTX, /* open a new wayland connection context */ 22 | VIRTWL_IOCTL_NEW_ALLOC, /* create a new virtwl shm allocation */ 23 | VIRTWL_IOCTL_NEW_PIPE_READ, /* create a new virtwl pipe that is readable via the returned fd */ 24 | VIRTWL_IOCTL_NEW_PIPE_WRITE, /* create a new virtwl pipe that is writable via the returned fd */ 25 | VIRTWL_IOCTL_NEW_DMABUF, /* create a new virtwl dmabuf that is writable via the returned fd */ 26 | }; 27 | 28 | struct virtwl_ioctl_new { 29 | __u32 type; /* VIRTWL_IOCTL_NEW_* */ 30 | int fd; /* return fd */ 31 | __u32 flags; /* currently always 0 */ 32 | union { 33 | __u32 size; /* size of allocation if type == VIRTWL_IOCTL_NEW_ALLOC */ 34 | struct { 35 | __u32 width; /* width in pixels */ 36 | __u32 height; /* height in pixels */ 37 | __u32 format; /* fourcc format */ 38 | __u32 stride0; /* return stride0 */ 39 | __u32 stride1; /* return stride1 */ 40 | __u32 stride2; /* return stride2 */ 41 | __u32 offset0; /* return offset0 */ 42 | __u32 offset1; /* return offset1 */ 43 | __u32 offset2; /* return offset2 */ 44 | } dmabuf; 45 | }; 46 | }; 47 | 48 | struct virtwl_ioctl_txn { 49 | int fds[VIRTWL_SEND_MAX_ALLOCS]; 50 | __u32 len; 51 | __u8 data[0]; 52 | }; 53 | 54 | struct virtwl_ioctl_dmabuf_sync { 55 | __u32 flags; /* synchronization flags (see dma-buf.h) */ 56 | }; 57 | 58 | #define VIRTWL_IOCTL_NEW VIRTWL_IOWR(0x00, struct virtwl_ioctl_new) 59 | #define VIRTWL_IOCTL_SEND VIRTWL_IOR(0x01, struct virtwl_ioctl_txn) 60 | #define VIRTWL_IOCTL_RECV VIRTWL_IOW(0x02, struct virtwl_ioctl_txn) 61 | #define VIRTWL_IOCTL_DMABUF_SYNC VIRTWL_IOR(0x03, \ 62 | struct virtwl_ioctl_dmabuf_sync) 63 | 64 | 65 | #endif /* _LINUX_VIRTWL_H */ 66 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # Copyright 2020 The Chromium OS 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 | project('sommelier', 'c') 6 | 7 | #===============# 8 | # Configuration # 9 | #===============# 10 | 11 | peer_cmd_prefix = get_option('peer_cmd_prefix') 12 | if peer_cmd_prefix == '' 13 | cpu_fam = target_machine.cpu_family() 14 | if cpu_fam == 'x86_64' 15 | peer_cmd_prefix = '''/opt/google/cros-containers/lib/ld-linux-x86-64.so.2 --library-path /opt/google/cros-containers/lib --inhibit-rpath ""''' 16 | elif cpu_fam == 'arm' or cpu_fam == 'aarch64' 17 | peer_cmd_prefix = '''/opt/google/cros-containers/lib/ld-linux-armhf.so.3 --library-path /opt/google/cros-containers/lib --inhibit-rpath ""''' 18 | else 19 | assert(false, 'No default peer_cmd_prefix for architecture: ' + cpu_fam) 20 | endif 21 | endif 22 | 23 | #===============# 24 | # Wayland Stuff # 25 | #===============# 26 | 27 | wl_scanner = find_program('wayland-scanner') 28 | 29 | wl_generators = [ 30 | generator( 31 | wl_scanner, 32 | output: '@BASENAME@-code.c', 33 | arguments: ['private-code', '@INPUT@', '@OUTPUT@'] 34 | ), 35 | generator( 36 | wl_scanner, 37 | output: '@BASENAME@-client-protocol.h', 38 | arguments: ['client-header', '@INPUT@', '@OUTPUT@'] 39 | ), 40 | generator( 41 | wl_scanner, 42 | output: '@BASENAME@-server-protocol.h', 43 | arguments: ['server-header', '@INPUT@', '@OUTPUT@'] 44 | ), 45 | ] 46 | 47 | wl_protocols = [ 48 | 'protocol/aura-shell.xml', 49 | 'protocol/drm.xml', 50 | 'protocol/gtk-shell.xml', 51 | 'protocol/keyboard-extension-unstable-v1.xml', 52 | 'protocol/linux-dmabuf-unstable-v1.xml', 53 | 'protocol/pointer-constraints-unstable-v1.xml', 54 | 'protocol/relative-pointer-unstable-v1.xml', 55 | 'protocol/text-input-unstable-v1.xml', 56 | 'protocol/viewporter.xml', 57 | 'protocol/xdg-shell.xml', 58 | ] 59 | 60 | wl_outs = [] 61 | 62 | foreach p : wl_protocols 63 | foreach g : wl_generators 64 | wl_outs += g.process(p) 65 | endforeach 66 | endforeach 67 | 68 | #===========# 69 | # Sommelier # 70 | #===========# 71 | 72 | executable('sommelier', 73 | install: true, 74 | sources: [ 75 | 'sommelier-compositor.c', 76 | 'sommelier-data-device-manager.c', 77 | 'sommelier-display.c', 78 | 'sommelier-drm.c', 79 | 'sommelier-gtk-shell.c', 80 | 'sommelier-output.c', 81 | 'sommelier-pointer-constraints.c', 82 | 'sommelier-relative-pointer-manager.c', 83 | 'sommelier-seat.c', 84 | 'sommelier-shell.c', 85 | 'sommelier-shm.c', 86 | 'sommelier-subcompositor.c', 87 | 'sommelier-text-input.c', 88 | 'sommelier-viewporter.c', 89 | 'sommelier-xdg-shell.c', 90 | 'sommelier.c', 91 | ] + wl_outs, 92 | dependencies: [ 93 | meson.get_compiler('c').find_library('m'), 94 | dependency('gbm'), 95 | dependency('libdrm'), 96 | dependency('pixman-1'), 97 | dependency('wayland-client'), 98 | dependency('wayland-server'), 99 | dependency('xcb'), 100 | dependency('xcb-composite'), 101 | dependency('xcb-xfixes'), 102 | dependency('xkbcommon'), 103 | ], 104 | c_args: [ 105 | '-D_GNU_SOURCE', 106 | '-DWL_HIDE_DEPRECATED', 107 | '-DXWAYLAND_PATH="' + get_option('xwayland_path') + '"', 108 | '-DXWAYLAND_GL_DRIVER_PATH="' + get_option('xwayland_gl_driver_path') + '"', 109 | '-DXWAYLAND_SHM_DRIVER="' + get_option('xwayland_shm_driver') + '"', 110 | '-DSHM_DRIVER="' + get_option('shm_driver') + '"', 111 | '-DPEER_CMD_PREFIX="' + peer_cmd_prefix + '"', 112 | '-DFRAME_COLOR="' + get_option('frame_color') + '"', 113 | '-DDARK_FRAME_COLOR="' + get_option('dark_frame_color') + '"', 114 | ], 115 | ) 116 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2020 The Chromium OS 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 | option('xwayland_path', 6 | type: 'string', 7 | value: '/usr/bin/Xwayland', 8 | description: 'path to Xwayland' 9 | ) 10 | 11 | option('xwayland_gl_driver_path', 12 | type: 'string', 13 | value: '/usr/lib/dri', 14 | description: 'the GL driver path to use for Xwayland' 15 | ) 16 | 17 | option('xwayland_shm_driver', 18 | type: 'string', 19 | value: 'virtwl', 20 | description: 'shm driver to use for Xwayland' 21 | ) 22 | 23 | option('shm_driver', 24 | type: 'string', 25 | value: 'virtwl-dmabuf', 26 | description: 'shm driver to use for wayland clients' 27 | ) 28 | 29 | option('frame_color', 30 | type: 'string', 31 | value: '#f2f2f2', 32 | description: 'frame color to use for Xwayland clients' 33 | ) 34 | 35 | option('dark_frame_color', 36 | type: 'string', 37 | value: '#323639', 38 | description: 'dark frame color to use for Xwayland clients' 39 | ) 40 | 41 | option('peer_cmd_prefix', 42 | type: 'string', 43 | value: '', 44 | description: 'command-line needed to spwan non-master sommeliers' 45 | ) 46 | -------------------------------------------------------------------------------- /protocol/aura-shell.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 2017 The Chromium Authors. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice (including the next 15 | paragraph) shall be included in all copies or substantial portions of the 16 | Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | DEALINGS IN THE SOFTWARE. 25 | 26 | 27 | 28 | 29 | The global interface exposing aura shell capabilities is used to 30 | instantiate an interface extension for a wl_surface object. 31 | This extended interface will then allow the client to use aura shell 32 | specific functionality. 33 | 34 | 35 | 36 | 38 | 40 | 41 | 42 | 43 | 44 | Instantiate an interface extension for the given wl_surface to 45 | provide aura shell functionality. If the given wl_surface is not 46 | associated with a shell surface, the shell_surface_missing protocol 47 | error is raised. 48 | 49 | 50 | 52 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | Instantiate an interface extension for the given wl_output to 61 | provide aura shell functionality. 62 | 63 | 64 | 66 | 68 | 69 | 70 | 71 | 72 | 73 | An additional interface to a wl_surface object, which allows the 74 | client to access aura shell specific functionality for surface. 75 | 76 | 77 | 78 | 79 | Frame types that can be used to decorate a surface. 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Suggests a surface should use a specific frame. 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | Set the "parent" of this surface. "x" and "y" arguments specify the 98 | initial position for surface relative to parent. 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | Set the frame colors. 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | Set the startup ID. 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | Set the application ID. 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | Set the identifier of the surface assigned by the client. 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | Enum describing why an occlusion change happened. An occlusion change as a 147 | result of a user action could include things like the user moving a window, 148 | changing occlusion, or opening/closing a window, changing the occlusion. 149 | 150 | 151 | 152 | 153 | 154 | 155 | Sets occlusion tracking on this surface. The client will be updated with a 156 | new occlusion fraction when the amount of occlusion of this surface changes. 157 | 158 | 159 | 160 | 161 | 162 | Unsets occlusion tracking for this surface. 163 | 164 | 165 | 166 | 167 | 168 | Notifies when there is a change in the amount this surface is occluded. 169 | The occlusion update is sent as a fixed point number from 0 to 1, representing 170 | the proportion of occlusion. 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | Make this the active window. This usually implies something like 181 | restacking this surface to the foreground. The compositor is free to 182 | ignore this request if it deems the client to be misbehaving. Typically 183 | this request will only be honoured in response to some user driven 184 | event, such as executing an application or opening a file in a window 185 | that already exists. 186 | 187 | 188 | 189 | 190 | 191 | Draw attention to this surface in a way that does not change the user's 192 | focus. This usually means animating window decorations or taskbar icons. 193 | The compositor can still ignore this request if it deems fit, but unlike 194 | draw_focus, these requests are expected to come from background tasks, 195 | and are more likely to be honoured. 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | Specifies how the OS will behave if this surface later goes fullscreen. 204 | Does not make the surface fullscreen. 205 | 206 | Typically the default mode is "immersive", in which the user can access 207 | the shelf by pointing to, or swiping over, the screen edge. In "plain" 208 | mode this functionality is disabled. 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | An additional interface to a wl_output object, which allows the 222 | client to access aura shell specific functionality for output. 223 | 224 | 225 | 226 | 227 | 228 | 229 | These flags describe properties of an output scale. 230 | They are used in the flags bitfield of the scale event. 231 | 232 | 234 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | The scale event describes an available scale for the output. 280 | 281 | The event is sent when binding to the output object and there 282 | will always be one scale, the current scale. The event is sent 283 | again if an output changes scale, for the scale that is now 284 | current. In other words, the current scale is always the last 285 | scale that was received with the current flag set. 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | The connection event describes how the output is connected. 301 | 302 | The event is sent when binding to the output object. 303 | 304 | 305 | 306 | 307 | 308 | 309 | This event describes the device specific scale factor for the output. 310 | 311 | The device specific scale factor is not expected the change during 312 | the lifetime of the output. And it is not limited to an integer value 313 | like the scale factor provided by wl_output interface. The exact 314 | contents scale used by the compositor can be determined by combining 315 | this device scale factor with the current output scale. 316 | 317 | The event is sent when binding to the output object. 318 | 319 | 320 | 321 | 322 | 323 | 324 | -------------------------------------------------------------------------------- /protocol/drm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright © 2008-2011 Kristian Høgsberg 6 | Copyright © 2010-2011 Intel Corporation 7 | 8 | Permission to use, copy, modify, distribute, and sell this 9 | software and its documentation for any purpose is hereby granted 10 | without fee, provided that\n the above copyright notice appear in 11 | all copies and that both that copyright notice and this permission 12 | notice appear in supporting documentation, and that the name of 13 | the copyright holders not be used in advertising or publicity 14 | pertaining to distribution of the software without specific, 15 | written prior permission. The copyright holders make no 16 | representations about the suitability of this software for any 17 | purpose. It is provided "as is" without express or implied 18 | warranty. 19 | 20 | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 21 | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 | FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 24 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 25 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 26 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 27 | THIS SOFTWARE. 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 107 | 108 | 109 | 110 | 111 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | Bitmask of capabilities. 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /protocol/gtk-shell.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | gtk_shell is a protocol extension providing additional features for 6 | clients implementing it. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /protocol/keyboard-extension-unstable-v1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 2017 The Chromium Authors. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice (including the next 15 | paragraph) shall be included in all copies or substantial portions of the 16 | Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | DEALINGS IN THE SOFTWARE. 25 | 26 | 27 | 28 | 29 | Allows a wl_keyboard to send ack_key requests for each key event of 30 | the keyboard to the server. 31 | 32 | Warning! The protocol described in this file is experimental and 33 | backward incompatible changes may be made. Backward compatible changes 34 | may be added together with the corresponding uinterface version bump. 35 | Backward incompatible changes are done by bumping the version number in 36 | the protocol and uinterface names and resetting the interface version. 37 | Once the protocol is to be declared stable, the 'z' prefix and the 38 | version number in the protocol and interface names are removed and the 39 | interface version number is reset. 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 49 | Create extended_keyboard object. 50 | See zcr_extended_keyboard interface for details. 51 | If the given wl_keyboard object already has a extended_keyboard object 52 | associated, the extended_keyboard_exists protocol error is raised. 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | The zcr_extended_keyboard_v1 interface extends the wl_keyboard interface 62 | with requests to notify whether sent key events are handled or not by 63 | the client. 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /protocol/meson.build: -------------------------------------------------------------------------------- 1 | wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true) 2 | if wayland_scanner_dep.found() 3 | wayland_scanner = find_program( 4 | wayland_scanner_dep.get_pkgconfig_variable('wayland_scanner'), 5 | native: true, 6 | ) 7 | else 8 | wayland_scanner = find_program('wayland-scanner', native: true) 9 | endif 10 | 11 | protocols = [ 12 | 'aura-shell.xml', 13 | 'drm.xml', 14 | 'gtk-shell.xml', 15 | 'keyboard-extension-unstable-v1.xml', 16 | 'linux-dmabuf-unstable-v1.xml', 17 | 'pointer-constraints-unstable-v1.xml', 18 | 'relative-pointer-unstable-v1.xml', 19 | 'text-input-unstable-v1.xml', 20 | 'viewporter.xml', 21 | 'xdg-shell.xml', 22 | ] 23 | 24 | wl_protos_src = [] 25 | wl_protos_headers = [] 26 | foreach p : protocols 27 | xml = join_paths(p) 28 | wl_protos_src += custom_target( 29 | xml.underscorify() + '_server_c', 30 | input: xml, 31 | output: '@BASENAME@-protocol.c', 32 | command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], 33 | ) 34 | wl_protos_headers += custom_target( 35 | xml.underscorify() + '_server_h', 36 | input: xml, 37 | output: '@BASENAME@-server-protocol.h', 38 | command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'], 39 | ) 40 | 41 | wl_protos_headers += custom_target( 42 | xml.underscorify() + '_client_h', 43 | input: xml, 44 | output: '@BASENAME@-client-protocol.h', 45 | command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], 46 | ) 47 | endforeach 48 | 49 | lib_sommelier_protos = static_library( 50 | 'sommelier_protos', 51 | wl_protos_src + wl_protos_headers, 52 | dependencies: wayland_client.partial_dependency(compile_args: true), 53 | ) 54 | 55 | sommelier_protos = declare_dependency( 56 | link_with: lib_sommelier_protos, 57 | sources: wl_protos_headers, 58 | ) 59 | 60 | -------------------------------------------------------------------------------- /protocol/relative-pointer-unstable-v1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright © 2014 Jonas Ådahl 6 | Copyright © 2015 Red Hat Inc. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a 9 | copy of this software and associated documentation files (the "Software"), 10 | to deal in the Software without restriction, including without limitation 11 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | and/or sell copies of the Software, and to permit persons to whom the 13 | Software is furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice (including the next 16 | paragraph) shall be included in all copies or substantial portions of the 17 | Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | 27 | 28 | 29 | This protocol specifies a set of interfaces used for making clients able to 30 | receive relative pointer events not obstructed by barriers (such as the 31 | monitor edge or other pointer barriers). 32 | 33 | To start receiving relative pointer events, a client must first bind the 34 | global interface "wp_relative_pointer_manager" which, if a compositor 35 | supports relative pointer motion events, is exposed by the registry. After 36 | having created the relative pointer manager proxy object, the client uses 37 | it to create the actual relative pointer object using the 38 | "get_relative_pointer" request given a wl_pointer. The relative pointer 39 | motion events will then, when applicable, be transmitted via the proxy of 40 | the newly created relative pointer object. See the documentation of the 41 | relative pointer interface for more details. 42 | 43 | Warning! The protocol described in this file is experimental and backward 44 | incompatible changes may be made. Backward compatible changes may be added 45 | together with the corresponding interface version bump. Backward 46 | incompatible changes are done by bumping the version number in the protocol 47 | and interface names and resetting the interface version. Once the protocol 48 | is to be declared stable, the 'z' prefix and the version number in the 49 | protocol and interface names are removed and the interface version number is 50 | reset. 51 | 52 | 53 | 54 | 55 | A global interface used for getting the relative pointer object for a 56 | given pointer. 57 | 58 | 59 | 60 | 61 | Used by the client to notify the server that it will no longer use this 62 | relative pointer manager object. 63 | 64 | 65 | 66 | 67 | 68 | Create a relative pointer interface given a wl_pointer object. See the 69 | wp_relative_pointer interface for more details. 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | A wp_relative_pointer object is an extension to the wl_pointer interface 79 | used for emitting relative pointer events. It shares the same focus as 80 | wl_pointer objects of the same seat and will only emit events when it has 81 | focus. 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | Relative x/y pointer motion from the pointer of the seat associated with 91 | this object. 92 | 93 | A relative motion is in the same dimension as regular wl_pointer motion 94 | events, except they do not represent an absolute position. For example, 95 | moving a pointer from (x, y) to (x', y') would have the equivalent 96 | relative motion (x' - x, y' - y). If a pointer motion caused the 97 | absolute pointer position to be clipped by for example the edge of the 98 | monitor, the relative motion is unaffected by the clipping and will 99 | represent the unclipped motion. 100 | 101 | This event also contains non-accelerated motion deltas. The 102 | non-accelerated delta is, when applicable, the regular pointer motion 103 | delta as it was before having applied motion acceleration and other 104 | transformations such as normalization. 105 | 106 | Note that the non-accelerated delta does not represent 'raw' events as 107 | they were read from some device. Pointer motion acceleration is device- 108 | and configuration-specific and non-accelerated deltas and accelerated 109 | deltas may have the same value on some devices. 110 | 111 | Relative motions are not coupled to wl_pointer.motion events, and can be 112 | sent in combination with such events, but also independently. There may 113 | also be scenarios where wl_pointer.motion is sent, but there is no 114 | relative motion. The order of an absolute and relative motion event 115 | originating from the same physical motion is not guaranteed. 116 | 117 | If the client needs button events or focus state, it can receive them 118 | from a wl_pointer object of the same seat that the wp_relative_pointer 119 | object is associated with. 120 | 121 | 123 | 125 | 127 | 129 | 131 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /protocol/viewporter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright © 2013-2016 Collabora, Ltd. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice (including the next 15 | paragraph) shall be included in all copies or substantial portions of the 16 | Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | DEALINGS IN THE SOFTWARE. 25 | 26 | 27 | 28 | 29 | The global interface exposing surface cropping and scaling 30 | capabilities is used to instantiate an interface extension for a 31 | wl_surface object. This extended interface will then allow 32 | cropping and scaling the surface contents, effectively 33 | disconnecting the direct relationship between the buffer and the 34 | surface size. 35 | 36 | 37 | 38 | 39 | Informs the server that the client will not be using this 40 | protocol object anymore. This does not affect any other objects, 41 | wp_viewport objects included. 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | 52 | Instantiate an interface extension for the given wl_surface to 53 | crop and scale its content. If the given wl_surface already has 54 | a wp_viewport object associated, the viewport_exists 55 | protocol error is raised. 56 | 57 | 59 | 61 | 62 | 63 | 64 | 65 | 66 | An additional interface to a wl_surface object, which allows the 67 | client to specify the cropping and scaling of the surface 68 | contents. 69 | 70 | This interface works with two concepts: the source rectangle (src_x, 71 | src_y, src_width, src_height), and the destination size (dst_width, 72 | dst_height). The contents of the source rectangle are scaled to the 73 | destination size, and content outside the source rectangle is ignored. 74 | This state is double-buffered, and is applied on the next 75 | wl_surface.commit. 76 | 77 | The two parts of crop and scale state are independent: the source 78 | rectangle, and the destination size. Initially both are unset, that 79 | is, no scaling is applied. The whole of the current wl_buffer is 80 | used as the source, and the surface size is as defined in 81 | wl_surface.attach. 82 | 83 | If the destination size is set, it causes the surface size to become 84 | dst_width, dst_height. The source (rectangle) is scaled to exactly 85 | this size. This overrides whatever the attached wl_buffer size is, 86 | unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface 87 | has no content and therefore no size. Otherwise, the size is always 88 | at least 1x1 in surface local coordinates. 89 | 90 | If the source rectangle is set, it defines what area of the wl_buffer is 91 | taken as the source. If the source rectangle is set and the destination 92 | size is not set, then src_width and src_height must be integers, and the 93 | surface size becomes the source rectangle size. This results in cropping 94 | without scaling. If src_width or src_height are not integers and 95 | destination size is not set, the bad_size protocol error is raised when 96 | the surface state is applied. 97 | 98 | The coordinate transformations from buffer pixel coordinates up to 99 | the surface-local coordinates happen in the following order: 100 | 1. buffer_transform (wl_surface.set_buffer_transform) 101 | 2. buffer_scale (wl_surface.set_buffer_scale) 102 | 3. crop and scale (wp_viewport.set*) 103 | This means, that the source rectangle coordinates of crop and scale 104 | are given in the coordinates after the buffer transform and scale, 105 | i.e. in the coordinates that would be the surface-local coordinates 106 | if the crop and scale was not applied. 107 | 108 | If src_x or src_y are negative, the bad_value protocol error is raised. 109 | Otherwise, if the source rectangle is partially or completely outside of 110 | the non-NULL wl_buffer, then the out_of_buffer protocol error is raised 111 | when the surface state is applied. A NULL wl_buffer does not raise the 112 | out_of_buffer error. 113 | 114 | The x, y arguments of wl_surface.attach are applied as normal to 115 | the surface. They indicate how many pixels to remove from the 116 | surface size from the left and the top. In other words, they are 117 | still in the surface-local coordinate system, just like dst_width 118 | and dst_height are. 119 | 120 | If the wl_surface associated with the wp_viewport is destroyed, 121 | all wp_viewport requests except 'destroy' raise the protocol error 122 | no_surface. 123 | 124 | If the wp_viewport object is destroyed, the crop and scale 125 | state is removed from the wl_surface. The change will be applied 126 | on the next wl_surface.commit. 127 | 128 | 129 | 130 | 131 | The associated wl_surface's crop and scale state is removed. 132 | The change is applied on the next wl_surface.commit. 133 | 134 | 135 | 136 | 137 | 139 | 141 | 143 | 145 | 146 | 147 | 148 | 149 | Set the source rectangle of the associated wl_surface. See 150 | wp_viewport for the description, and relation to the wl_buffer 151 | size. 152 | 153 | If all of x, y, width and height are -1.0, the source rectangle is 154 | unset instead. Any other set of values where width or height are zero 155 | or negative, or x or y are negative, raise the bad_value protocol 156 | error. 157 | 158 | The crop and scale state is double-buffered state, and will be 159 | applied on the next wl_surface.commit. 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | Set the destination size of the associated wl_surface. See 170 | wp_viewport for the description, and relation to the wl_buffer 171 | size. 172 | 173 | If width is -1 and height is -1, the destination size is unset 174 | instead. Any other pair of values for width and height that 175 | contains zero or negative values raises the bad_value protocol 176 | error. 177 | 178 | The crop and scale state is double-buffered state, and will be 179 | applied on the next wl_surface.commit. 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /sommelier-display.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static void sl_registry_bind(struct wl_client* client, 13 | struct wl_resource* resource, 14 | uint32_t name, 15 | const char* interface, 16 | uint32_t version, 17 | uint32_t id) { 18 | struct sl_host_registry* host = wl_resource_get_user_data(resource); 19 | struct sl_global* global; 20 | 21 | wl_list_for_each(global, &host->ctx->globals, link) { 22 | if (global->name == name) 23 | break; 24 | } 25 | 26 | assert(&global->link != &host->ctx->globals); 27 | assert(version != 0); 28 | assert(global->version >= version); 29 | 30 | global->bind(client, global->data, version, id); 31 | } 32 | 33 | static const struct wl_registry_interface sl_registry_implementation = { 34 | sl_registry_bind}; 35 | 36 | static void sl_sync_callback_done(void* data, 37 | struct wl_callback* callback, 38 | uint32_t serial) { 39 | struct sl_host_callback* host = wl_callback_get_user_data(callback); 40 | 41 | wl_callback_send_done(host->resource, serial); 42 | wl_resource_destroy(host->resource); 43 | } 44 | 45 | static const struct wl_callback_listener sl_sync_callback_listener = { 46 | sl_sync_callback_done}; 47 | 48 | static void sl_host_callback_destroy(struct wl_resource* resource) { 49 | struct sl_host_callback* host = wl_resource_get_user_data(resource); 50 | 51 | wl_callback_destroy(host->proxy); 52 | wl_resource_set_user_data(resource, NULL); 53 | free(host); 54 | } 55 | 56 | static void sl_display_sync(struct wl_client* client, 57 | struct wl_resource* resource, 58 | uint32_t id) { 59 | struct sl_context* ctx = wl_resource_get_user_data(resource); 60 | struct sl_host_callback* host_callback; 61 | 62 | host_callback = malloc(sizeof(*host_callback)); 63 | assert(host_callback); 64 | 65 | host_callback->resource = 66 | wl_resource_create(client, &wl_callback_interface, 1, id); 67 | wl_resource_set_implementation(host_callback->resource, NULL, host_callback, 68 | sl_host_callback_destroy); 69 | host_callback->proxy = wl_display_sync(ctx->display); 70 | wl_callback_set_user_data(host_callback->proxy, host_callback); 71 | wl_callback_add_listener(host_callback->proxy, &sl_sync_callback_listener, 72 | host_callback); 73 | } 74 | 75 | static void sl_destroy_host_registry(struct wl_resource* resource) { 76 | struct sl_host_registry* host = wl_resource_get_user_data(resource); 77 | 78 | wl_list_remove(&host->link); 79 | free(host); 80 | } 81 | 82 | static void sl_display_get_registry(struct wl_client* client, 83 | struct wl_resource* resource, 84 | uint32_t id) { 85 | struct sl_context* ctx = wl_resource_get_user_data(resource); 86 | struct sl_host_registry* host_registry; 87 | struct sl_global* global; 88 | 89 | host_registry = malloc(sizeof(*host_registry)); 90 | assert(host_registry); 91 | 92 | host_registry->ctx = ctx; 93 | host_registry->resource = 94 | wl_resource_create(client, &wl_registry_interface, 1, id); 95 | wl_list_insert(&ctx->registries, &host_registry->link); 96 | wl_resource_set_implementation(host_registry->resource, 97 | &sl_registry_implementation, host_registry, 98 | sl_destroy_host_registry); 99 | 100 | wl_list_for_each(global, &ctx->globals, link) { 101 | wl_resource_post_event(host_registry->resource, WL_REGISTRY_GLOBAL, 102 | global->name, global->interface->name, 103 | global->version); 104 | } 105 | } 106 | 107 | static const struct wl_display_interface sl_display_implementation = { 108 | sl_display_sync, sl_display_get_registry}; 109 | 110 | static enum wl_iterator_result sl_set_implementation( 111 | struct wl_resource* resource, void* user_data) { 112 | struct sl_context* ctx = (struct sl_context*)user_data; 113 | 114 | if (strcmp(wl_resource_get_class(resource), "wl_display") == 0) { 115 | wl_resource_set_implementation(resource, &sl_display_implementation, ctx, 116 | NULL); 117 | return WL_ITERATOR_STOP; 118 | } 119 | 120 | return WL_ITERATOR_CONTINUE; 121 | } 122 | 123 | void sl_set_display_implementation(struct sl_context* ctx) { 124 | // Find display resource and set implementation. 125 | wl_client_for_each_resource(ctx->client, sl_set_implementation, ctx); 126 | } 127 | -------------------------------------------------------------------------------- /sommelier-drm.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "virtgpu_drm.h" 16 | 17 | #include "drm-server-protocol.h" 18 | #include "linux-dmabuf-unstable-v1-client-protocol.h" 19 | 20 | struct sl_host_drm { 21 | struct sl_context* ctx; 22 | uint32_t version; 23 | struct wl_resource* resource; 24 | struct zwp_linux_dmabuf_v1* linux_dmabuf_proxy; 25 | struct wl_callback* callback; 26 | }; 27 | 28 | static void sl_drm_authenticate(struct wl_client* client, 29 | struct wl_resource* resource, 30 | uint32_t id) { 31 | wl_drm_send_authenticated(resource); 32 | } 33 | 34 | static void sl_drm_create_buffer(struct wl_client* client, 35 | struct wl_resource* resource, 36 | uint32_t id, 37 | uint32_t name, 38 | int32_t width, 39 | int32_t height, 40 | uint32_t stride, 41 | uint32_t format) { 42 | assert(0); 43 | } 44 | 45 | static void sl_drm_create_planar_buffer(struct wl_client* client, 46 | struct wl_resource* resource, 47 | uint32_t id, 48 | uint32_t name, 49 | int32_t width, 50 | int32_t height, 51 | uint32_t format, 52 | int32_t offset0, 53 | int32_t stride0, 54 | int32_t offset1, 55 | int32_t stride1, 56 | int32_t offset2, 57 | int32_t stride2) { 58 | assert(0); 59 | } 60 | 61 | static void sl_drm_sync(struct sl_context* ctx, 62 | struct sl_sync_point* sync_point) { 63 | int drm_fd = gbm_device_get_fd(ctx->gbm); 64 | struct drm_prime_handle prime_handle; 65 | int ret; 66 | 67 | // First imports the prime fd to a gem handle. This will fail if this 68 | // function was not passed a prime handle that can be imported by the drm 69 | // device given to sommelier. 70 | memset(&prime_handle, 0, sizeof(prime_handle)); 71 | prime_handle.fd = sync_point->fd; 72 | ret = drmIoctl(drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_handle); 73 | if (!ret) { 74 | struct drm_virtgpu_3d_wait wait_arg; 75 | struct drm_gem_close gem_close; 76 | 77 | // Then attempts to wait for GPU operations to complete. This will fail 78 | // silently if the drm device passed to sommelier is not a virtio-gpu 79 | // device. 80 | memset(&wait_arg, 0, sizeof(wait_arg)); 81 | wait_arg.handle = prime_handle.handle; 82 | drmIoctl(drm_fd, DRM_IOCTL_VIRTGPU_WAIT, &wait_arg); 83 | 84 | // Always close the handle we imported. 85 | memset(&gem_close, 0, sizeof(gem_close)); 86 | gem_close.handle = prime_handle.handle; 87 | drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close); 88 | } 89 | } 90 | 91 | static void sl_drm_create_prime_buffer(struct wl_client* client, 92 | struct wl_resource* resource, 93 | uint32_t id, 94 | int32_t name, 95 | int32_t width, 96 | int32_t height, 97 | uint32_t format, 98 | int32_t offset0, 99 | int32_t stride0, 100 | int32_t offset1, 101 | int32_t stride1, 102 | int32_t offset2, 103 | int32_t stride2) { 104 | struct sl_host_drm* host = wl_resource_get_user_data(resource); 105 | struct zwp_linux_buffer_params_v1* buffer_params; 106 | 107 | assert(name >= 0); 108 | assert(!offset1); 109 | assert(!stride1); 110 | assert(!offset2); 111 | assert(!stride2); 112 | 113 | // Attempts to correct stride0 with virtio-gpu specific resource information, 114 | // if available. Ideally mesa/gbm should have the correct stride. Remove 115 | // after crbug.com/892242 is resolved in mesa. 116 | int is_gpu_buffer = 0; 117 | if (host->ctx->gbm) { 118 | int drm_fd = gbm_device_get_fd(host->ctx->gbm); 119 | struct drm_prime_handle prime_handle; 120 | int ret; 121 | 122 | // First imports the prime fd to a gem handle. This will fail if this 123 | // function was not passed a prime handle that can be imported by the drm 124 | // device given to sommelier. 125 | memset(&prime_handle, 0, sizeof(prime_handle)); 126 | prime_handle.fd = name; 127 | ret = drmIoctl(drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_handle); 128 | if (!ret) { 129 | struct drm_virtgpu_resource_info info_arg; 130 | struct drm_gem_close gem_close; 131 | 132 | // Then attempts to get resource information. This will fail silently if 133 | // the drm device passed to sommelier is not a virtio-gpu device. 134 | memset(&info_arg, 0, sizeof(info_arg)); 135 | info_arg.bo_handle = prime_handle.handle; 136 | ret = drmIoctl(drm_fd, DRM_IOCTL_VIRTGPU_RESOURCE_INFO, &info_arg); 137 | // Correct stride0 if we are able to get proper resource info. 138 | if (!ret) { 139 | stride0 = info_arg.stride; 140 | is_gpu_buffer = 1; 141 | } 142 | 143 | // Always close the handle we imported. 144 | memset(&gem_close, 0, sizeof(gem_close)); 145 | gem_close.handle = prime_handle.handle; 146 | drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close); 147 | } 148 | } 149 | 150 | buffer_params = 151 | zwp_linux_dmabuf_v1_create_params(host->ctx->linux_dmabuf->internal); 152 | zwp_linux_buffer_params_v1_add(buffer_params, name, 0, offset0, stride0, 153 | DRM_FORMAT_MOD_INVALID >> 32, 154 | DRM_FORMAT_MOD_INVALID & 0xffffffff); 155 | 156 | struct sl_host_buffer* host_buffer = 157 | sl_create_host_buffer(client, id, 158 | zwp_linux_buffer_params_v1_create_immed( 159 | buffer_params, width, height, format, 0), 160 | width, height); 161 | if (is_gpu_buffer) { 162 | host_buffer->sync_point = sl_sync_point_create(name); 163 | host_buffer->sync_point->sync = sl_drm_sync; 164 | } else { 165 | close(name); 166 | } 167 | 168 | zwp_linux_buffer_params_v1_destroy(buffer_params); 169 | } 170 | 171 | static const struct wl_drm_interface sl_drm_implementation = { 172 | sl_drm_authenticate, sl_drm_create_buffer, sl_drm_create_planar_buffer, 173 | sl_drm_create_prime_buffer}; 174 | 175 | static void sl_destroy_host_drm(struct wl_resource* resource) { 176 | struct sl_host_drm* host = wl_resource_get_user_data(resource); 177 | 178 | zwp_linux_dmabuf_v1_destroy(host->linux_dmabuf_proxy); 179 | wl_callback_destroy(host->callback); 180 | wl_resource_set_user_data(resource, NULL); 181 | free(host); 182 | } 183 | 184 | static void sl_drm_format(void* data, 185 | struct zwp_linux_dmabuf_v1* linux_dmabuf, 186 | uint32_t format) { 187 | struct sl_host_drm* host = zwp_linux_dmabuf_v1_get_user_data(linux_dmabuf); 188 | 189 | switch (format) { 190 | case WL_DRM_FORMAT_RGB565: 191 | case WL_DRM_FORMAT_ARGB8888: 192 | case WL_DRM_FORMAT_ABGR8888: 193 | case WL_DRM_FORMAT_XRGB8888: 194 | case WL_DRM_FORMAT_XBGR8888: 195 | wl_drm_send_format(host->resource, format); 196 | break; 197 | default: 198 | break; 199 | } 200 | } 201 | 202 | static void sl_drm_modifier(void* data, 203 | struct zwp_linux_dmabuf_v1* linux_dmabuf, 204 | uint32_t format, 205 | uint32_t modifier_hi, 206 | uint32_t modifier_lo) {} 207 | 208 | static const struct zwp_linux_dmabuf_v1_listener sl_linux_dmabuf_listener = { 209 | sl_drm_format, sl_drm_modifier}; 210 | 211 | static void sl_drm_callback_done(void* data, 212 | struct wl_callback* callback, 213 | uint32_t serial) { 214 | struct sl_host_drm* host = wl_callback_get_user_data(callback); 215 | 216 | if (host->ctx->drm_device) 217 | wl_drm_send_device(host->resource, host->ctx->drm_device); 218 | if (host->version >= WL_DRM_CREATE_PRIME_BUFFER_SINCE_VERSION) 219 | wl_drm_send_capabilities(host->resource, WL_DRM_CAPABILITY_PRIME); 220 | } 221 | 222 | static const struct wl_callback_listener sl_drm_callback_listener = { 223 | sl_drm_callback_done}; 224 | 225 | static void sl_bind_host_drm(struct wl_client* client, 226 | void* data, 227 | uint32_t version, 228 | uint32_t id) { 229 | struct sl_context* ctx = (struct sl_context*)data; 230 | struct sl_host_drm* host; 231 | 232 | host = malloc(sizeof(*host)); 233 | assert(host); 234 | host->ctx = ctx; 235 | host->version = MIN(version, 2); 236 | host->resource = 237 | wl_resource_create(client, &wl_drm_interface, host->version, id); 238 | wl_resource_set_implementation(host->resource, &sl_drm_implementation, host, 239 | sl_destroy_host_drm); 240 | 241 | host->linux_dmabuf_proxy = wl_registry_bind( 242 | wl_display_get_registry(ctx->display), ctx->linux_dmabuf->id, 243 | &zwp_linux_dmabuf_v1_interface, ctx->linux_dmabuf->version); 244 | zwp_linux_dmabuf_v1_set_user_data(host->linux_dmabuf_proxy, host); 245 | zwp_linux_dmabuf_v1_add_listener(host->linux_dmabuf_proxy, 246 | &sl_linux_dmabuf_listener, host); 247 | 248 | host->callback = wl_display_sync(ctx->display); 249 | wl_callback_set_user_data(host->callback, host); 250 | wl_callback_add_listener(host->callback, &sl_drm_callback_listener, host); 251 | } 252 | 253 | struct sl_global* sl_drm_global_create(struct sl_context* ctx) { 254 | assert(ctx->linux_dmabuf); 255 | 256 | // Early out if DMABuf protocol version is not sufficient. 257 | if (ctx->linux_dmabuf->version < 2) 258 | return NULL; 259 | 260 | return sl_global_create(ctx, &wl_drm_interface, 2, ctx, sl_bind_host_drm); 261 | } 262 | -------------------------------------------------------------------------------- /sommelier-gtk-shell.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "aura-shell-client-protocol.h" 12 | #include "gtk-shell-server-protocol.h" 13 | 14 | struct sl_host_gtk_shell { 15 | struct sl_aura_shell* aura_shell; 16 | struct wl_resource* resource; 17 | struct zaura_shell* proxy; 18 | struct wl_callback* callback; 19 | char* startup_id; 20 | struct wl_list surfaces; 21 | }; 22 | 23 | struct sl_host_gtk_surface { 24 | struct wl_resource* resource; 25 | struct zaura_surface* proxy; 26 | struct wl_list link; 27 | struct sl_aura_shell* aura_shell; 28 | }; 29 | 30 | static void sl_gtk_surface_set_dbus_properties( 31 | struct wl_client* client, 32 | struct wl_resource* resource, 33 | const char* application_id, 34 | const char* app_menu_path, 35 | const char* menubar_path, 36 | const char* window_object_path, 37 | const char* application_object_path, 38 | const char* unique_bus_name) { 39 | struct sl_host_gtk_surface* host = wl_resource_get_user_data(resource); 40 | 41 | zaura_surface_set_application_id(host->proxy, application_id); 42 | } 43 | 44 | static void sl_gtk_surface_set_modal(struct wl_client* client, 45 | struct wl_resource* resource) {} 46 | 47 | static void sl_gtk_surface_unset_modal(struct wl_client* client, 48 | struct wl_resource* resource) {} 49 | 50 | static void sl_gtk_surface_present(struct wl_client* client, 51 | struct wl_resource* resource, 52 | uint32_t time) {} 53 | 54 | static const struct gtk_surface1_interface sl_gtk_surface_implementation = { 55 | sl_gtk_surface_set_dbus_properties, sl_gtk_surface_set_modal, 56 | sl_gtk_surface_unset_modal, sl_gtk_surface_present}; 57 | 58 | static void sl_destroy_host_gtk_surface(struct wl_resource* resource) { 59 | struct sl_host_gtk_surface* host = wl_resource_get_user_data(resource); 60 | 61 | zaura_surface_destroy(host->proxy); 62 | wl_list_remove(&host->link); 63 | wl_resource_set_user_data(resource, NULL); 64 | free(host); 65 | } 66 | 67 | static void sl_gtk_shell_get_gtk_surface(struct wl_client* client, 68 | struct wl_resource* resource, 69 | uint32_t id, 70 | struct wl_resource* surface_resource) { 71 | struct sl_host_gtk_shell* host = wl_resource_get_user_data(resource); 72 | struct sl_host_surface* host_surface = 73 | wl_resource_get_user_data(surface_resource); 74 | struct sl_host_gtk_surface* host_gtk_surface; 75 | 76 | host_gtk_surface = malloc(sizeof(*host_gtk_surface)); 77 | assert(host_gtk_surface); 78 | 79 | wl_list_insert(&host->surfaces, &host_gtk_surface->link); 80 | host_gtk_surface->aura_shell = host->aura_shell; 81 | host_gtk_surface->resource = 82 | wl_resource_create(client, >k_surface1_interface, 1, id); 83 | wl_resource_set_implementation(host_gtk_surface->resource, 84 | &sl_gtk_surface_implementation, 85 | host_gtk_surface, sl_destroy_host_gtk_surface); 86 | host_gtk_surface->proxy = 87 | zaura_shell_get_aura_surface(host->proxy, host_surface->proxy); 88 | zaura_surface_set_startup_id(host_gtk_surface->proxy, host->startup_id); 89 | } 90 | 91 | static void sl_gtk_shell_set_startup_id(struct wl_client* client, 92 | struct wl_resource* resource, 93 | const char* startup_id) { 94 | struct sl_host_gtk_shell* host = wl_resource_get_user_data(resource); 95 | struct sl_host_gtk_surface* surface; 96 | 97 | free(host->startup_id); 98 | host->startup_id = startup_id ? strdup(startup_id) : NULL; 99 | 100 | wl_list_for_each(surface, &host->surfaces, link) 101 | zaura_surface_set_startup_id(surface->proxy, host->startup_id); 102 | } 103 | 104 | static void sl_gtk_shell_system_bell(struct wl_client* client, 105 | struct wl_resource* resource, 106 | struct wl_resource* surface_resource) {} 107 | 108 | static const struct gtk_shell1_interface sl_gtk_shell_implementation = { 109 | sl_gtk_shell_get_gtk_surface, sl_gtk_shell_set_startup_id, 110 | sl_gtk_shell_system_bell}; 111 | 112 | static void sl_destroy_host_gtk_shell(struct wl_resource* resource) { 113 | struct sl_host_gtk_shell* host = wl_resource_get_user_data(resource); 114 | 115 | free(host->startup_id); 116 | wl_callback_destroy(host->callback); 117 | zaura_shell_destroy(host->proxy); 118 | wl_resource_set_user_data(resource, NULL); 119 | free(host); 120 | } 121 | 122 | static void sl_gtk_shell_callback_done(void* data, 123 | struct wl_callback* callback, 124 | uint32_t serial) { 125 | struct sl_host_gtk_shell* host = wl_callback_get_user_data(callback); 126 | 127 | gtk_shell1_send_capabilities(host->resource, 0); 128 | } 129 | 130 | static const struct wl_callback_listener sl_gtk_shell_callback_listener = { 131 | sl_gtk_shell_callback_done}; 132 | 133 | static void sl_bind_host_gtk_shell(struct wl_client* client, 134 | void* data, 135 | uint32_t version, 136 | uint32_t id) { 137 | struct sl_context* ctx = (struct sl_context*)data; 138 | struct sl_host_gtk_shell* host; 139 | 140 | host = malloc(sizeof(*host)); 141 | assert(host); 142 | host->aura_shell = ctx->aura_shell; 143 | host->startup_id = NULL; 144 | wl_list_init(&host->surfaces); 145 | host->resource = wl_resource_create(client, >k_shell1_interface, 1, id); 146 | wl_resource_set_implementation(host->resource, &sl_gtk_shell_implementation, 147 | host, sl_destroy_host_gtk_shell); 148 | host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display), 149 | ctx->aura_shell->id, &zaura_shell_interface, 150 | ctx->aura_shell->version); 151 | zaura_shell_set_user_data(host->proxy, host); 152 | 153 | host->callback = wl_display_sync(ctx->aura_shell->ctx->display); 154 | wl_callback_set_user_data(host->callback, host); 155 | wl_callback_add_listener(host->callback, &sl_gtk_shell_callback_listener, 156 | host); 157 | } 158 | 159 | struct sl_global* sl_gtk_shell_global_create(struct sl_context* ctx) { 160 | return sl_global_create(ctx, >k_shell1_interface, 1, ctx, 161 | sl_bind_host_gtk_shell); 162 | } -------------------------------------------------------------------------------- /sommelier-output.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "aura-shell-client-protocol.h" 13 | 14 | #define MAX_OUTPUT_SCALE 2 15 | 16 | #define INCH_IN_MM 25.4 17 | 18 | // Legacy X11 applications use DPI to decide on their scale. This value is what 19 | // the convention for a "normal" scale is. One way to verify the convention is 20 | // to note the DPI of a typical monitor circa ~2005, i.e. 20" 1080p. 21 | #define DEFACTO_DPI 96 22 | 23 | double sl_output_aura_scale_factor_to_double(int scale_factor) { 24 | // Aura scale factor is an enum that for all currently know values 25 | // is a scale value multipled by 1000. For example, enum value for 26 | // 1.25 scale factor is 1250. 27 | return scale_factor / 1000.0; 28 | } 29 | 30 | int dpi_to_physical_mm(double dpi, int px) { 31 | return px * (INCH_IN_MM / dpi); 32 | } 33 | 34 | void sl_output_get_host_output_state(struct sl_host_output* host, 35 | int* scale, 36 | int* physical_width, 37 | int* physical_height, 38 | int* width, 39 | int* height) { 40 | // The user's chosen zoom level. 41 | double current_scale = 42 | sl_output_aura_scale_factor_to_double(host->current_scale); 43 | 44 | // The scale applied to a screen at the default zoom. I.e. this value 45 | // determines the meaning of "100%" zoom, and how zoom relates to the 46 | // apparent resolution: 47 | // 48 | // apparent_res = native_res / device_scale_factor * current_scale 49 | // 50 | // e.g.: On a device with a DSF of 2.0, 80% zoom really means "apply 1.6x 51 | // scale", and 50% zoom would give you an apparent resolution equal to the 52 | // native one. 53 | double device_scale_factor = 54 | sl_output_aura_scale_factor_to_double(host->device_scale_factor); 55 | 56 | // Optimistically, we will try to apply the scale that the user chose. 57 | // Failing that, we will use the scale set for this wl_output. 58 | double applied_scale = device_scale_factor * current_scale; 59 | 60 | if (host->applied_scale < 0) { 61 | if (!host->ctx->aura_shell) { 62 | applied_scale = host->scale_factor; 63 | } 64 | 65 | if (host->ctx->overridden_output_scales) { 66 | const char* scales = host->ctx->overridden_output_scales; 67 | int output_name_size = strlen(host->name); 68 | while (true) { 69 | if (strncmp(scales, host->name, output_name_size) == 0 && scales[output_name_size] == '=') { 70 | scales += output_name_size + 1; 71 | applied_scale = strtod(scales, NULL); 72 | fprintf(stderr, "Applied overridden scale %lf for output %s\n", applied_scale, host->name); 73 | break; 74 | } 75 | scales = strstr(scales, ","); 76 | if (scales == NULL) { 77 | break; 78 | } 79 | ++scales; 80 | } 81 | } 82 | 83 | host->applied_scale = applied_scale; 84 | } else { 85 | applied_scale = host->applied_scale; 86 | } 87 | 88 | int target_dpi = DEFACTO_DPI; 89 | if (host->ctx->xwayland) { 90 | // For X11, we must fix the scale to be 1 (since X apps typically can't 91 | // handle scaling). As a result, we adjust the resolution (based on the 92 | // scale we want to apply and sommelier's configuration) and the physical 93 | // dimensions (based on what DPI we want the applications to use). E.g.: 94 | // - Device scale is 1.25x, with 1920x1080 resolution on a 295mm by 165mm 95 | // screen. 96 | // - User chosen zoom is 130% 97 | // - Sommelier is scaled to 0.5 (a.k.a low density). Since ctx->scale also 98 | // has the device scale, it will be 0.625 (i.e. 0.5 * 1.25). 99 | // - We want the DPI to be 120 (i.e. 96 * 1.25) 100 | // - Meaning 0.21 mm/px 101 | // - We report resolution 738x415 (1920x1080 * 0.5 / 1.3) 102 | // - We report dimensions 155mm by 87mm (738x415 * 0.21) 103 | // This is mostly expected, another way of thinking about them is that zoom 104 | // and scale modify the application's understanding of length: 105 | // - Increasing the zoom makes lengths appear longer (i.e. fewer mm to work 106 | // with over the same real length). 107 | // - Scaling the screen does the inverse. 108 | if (scale) 109 | *scale = 1; 110 | *width = host->width * host->ctx->scale / applied_scale; 111 | *height = host->height * host->ctx->scale / applied_scale; 112 | 113 | target_dpi = DEFACTO_DPI * device_scale_factor; 114 | *physical_width = dpi_to_physical_mm(target_dpi, *width); 115 | *physical_height = dpi_to_physical_mm(target_dpi, *height); 116 | } else { 117 | // For wayland, we directly apply the scale which combines the user's chosen 118 | // preference (from aura) and the scale which this sommelier was configured 119 | // for (i.e. based on ctx->scale, which comes from the env/cmd line). 120 | // 121 | // See above comment: ctx->scale already has the device_scale_factor in it, 122 | // so this maths actually looks like: 123 | // 124 | // applied / ctx->scale 125 | // = (current*DSF) / (config*DSF) 126 | // = current / config 127 | // 128 | // E.g. if we configured sommelier to scale everything 0.5x, and the user 129 | // has chosen 130% zoom, we are applying 2.6x scale factor. 130 | int s = MIN(ceil(applied_scale / host->ctx->scale), MAX_OUTPUT_SCALE); 131 | 132 | if (scale) 133 | *scale = s; 134 | *physical_width = host->physical_width; 135 | *physical_height = host->physical_height; 136 | *width = host->width * host->ctx->scale * s / applied_scale; 137 | *height = host->height * host->ctx->scale * s / applied_scale; 138 | target_dpi = (*width * INCH_IN_MM) / *physical_width; 139 | } 140 | 141 | if (host->ctx->dpi.size) { 142 | int adjusted_dpi = *((int*)host->ctx->dpi.data); 143 | int* p; 144 | 145 | // Choose the DPI bucket which is closest to the target DPI which we 146 | // calculated above. 147 | wl_array_for_each(p, &host->ctx->dpi) { 148 | if (abs(*p - target_dpi) < abs(adjusted_dpi - target_dpi)) 149 | adjusted_dpi = *p; 150 | } 151 | 152 | *physical_width = dpi_to_physical_mm(adjusted_dpi, *width); 153 | *physical_height = dpi_to_physical_mm(adjusted_dpi, *height); 154 | } 155 | } 156 | 157 | void sl_output_send_host_output_state(struct sl_host_output* host) { 158 | int scale; 159 | int physical_width; 160 | int physical_height; 161 | int width; 162 | int height; 163 | 164 | sl_output_get_host_output_state(host, &scale, &physical_width, 165 | &physical_height, &width, &height); 166 | 167 | // Use density of internal display for all Xwayland outputs. X11 clients 168 | // typically lack support for dynamically changing density so it's 169 | // preferred to always use the density of the internal display. 170 | if (host->ctx->xwayland) { 171 | struct sl_host_output* output; 172 | 173 | wl_list_for_each(output, &host->ctx->host_outputs, link) { 174 | if (output->internal) { 175 | int internal_width; 176 | int internal_height; 177 | 178 | sl_output_get_host_output_state(output, NULL, &physical_width, 179 | &physical_height, &internal_width, 180 | &internal_height); 181 | 182 | physical_width = (physical_width * width) / internal_width; 183 | physical_height = (physical_height * height) / internal_height; 184 | break; 185 | } 186 | } 187 | } 188 | 189 | // X/Y are best left at origin as managed X windows are kept centered on 190 | // the root window. The result is that all outputs are overlapping and 191 | // pointer events can always be dispatched to the visible region of the 192 | // window. 193 | wl_output_send_geometry(host->resource, 0, 0, physical_width, physical_height, 194 | host->subpixel, host->make, host->model, 195 | host->transform); 196 | wl_output_send_mode(host->resource, host->flags | WL_OUTPUT_MODE_CURRENT, 197 | width, height, host->refresh); 198 | if (wl_resource_get_version(host->resource) >= WL_OUTPUT_SCALE_SINCE_VERSION) 199 | wl_output_send_scale(host->resource, scale); 200 | if (wl_resource_get_version(host->resource) >= WL_OUTPUT_DONE_SINCE_VERSION) 201 | wl_output_send_done(host->resource); 202 | } 203 | 204 | static void sl_output_geometry(void* data, 205 | struct wl_output* output, 206 | int x, 207 | int y, 208 | int physical_width, 209 | int physical_height, 210 | int subpixel, 211 | const char* make, 212 | const char* model, 213 | int transform) { 214 | struct sl_host_output* host = wl_output_get_user_data(output); 215 | 216 | host->x = x; 217 | host->y = y; 218 | host->physical_width = physical_width; 219 | host->physical_height = physical_height; 220 | host->subpixel = subpixel; 221 | free(host->model); 222 | host->model = strdup(model); 223 | free(host->make); 224 | host->make = strdup(make); 225 | host->transform = transform; 226 | } 227 | 228 | static void sl_output_mode(void* data, 229 | struct wl_output* output, 230 | uint32_t flags, 231 | int width, 232 | int height, 233 | int refresh) { 234 | struct sl_host_output* host = wl_output_get_user_data(output); 235 | 236 | host->flags = flags; 237 | host->width = width; 238 | host->height = height; 239 | host->refresh = refresh; 240 | } 241 | 242 | static void sl_output_done(void* data, struct wl_output* output) { 243 | struct sl_host_output* host = wl_output_get_user_data(output); 244 | 245 | // Early out if scale is expected but not yet know. 246 | if (host->expecting_scale) 247 | return; 248 | 249 | sl_output_send_host_output_state(host); 250 | 251 | // Expect scale if aura output exists. 252 | if (host->aura_output) 253 | host->expecting_scale = 1; 254 | } 255 | 256 | static void sl_output_scale(void* data, 257 | struct wl_output* output, 258 | int32_t scale_factor) { 259 | struct sl_host_output* host = wl_output_get_user_data(output); 260 | 261 | host->scale_factor = scale_factor; 262 | } 263 | 264 | static void sl_output_name(void* data, 265 | struct wl_output* output, 266 | const char* name) { 267 | struct sl_host_output* host = wl_output_get_user_data(output); 268 | 269 | free(host->name); 270 | host->name = strdup(name); 271 | } 272 | 273 | static void sl_output_description(void *data, 274 | struct wl_output *wl_output, 275 | const char *description) {} 276 | 277 | static const struct wl_output_listener sl_output_listener = { 278 | sl_output_geometry, sl_output_mode, sl_output_done, sl_output_scale, 279 | sl_output_name, sl_output_description}; 280 | 281 | static void sl_aura_output_scale(void* data, 282 | struct zaura_output* output, 283 | uint32_t flags, 284 | uint32_t scale) { 285 | struct sl_host_output* host = zaura_output_get_user_data(output); 286 | 287 | if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT) 288 | host->current_scale = scale; 289 | if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED) 290 | host->preferred_scale = scale; 291 | 292 | host->expecting_scale = 0; 293 | } 294 | 295 | static void sl_aura_output_connection(void* data, 296 | struct zaura_output* output, 297 | uint32_t connection) { 298 | struct sl_host_output* host = zaura_output_get_user_data(output); 299 | 300 | host->internal = connection == ZAURA_OUTPUT_CONNECTION_TYPE_INTERNAL; 301 | } 302 | 303 | static void sl_aura_output_device_scale_factor(void* data, 304 | struct zaura_output* output, 305 | uint32_t device_scale_factor) { 306 | struct sl_host_output* host = zaura_output_get_user_data(output); 307 | 308 | host->device_scale_factor = device_scale_factor; 309 | } 310 | 311 | static const struct zaura_output_listener sl_aura_output_listener = { 312 | sl_aura_output_scale, sl_aura_output_connection, 313 | sl_aura_output_device_scale_factor}; 314 | 315 | static void sl_destroy_host_output(struct wl_resource* resource) { 316 | struct sl_host_output* host = wl_resource_get_user_data(resource); 317 | 318 | if (host->aura_output) 319 | zaura_output_destroy(host->aura_output); 320 | if (wl_output_get_version(host->proxy) >= WL_OUTPUT_RELEASE_SINCE_VERSION) { 321 | wl_output_release(host->proxy); 322 | } else { 323 | wl_output_destroy(host->proxy); 324 | } 325 | wl_resource_set_user_data(resource, NULL); 326 | wl_list_remove(&host->link); 327 | free(host->make); 328 | free(host->model); 329 | free(host->name); 330 | free(host); 331 | } 332 | 333 | static void sl_bind_host_output(struct wl_client* client, 334 | void* data, 335 | uint32_t version, 336 | uint32_t id) { 337 | struct sl_output* output = (struct sl_output*)data; 338 | struct sl_context* ctx = output->ctx; 339 | struct sl_host_output* host; 340 | 341 | host = malloc(sizeof(*host)); 342 | assert(host); 343 | host->ctx = ctx; 344 | host->resource = wl_resource_create(client, &wl_output_interface, 345 | MIN(version, output->version), id); 346 | wl_resource_set_implementation(host->resource, NULL, host, 347 | sl_destroy_host_output); 348 | host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display), 349 | output->id, &wl_output_interface, 350 | wl_resource_get_version(host->resource)); 351 | wl_output_set_user_data(host->proxy, host); 352 | wl_output_add_listener(host->proxy, &sl_output_listener, host); 353 | host->aura_output = NULL; 354 | // We assume that first output is internal by default. 355 | host->internal = wl_list_empty(&ctx->host_outputs); 356 | host->x = 0; 357 | host->y = 0; 358 | host->physical_width = 0; 359 | host->physical_height = 0; 360 | host->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; 361 | host->make = strdup("unknown"); 362 | host->model = strdup("unknown"); 363 | host->name = NULL; 364 | host->transform = WL_OUTPUT_TRANSFORM_NORMAL; 365 | host->flags = 0; 366 | host->width = 1024; 367 | host->height = 768; 368 | host->refresh = 60000; 369 | host->scale_factor = 1; 370 | host->current_scale = 1000; 371 | host->preferred_scale = 1000; 372 | host->device_scale_factor = 1000; 373 | host->expecting_scale = 0; 374 | host->applied_scale = -1; 375 | wl_list_insert(ctx->host_outputs.prev, &host->link); 376 | if (ctx->aura_shell) { 377 | host->expecting_scale = 1; 378 | host->internal = 0; 379 | host->aura_output = 380 | zaura_shell_get_aura_output(ctx->aura_shell->internal, host->proxy); 381 | zaura_output_set_user_data(host->aura_output, host); 382 | zaura_output_add_listener(host->aura_output, &sl_aura_output_listener, 383 | host); 384 | } 385 | } 386 | 387 | struct sl_global* sl_output_global_create(struct sl_output* output) { 388 | return sl_global_create(output->ctx, &wl_output_interface, output->version, 389 | output, sl_bind_host_output); 390 | } 391 | -------------------------------------------------------------------------------- /sommelier-pointer-constraints.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "pointer-constraints-unstable-v1-server-protocol.h" 17 | #include "pointer-constraints-unstable-v1-client-protocol.h" 18 | 19 | #define SL_HOST_OBJECT(NAME, INTERFACE) \ 20 | struct sl_host_##NAME { \ 21 | struct sl_context* ctx; \ 22 | struct wl_resource* resource; \ 23 | struct INTERFACE* proxy; \ 24 | }; \ 25 | static void sl_destroy_host_##NAME(struct wl_resource* resource) { \ 26 | struct sl_host_##NAME* host = wl_resource_get_user_data(resource); \ 27 | INTERFACE##_destroy(host->proxy); \ 28 | wl_resource_set_user_data(resource, NULL); \ 29 | free(host); \ 30 | } \ 31 | static void sl_##NAME##_destroy(struct wl_client* client, \ 32 | struct wl_resource* resource) { \ 33 | wl_resource_destroy(resource); \ 34 | } 35 | 36 | SL_HOST_OBJECT(pointer_constraints, zwp_pointer_constraints_v1); 37 | 38 | SL_HOST_OBJECT(locked_pointer, zwp_locked_pointer_v1); 39 | 40 | SL_HOST_OBJECT(confined_pointer, zwp_confined_pointer_v1); 41 | 42 | static void sl_locked_pointer_locked( 43 | void* data, struct zwp_locked_pointer_v1* locked_pointer) { 44 | struct sl_host_locked_pointer* host = 45 | zwp_locked_pointer_v1_get_user_data(locked_pointer); 46 | 47 | zwp_locked_pointer_v1_send_locked(host->resource); 48 | } 49 | 50 | static void sl_locked_pointer_unlocked( 51 | void* data, struct zwp_locked_pointer_v1* locked_pointer) { 52 | struct sl_host_locked_pointer* host = 53 | zwp_locked_pointer_v1_get_user_data(locked_pointer); 54 | 55 | zwp_locked_pointer_v1_send_unlocked(host->resource); 56 | } 57 | 58 | static void sl_locked_pointer_set_cursor_position_hint( 59 | struct wl_client* client, 60 | struct wl_resource* resource, 61 | wl_fixed_t surface_x, 62 | wl_fixed_t surface_y) { 63 | struct sl_host_locked_pointer* host = wl_resource_get_user_data(resource); 64 | double scale = host->ctx->scale; 65 | 66 | zwp_locked_pointer_v1_set_cursor_position_hint(host->proxy, surface_x / scale, 67 | surface_y / scale); 68 | } 69 | 70 | static void sl_locked_pointer_set_region(struct wl_client* client, 71 | struct wl_resource* resource, 72 | struct wl_resource* region) { 73 | struct sl_host_locked_pointer* host = wl_resource_get_user_data(resource); 74 | struct sl_host_region* host_region = 75 | region ? wl_resource_get_user_data(region) : NULL; 76 | 77 | zwp_locked_pointer_v1_set_region(host->proxy, 78 | host_region ? host_region->proxy : NULL); 79 | } 80 | 81 | static struct zwp_locked_pointer_v1_listener sl_locked_pointer_listener = { 82 | sl_locked_pointer_locked, 83 | sl_locked_pointer_unlocked, 84 | }; 85 | 86 | static struct zwp_locked_pointer_v1_interface sl_locked_pointer_implementation = 87 | {sl_locked_pointer_destroy, sl_locked_pointer_set_cursor_position_hint, 88 | sl_locked_pointer_set_region}; 89 | 90 | static void sl_confined_pointer_confined( 91 | void* data, struct zwp_confined_pointer_v1* confined_pointer) { 92 | struct sl_host_confined_pointer* host = 93 | zwp_confined_pointer_v1_get_user_data(confined_pointer); 94 | 95 | zwp_confined_pointer_v1_send_confined(host->resource); 96 | } 97 | 98 | static void sl_confined_pointer_unconfined( 99 | void* data, struct zwp_confined_pointer_v1* confined_pointer) { 100 | struct sl_host_confined_pointer* host = 101 | zwp_confined_pointer_v1_get_user_data(confined_pointer); 102 | 103 | zwp_confined_pointer_v1_send_unconfined(host->resource); 104 | } 105 | 106 | static void sl_confined_pointer_set_region(struct wl_client* client, 107 | struct wl_resource* resource, 108 | struct wl_resource* region) { 109 | struct sl_host_confined_pointer* host = wl_resource_get_user_data(resource); 110 | struct sl_host_region* host_region = 111 | region ? wl_resource_get_user_data(region) : NULL; 112 | 113 | zwp_confined_pointer_v1_set_region(host->proxy, 114 | host_region ? host_region->proxy : NULL); 115 | } 116 | 117 | static struct zwp_confined_pointer_v1_listener sl_confined_pointer_listener = { 118 | sl_confined_pointer_confined, 119 | sl_confined_pointer_unconfined, 120 | }; 121 | 122 | static struct zwp_confined_pointer_v1_interface 123 | sl_confined_pointer_implementation = { 124 | sl_confined_pointer_destroy, 125 | sl_confined_pointer_set_region, 126 | }; 127 | 128 | static void sl_pointer_constraints_lock_pointer(struct wl_client* client, 129 | struct wl_resource* resource, 130 | uint32_t id, 131 | struct wl_resource* surface, 132 | struct wl_resource* pointer, 133 | struct wl_resource* region, 134 | uint32_t lifetime) { 135 | struct sl_host_pointer_constraints* host = 136 | wl_resource_get_user_data(resource); 137 | struct wl_resource* locked_pointer_resource = 138 | wl_resource_create(client, &zwp_locked_pointer_v1_interface, 1, id); 139 | struct sl_host_locked_pointer* locked_pointer_host; 140 | 141 | struct sl_host_surface* host_surface = wl_resource_get_user_data(surface); 142 | struct sl_host_pointer* host_pointer = wl_resource_get_user_data(pointer); 143 | struct sl_host_region* host_region = 144 | region ? wl_resource_get_user_data(region) : NULL; 145 | 146 | locked_pointer_host = malloc(sizeof(struct sl_host_locked_pointer)); 147 | assert(locked_pointer_host); 148 | locked_pointer_host->resource = locked_pointer_resource; 149 | locked_pointer_host->ctx = host->ctx; 150 | locked_pointer_host->proxy = zwp_pointer_constraints_v1_lock_pointer( 151 | host->ctx->pointer_constraints->internal, host_surface->proxy, 152 | host_pointer->proxy, host_region ? host_region->proxy : NULL, lifetime); 153 | wl_resource_set_implementation( 154 | locked_pointer_resource, &sl_locked_pointer_implementation, 155 | locked_pointer_host, sl_destroy_host_locked_pointer); 156 | zwp_locked_pointer_v1_set_user_data(locked_pointer_host->proxy, 157 | locked_pointer_host); 158 | zwp_locked_pointer_v1_add_listener(locked_pointer_host->proxy, 159 | &sl_locked_pointer_listener, 160 | locked_pointer_host); 161 | } 162 | 163 | static void sl_pointer_constraints_confine_pointer(struct wl_client* client, 164 | struct wl_resource* resource, 165 | uint32_t id, 166 | struct wl_resource* surface, 167 | struct wl_resource* pointer, 168 | struct wl_resource* region, 169 | uint32_t lifetime) { 170 | struct sl_host_pointer_constraints* host = 171 | wl_resource_get_user_data(resource); 172 | struct wl_resource* confined_pointer_resource = 173 | wl_resource_create(client, &zwp_confined_pointer_v1_interface, 1, id); 174 | struct sl_host_confined_pointer* confined_pointer_host; 175 | 176 | struct sl_host_surface* host_surface = wl_resource_get_user_data(surface); 177 | struct sl_host_pointer* host_pointer = wl_resource_get_user_data(pointer); 178 | struct sl_host_region* host_region = 179 | region ? wl_resource_get_user_data(region) : NULL; 180 | 181 | confined_pointer_host = malloc(sizeof(struct sl_host_confined_pointer)); 182 | assert(confined_pointer_host); 183 | confined_pointer_host->resource = confined_pointer_resource; 184 | confined_pointer_host->ctx = host->ctx; 185 | confined_pointer_host->proxy = zwp_pointer_constraints_v1_confine_pointer( 186 | host->ctx->pointer_constraints->internal, host_surface->proxy, 187 | host_pointer->proxy, host_region ? host_region->proxy : NULL, lifetime); 188 | wl_resource_set_implementation( 189 | confined_pointer_resource, &sl_confined_pointer_implementation, 190 | confined_pointer_host, sl_destroy_host_confined_pointer); 191 | zwp_confined_pointer_v1_set_user_data(confined_pointer_host->proxy, 192 | confined_pointer_host); 193 | zwp_confined_pointer_v1_add_listener(confined_pointer_host->proxy, 194 | &sl_confined_pointer_listener, 195 | confined_pointer_host); 196 | } 197 | 198 | static struct zwp_pointer_constraints_v1_interface 199 | sl_pointer_constraints_implementation = { 200 | sl_pointer_constraints_destroy, 201 | sl_pointer_constraints_lock_pointer, 202 | sl_pointer_constraints_confine_pointer, 203 | }; 204 | 205 | static void sl_bind_host_pointer_constraints(struct wl_client* client, 206 | void* data, 207 | uint32_t version, 208 | uint32_t id) { 209 | struct sl_context* ctx = (struct sl_context*)data; 210 | struct sl_pointer_constraints* pointer_constraints = ctx->pointer_constraints; 211 | struct sl_host_pointer_constraints* host = 212 | malloc(sizeof(struct sl_host_pointer_constraints)); 213 | 214 | assert(host); 215 | host->ctx = ctx; 216 | host->resource = 217 | wl_resource_create(client, &zwp_pointer_constraints_v1_interface, 1, id); 218 | wl_resource_set_implementation(host->resource, 219 | &sl_pointer_constraints_implementation, host, 220 | sl_destroy_host_pointer_constraints); 221 | host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display), 222 | pointer_constraints->id, 223 | &zwp_pointer_constraints_v1_interface, 224 | wl_resource_get_version(host->resource)); 225 | zwp_pointer_constraints_v1_set_user_data(host->proxy, host); 226 | } 227 | 228 | struct sl_global* sl_pointer_constraints_global_create(struct sl_context* ctx) { 229 | return sl_global_create(ctx, &zwp_pointer_constraints_v1_interface, 1, ctx, 230 | sl_bind_host_pointer_constraints); 231 | } 232 | -------------------------------------------------------------------------------- /sommelier-relative-pointer-manager.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "relative-pointer-unstable-v1-server-protocol.h" 18 | #include "relative-pointer-unstable-v1-client-protocol.h" 19 | 20 | struct sl_host_relative_pointer_manager { 21 | struct sl_context* ctx; 22 | struct wl_resource* resource; 23 | struct zwp_relative_pointer_manager_v1* proxy; 24 | }; 25 | 26 | struct sl_host_relative_pointer { 27 | struct sl_context* ctx; 28 | struct wl_resource* resource; 29 | struct zwp_relative_pointer_v1* proxy; 30 | }; 31 | 32 | // Like ceil(), but strictly increases the magnitude of the input value (i.e. 33 | // trunc() but for increasing the magnitude). 34 | wl_fixed_t magnitude_ceil(wl_fixed_t val) { 35 | double temp = wl_fixed_to_double(val); 36 | temp = temp > 0 ? ceil(temp) : floor(temp); 37 | return wl_fixed_from_double(temp); 38 | } 39 | 40 | static void sl_relative_pointer_relative_motion( 41 | void* data, 42 | struct zwp_relative_pointer_v1* relative_pointer, 43 | uint32_t utime_hi, 44 | uint32_t utime_lo, 45 | wl_fixed_t dx, 46 | wl_fixed_t dy, 47 | wl_fixed_t dx_unaccel, 48 | wl_fixed_t dy_unaccel) { 49 | struct sl_host_relative_pointer* host = 50 | zwp_relative_pointer_v1_get_user_data(relative_pointer); 51 | 52 | // Unfortunately, many x11 toolkits truncate RawMotion events. We force them 53 | // to interpret cursor movement by rounding to the next greater-magnitude 54 | // value. 55 | if (host->ctx->xwayland) { 56 | dx_unaccel = magnitude_ceil(dx_unaccel); 57 | dy_unaccel = magnitude_ceil(dy_unaccel); 58 | } 59 | 60 | zwp_relative_pointer_v1_send_relative_motion( 61 | host->resource, utime_hi, utime_lo, dx, dy, dx_unaccel, dy_unaccel); 62 | } 63 | 64 | static void sl_destroy_host_relative_pointer(struct wl_resource* resource) { 65 | struct sl_host_relative_pointer* host = wl_resource_get_user_data(resource); 66 | 67 | zwp_relative_pointer_v1_destroy(host->proxy); 68 | wl_resource_set_user_data(resource, NULL); 69 | free(host); 70 | } 71 | 72 | static void sl_relative_pointer_destroy(struct wl_client* client, 73 | struct wl_resource* resource) { 74 | wl_resource_destroy(resource); 75 | } 76 | 77 | static struct zwp_relative_pointer_v1_listener sl_relative_pointer_listener = { 78 | sl_relative_pointer_relative_motion, 79 | }; 80 | 81 | static struct zwp_relative_pointer_v1_interface 82 | sl_relative_pointer_implementation = { 83 | sl_relative_pointer_destroy, 84 | }; 85 | 86 | static void sl_destroy_host_relative_pointer_manager( 87 | struct wl_resource* resource) { 88 | struct sl_host_relative_pointer_manager* host = 89 | wl_resource_get_user_data(resource); 90 | 91 | zwp_relative_pointer_manager_v1_destroy(host->proxy); 92 | wl_resource_set_user_data(resource, NULL); 93 | free(host); 94 | } 95 | 96 | static void sl_relative_pointer_manager_destroy(struct wl_client* client, 97 | struct wl_resource* resource) { 98 | wl_resource_destroy(resource); 99 | } 100 | 101 | static void sl_relative_pointer_manager_get_relative_pointer( 102 | struct wl_client* client, 103 | struct wl_resource* resource, 104 | uint32_t id, 105 | struct wl_resource* pointer) { 106 | struct sl_host_relative_pointer_manager* host = 107 | wl_resource_get_user_data(resource); 108 | struct sl_host_pointer* host_pointer = wl_resource_get_user_data(pointer); 109 | struct wl_resource* relative_pointer_resource = 110 | wl_resource_create(client, &zwp_relative_pointer_v1_interface, 1, id); 111 | struct sl_host_relative_pointer* relative_pointer_host; 112 | 113 | relative_pointer_host = malloc(sizeof(*relative_pointer_host)); 114 | assert(relative_pointer_host); 115 | relative_pointer_host->resource = relative_pointer_resource; 116 | relative_pointer_host->ctx = host->ctx; 117 | relative_pointer_host->proxy = 118 | zwp_relative_pointer_manager_v1_get_relative_pointer( 119 | host->ctx->relative_pointer_manager->internal, host_pointer->proxy); 120 | wl_resource_set_implementation( 121 | relative_pointer_resource, &sl_relative_pointer_implementation, 122 | relative_pointer_host, sl_destroy_host_relative_pointer); 123 | zwp_relative_pointer_v1_set_user_data(relative_pointer_host->proxy, 124 | relative_pointer_host); 125 | zwp_relative_pointer_v1_add_listener(relative_pointer_host->proxy, 126 | &sl_relative_pointer_listener, 127 | relative_pointer_host); 128 | } 129 | 130 | static struct zwp_relative_pointer_manager_v1_interface 131 | sl_relative_pointer_manager_implementation = { 132 | sl_relative_pointer_manager_destroy, 133 | sl_relative_pointer_manager_get_relative_pointer, 134 | }; 135 | 136 | static void sl_bind_host_relative_pointer_manager(struct wl_client* client, 137 | void* data, 138 | uint32_t version, 139 | uint32_t id) { 140 | struct sl_context* ctx = (struct sl_context*)data; 141 | struct sl_relative_pointer_manager* relative_pointer_manager = 142 | ctx->relative_pointer_manager; 143 | struct sl_host_relative_pointer_manager* host; 144 | 145 | host = malloc(sizeof(*host)); 146 | assert(host); 147 | host->ctx = ctx; 148 | host->resource = wl_resource_create( 149 | client, &zwp_relative_pointer_manager_v1_interface, 1, id); 150 | wl_resource_set_implementation( 151 | host->resource, &sl_relative_pointer_manager_implementation, host, 152 | sl_destroy_host_relative_pointer_manager); 153 | host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display), 154 | relative_pointer_manager->id, 155 | &zwp_relative_pointer_manager_v1_interface, 156 | wl_resource_get_version(host->resource)); 157 | zwp_relative_pointer_manager_v1_set_user_data(host->proxy, host); 158 | } 159 | 160 | struct sl_global* sl_relative_pointer_manager_global_create( 161 | struct sl_context* ctx) { 162 | return sl_global_create(ctx, &zwp_relative_pointer_manager_v1_interface, 1, 163 | ctx, sl_bind_host_relative_pointer_manager); 164 | } 165 | -------------------------------------------------------------------------------- /sommelier-shell.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | struct sl_host_shell_surface { 12 | struct wl_resource* resource; 13 | struct wl_shell_surface* proxy; 14 | }; 15 | 16 | struct sl_host_shell { 17 | struct sl_shell* shell; 18 | struct wl_resource* resource; 19 | struct wl_shell* proxy; 20 | }; 21 | 22 | static void sl_shell_surface_pong(struct wl_client* client, 23 | struct wl_resource* resource, 24 | uint32_t serial) { 25 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 26 | 27 | wl_shell_surface_pong(host->proxy, serial); 28 | } 29 | 30 | static void sl_shell_surface_move(struct wl_client* client, 31 | struct wl_resource* resource, 32 | struct wl_resource* seat_resource, 33 | uint32_t serial) { 34 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 35 | struct sl_host_seat* host_seat = wl_resource_get_user_data(seat_resource); 36 | 37 | wl_shell_surface_move(host->proxy, host_seat->proxy, serial); 38 | } 39 | 40 | static void sl_shell_surface_resize(struct wl_client* client, 41 | struct wl_resource* resource, 42 | struct wl_resource* seat_resource, 43 | uint32_t serial, 44 | uint32_t edges) { 45 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 46 | struct sl_host_seat* host_seat = wl_resource_get_user_data(seat_resource); 47 | 48 | wl_shell_surface_resize(host->proxy, host_seat->proxy, serial, edges); 49 | } 50 | 51 | static void sl_shell_surface_set_toplevel(struct wl_client* client, 52 | struct wl_resource* resource) { 53 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 54 | 55 | wl_shell_surface_set_toplevel(host->proxy); 56 | } 57 | 58 | static void sl_shell_surface_set_transient(struct wl_client* client, 59 | struct wl_resource* resource, 60 | struct wl_resource* parent_resource, 61 | int32_t x, 62 | int32_t y, 63 | uint32_t flags) { 64 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 65 | struct sl_host_surface* host_parent = 66 | wl_resource_get_user_data(parent_resource); 67 | 68 | wl_shell_surface_set_transient(host->proxy, host_parent->proxy, x, y, flags); 69 | } 70 | 71 | static void sl_shell_surface_set_fullscreen( 72 | struct wl_client* client, 73 | struct wl_resource* resource, 74 | uint32_t method, 75 | uint32_t framerate, 76 | struct wl_resource* output_resource) { 77 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 78 | struct sl_host_output* host_output = 79 | output_resource ? wl_resource_get_user_data(output_resource) : NULL; 80 | 81 | wl_shell_surface_set_fullscreen(host->proxy, method, framerate, 82 | host_output ? host_output->proxy : NULL); 83 | } 84 | 85 | static void sl_shell_surface_set_popup(struct wl_client* client, 86 | struct wl_resource* resource, 87 | struct wl_resource* seat_resource, 88 | uint32_t serial, 89 | struct wl_resource* parent_resource, 90 | int32_t x, 91 | int32_t y, 92 | uint32_t flags) { 93 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 94 | struct sl_host_seat* host_seat = wl_resource_get_user_data(seat_resource); 95 | struct sl_host_surface* host_parent = 96 | wl_resource_get_user_data(parent_resource); 97 | 98 | wl_shell_surface_set_popup(host->proxy, host_seat->proxy, serial, 99 | host_parent->proxy, x, y, flags); 100 | } 101 | 102 | static void sl_shell_surface_set_maximized( 103 | struct wl_client* client, 104 | struct wl_resource* resource, 105 | struct wl_resource* output_resource) { 106 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 107 | struct sl_host_output* host_output = 108 | output_resource ? wl_resource_get_user_data(output_resource) : NULL; 109 | 110 | wl_shell_surface_set_maximized(host->proxy, 111 | host_output ? host_output->proxy : NULL); 112 | } 113 | 114 | static void sl_shell_surface_set_title(struct wl_client* client, 115 | struct wl_resource* resource, 116 | const char* title) { 117 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 118 | 119 | wl_shell_surface_set_title(host->proxy, title); 120 | } 121 | 122 | static void sl_shell_surface_set_class(struct wl_client* client, 123 | struct wl_resource* resource, 124 | const char* clazz) { 125 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 126 | 127 | wl_shell_surface_set_class(host->proxy, clazz); 128 | } 129 | 130 | static const struct wl_shell_surface_interface sl_shell_surface_implementation = 131 | {sl_shell_surface_pong, sl_shell_surface_move, 132 | sl_shell_surface_resize, sl_shell_surface_set_toplevel, 133 | sl_shell_surface_set_transient, sl_shell_surface_set_fullscreen, 134 | sl_shell_surface_set_popup, sl_shell_surface_set_maximized, 135 | sl_shell_surface_set_title, sl_shell_surface_set_class}; 136 | 137 | static void sl_shell_surface_ping(void* data, 138 | struct wl_shell_surface* shell_surface, 139 | uint32_t serial) { 140 | struct sl_host_shell_surface* host = 141 | wl_shell_surface_get_user_data(shell_surface); 142 | 143 | wl_shell_surface_send_ping(host->resource, serial); 144 | } 145 | 146 | static void sl_shell_surface_configure(void* data, 147 | struct wl_shell_surface* shell_surface, 148 | uint32_t edges, 149 | int32_t width, 150 | int32_t height) { 151 | struct sl_host_shell_surface* host = 152 | wl_shell_surface_get_user_data(shell_surface); 153 | 154 | wl_shell_surface_send_configure(host->resource, edges, width, height); 155 | } 156 | 157 | static void sl_shell_surface_popup_done( 158 | void* data, struct wl_shell_surface* shell_surface) { 159 | struct sl_host_shell_surface* host = 160 | wl_shell_surface_get_user_data(shell_surface); 161 | 162 | wl_shell_surface_send_popup_done(host->resource); 163 | } 164 | 165 | static const struct wl_shell_surface_listener sl_shell_surface_listener = { 166 | sl_shell_surface_ping, sl_shell_surface_configure, 167 | sl_shell_surface_popup_done}; 168 | 169 | static void sl_destroy_host_shell_surface(struct wl_resource* resource) { 170 | struct sl_host_shell_surface* host = wl_resource_get_user_data(resource); 171 | 172 | wl_shell_surface_destroy(host->proxy); 173 | wl_resource_set_user_data(resource, NULL); 174 | free(host); 175 | } 176 | 177 | static void sl_host_shell_get_shell_surface( 178 | struct wl_client* client, 179 | struct wl_resource* resource, 180 | uint32_t id, 181 | struct wl_resource* surface_resource) { 182 | struct sl_host_shell* host = wl_resource_get_user_data(resource); 183 | struct sl_host_surface* host_surface = 184 | wl_resource_get_user_data(surface_resource); 185 | struct sl_host_shell_surface* host_shell_surface; 186 | 187 | host_shell_surface = malloc(sizeof(*host_shell_surface)); 188 | assert(host_shell_surface); 189 | host_shell_surface->resource = 190 | wl_resource_create(client, &wl_shell_surface_interface, 1, id); 191 | wl_resource_set_implementation( 192 | host_shell_surface->resource, &sl_shell_surface_implementation, 193 | host_shell_surface, sl_destroy_host_shell_surface); 194 | host_shell_surface->proxy = 195 | wl_shell_get_shell_surface(host->proxy, host_surface->proxy); 196 | wl_shell_surface_set_user_data(host_shell_surface->proxy, host_shell_surface); 197 | wl_shell_surface_add_listener(host_shell_surface->proxy, 198 | &sl_shell_surface_listener, host_shell_surface); 199 | host_surface->has_role = 1; 200 | } 201 | 202 | static const struct wl_shell_interface sl_shell_implementation = { 203 | sl_host_shell_get_shell_surface}; 204 | 205 | static void sl_destroy_host_shell(struct wl_resource* resource) { 206 | struct sl_host_shell* host = wl_resource_get_user_data(resource); 207 | 208 | wl_shell_destroy(host->proxy); 209 | wl_resource_set_user_data(resource, NULL); 210 | free(host); 211 | } 212 | 213 | static void sl_bind_host_shell(struct wl_client* client, 214 | void* data, 215 | uint32_t version, 216 | uint32_t id) { 217 | struct sl_context* ctx = (struct sl_context*)data; 218 | struct sl_host_shell* host; 219 | 220 | host = malloc(sizeof(*host)); 221 | assert(host); 222 | host->shell = ctx->shell; 223 | host->resource = wl_resource_create(client, &wl_shell_interface, 1, id); 224 | wl_resource_set_implementation(host->resource, &sl_shell_implementation, host, 225 | sl_destroy_host_shell); 226 | host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display), 227 | ctx->shell->id, &wl_shell_interface, 228 | wl_resource_get_version(host->resource)); 229 | wl_shell_set_user_data(host->proxy, host); 230 | } 231 | 232 | struct sl_global* sl_shell_global_create(struct sl_context* ctx) { 233 | return sl_global_create(ctx, &wl_shell_interface, 1, ctx, sl_bind_host_shell); 234 | } -------------------------------------------------------------------------------- /sommelier-shm.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "drm-server-protocol.h" 13 | #include "linux-dmabuf-unstable-v1-client-protocol.h" 14 | 15 | struct sl_host_shm_pool { 16 | struct sl_shm* shm; 17 | struct wl_resource* resource; 18 | struct wl_shm_pool* proxy; 19 | int fd; 20 | }; 21 | 22 | struct sl_host_shm { 23 | struct sl_shm* shm; 24 | struct wl_resource* resource; 25 | struct wl_shm* shm_proxy; 26 | struct zwp_linux_dmabuf_v1* linux_dmabuf_proxy; 27 | }; 28 | 29 | size_t sl_shm_bpp_for_shm_format(uint32_t format) { 30 | switch (format) { 31 | case WL_SHM_FORMAT_NV12: 32 | return 1; 33 | case WL_SHM_FORMAT_RGB565: 34 | return 2; 35 | case WL_SHM_FORMAT_ARGB8888: 36 | case WL_SHM_FORMAT_ABGR8888: 37 | case WL_SHM_FORMAT_XRGB8888: 38 | case WL_SHM_FORMAT_XBGR8888: 39 | return 4; 40 | } 41 | assert(0); 42 | return 0; 43 | } 44 | 45 | size_t sl_shm_num_planes_for_shm_format(uint32_t format) { 46 | switch (format) { 47 | case WL_SHM_FORMAT_NV12: 48 | return 2; 49 | case WL_SHM_FORMAT_RGB565: 50 | case WL_SHM_FORMAT_ARGB8888: 51 | case WL_SHM_FORMAT_ABGR8888: 52 | case WL_SHM_FORMAT_XRGB8888: 53 | case WL_SHM_FORMAT_XBGR8888: 54 | return 1; 55 | } 56 | assert(0); 57 | return 0; 58 | } 59 | 60 | static size_t sl_y_subsampling_for_shm_format_plane(uint32_t format, 61 | size_t plane) { 62 | switch (format) { 63 | case WL_SHM_FORMAT_NV12: { 64 | const size_t subsampling[] = {1, 2}; 65 | 66 | assert(plane < ARRAY_SIZE(subsampling)); 67 | return subsampling[plane]; 68 | } 69 | case WL_SHM_FORMAT_RGB565: 70 | case WL_SHM_FORMAT_ARGB8888: 71 | case WL_SHM_FORMAT_ABGR8888: 72 | case WL_SHM_FORMAT_XRGB8888: 73 | case WL_SHM_FORMAT_XBGR8888: 74 | return 1; 75 | } 76 | assert(0); 77 | return 0; 78 | } 79 | 80 | static int sl_offset_for_shm_format_plane(uint32_t format, 81 | size_t height, 82 | size_t stride, 83 | size_t plane) { 84 | switch (format) { 85 | case WL_SHM_FORMAT_NV12: { 86 | const size_t offset[] = {0, 1}; 87 | 88 | assert(plane < ARRAY_SIZE(offset)); 89 | return offset[plane] * height * stride; 90 | } 91 | case WL_SHM_FORMAT_RGB565: 92 | case WL_SHM_FORMAT_ARGB8888: 93 | case WL_SHM_FORMAT_ABGR8888: 94 | case WL_SHM_FORMAT_XRGB8888: 95 | case WL_SHM_FORMAT_XBGR8888: 96 | return 0; 97 | } 98 | assert(0); 99 | return 0; 100 | } 101 | 102 | static size_t sl_size_for_shm_format_plane(uint32_t format, 103 | size_t height, 104 | size_t stride, 105 | size_t plane) { 106 | return height / sl_y_subsampling_for_shm_format_plane(format, plane) * stride; 107 | } 108 | 109 | static size_t sl_size_for_shm_format(uint32_t format, 110 | size_t height, 111 | size_t stride) { 112 | size_t i, num_planes = sl_shm_num_planes_for_shm_format(format); 113 | size_t total_size = 0; 114 | 115 | for (i = 0; i < num_planes; ++i) { 116 | size_t size = sl_size_for_shm_format_plane(format, height, stride, i); 117 | size_t offset = sl_offset_for_shm_format_plane(format, height, stride, i); 118 | total_size = MAX(total_size, size + offset); 119 | } 120 | 121 | return total_size; 122 | } 123 | 124 | static void sl_host_shm_pool_create_host_buffer(struct wl_client* client, 125 | struct wl_resource* resource, 126 | uint32_t id, 127 | int32_t offset, 128 | int32_t width, 129 | int32_t height, 130 | int32_t stride, 131 | uint32_t format) { 132 | struct sl_host_shm_pool* host = wl_resource_get_user_data(resource); 133 | 134 | if (host->shm->ctx->shm_driver == SHM_DRIVER_NOOP) { 135 | assert(host->proxy); 136 | sl_create_host_buffer(client, id, 137 | wl_shm_pool_create_buffer(host->proxy, offset, width, 138 | height, stride, format), 139 | width, height); 140 | } else { 141 | struct sl_host_buffer* host_buffer = 142 | sl_create_host_buffer(client, id, NULL, width, height); 143 | 144 | host_buffer->shm_format = format; 145 | host_buffer->shm_mmap = sl_mmap_create( 146 | host->fd, sl_size_for_shm_format(format, height, stride), 147 | sl_shm_bpp_for_shm_format(format), 148 | sl_shm_num_planes_for_shm_format(format), offset, stride, 149 | offset + sl_offset_for_shm_format_plane(format, height, stride, 1), 150 | stride, sl_y_subsampling_for_shm_format_plane(format, 0), 151 | sl_y_subsampling_for_shm_format_plane(format, 1)); 152 | // In the case of mmaps created from the client buffer, we want to be able 153 | // to close the FD when the client releases the shm pool (i.e. when it's 154 | // done transferring) as opposed to when the pool is freed (i.e. when we're 155 | // done drawing). 156 | // We do this by removing the handle to the FD after it has been mmapped, 157 | // which prevents a double-close. 158 | host_buffer->shm_mmap->fd = -1; 159 | host_buffer->shm_mmap->buffer_resource = host_buffer->resource; 160 | } 161 | } 162 | 163 | static void sl_host_shm_pool_destroy(struct wl_client* client, 164 | struct wl_resource* resource) { 165 | wl_resource_destroy(resource); 166 | } 167 | 168 | static void sl_host_shm_pool_resize(struct wl_client* client, 169 | struct wl_resource* resource, 170 | int32_t size) { 171 | struct sl_host_shm_pool* host = wl_resource_get_user_data(resource); 172 | 173 | if (host->proxy) 174 | wl_shm_pool_resize(host->proxy, size); 175 | } 176 | 177 | static const struct wl_shm_pool_interface sl_shm_pool_implementation = { 178 | sl_host_shm_pool_create_host_buffer, sl_host_shm_pool_destroy, 179 | sl_host_shm_pool_resize}; 180 | 181 | static void sl_destroy_host_shm_pool(struct wl_resource* resource) { 182 | struct sl_host_shm_pool* host = wl_resource_get_user_data(resource); 183 | 184 | if (host->fd >= 0) 185 | close(host->fd); 186 | if (host->proxy) 187 | wl_shm_pool_destroy(host->proxy); 188 | wl_resource_set_user_data(resource, NULL); 189 | free(host); 190 | } 191 | 192 | static void sl_shm_create_host_pool(struct wl_client* client, 193 | struct wl_resource* resource, 194 | uint32_t id, 195 | int fd, 196 | int32_t size) { 197 | struct sl_host_shm* host = wl_resource_get_user_data(resource); 198 | struct sl_host_shm_pool* host_shm_pool; 199 | 200 | host_shm_pool = malloc(sizeof(*host_shm_pool)); 201 | assert(host_shm_pool); 202 | 203 | host_shm_pool->shm = host->shm; 204 | host_shm_pool->fd = -1; 205 | host_shm_pool->proxy = NULL; 206 | host_shm_pool->resource = 207 | wl_resource_create(client, &wl_shm_pool_interface, 1, id); 208 | wl_resource_set_implementation(host_shm_pool->resource, 209 | &sl_shm_pool_implementation, host_shm_pool, 210 | sl_destroy_host_shm_pool); 211 | 212 | switch (host->shm->ctx->shm_driver) { 213 | case SHM_DRIVER_NOOP: 214 | host_shm_pool->proxy = wl_shm_create_pool(host->shm_proxy, fd, size); 215 | wl_shm_pool_set_user_data(host_shm_pool->proxy, host_shm_pool); 216 | close(fd); 217 | break; 218 | case SHM_DRIVER_DMABUF: 219 | case SHM_DRIVER_VIRTWL: 220 | case SHM_DRIVER_VIRTWL_DMABUF: 221 | host_shm_pool->fd = fd; 222 | break; 223 | } 224 | } 225 | 226 | static const struct wl_shm_interface sl_shm_implementation = { 227 | sl_shm_create_host_pool}; 228 | 229 | static void sl_shm_format(void* data, struct wl_shm* shm, uint32_t format) { 230 | struct sl_host_shm* host = wl_shm_get_user_data(shm); 231 | 232 | switch (format) { 233 | case WL_SHM_FORMAT_RGB565: 234 | case WL_SHM_FORMAT_ARGB8888: 235 | case WL_SHM_FORMAT_ABGR8888: 236 | case WL_SHM_FORMAT_XRGB8888: 237 | case WL_SHM_FORMAT_XBGR8888: 238 | wl_shm_send_format(host->resource, format); 239 | break; 240 | default: 241 | break; 242 | } 243 | } 244 | 245 | static const struct wl_shm_listener sl_shm_listener = {sl_shm_format}; 246 | 247 | static void sl_drm_format(void* data, 248 | struct zwp_linux_dmabuf_v1* linux_dmabuf, 249 | uint32_t format) { 250 | struct sl_host_shm* host = zwp_linux_dmabuf_v1_get_user_data(linux_dmabuf); 251 | 252 | // Forward SHM versions of supported formats. 253 | switch (format) { 254 | case WL_DRM_FORMAT_NV12: 255 | wl_shm_send_format(host->resource, WL_SHM_FORMAT_NV12); 256 | break; 257 | case WL_DRM_FORMAT_RGB565: 258 | wl_shm_send_format(host->resource, WL_SHM_FORMAT_RGB565); 259 | break; 260 | case WL_DRM_FORMAT_ARGB8888: 261 | wl_shm_send_format(host->resource, WL_SHM_FORMAT_ARGB8888); 262 | break; 263 | case WL_DRM_FORMAT_ABGR8888: 264 | wl_shm_send_format(host->resource, WL_SHM_FORMAT_ABGR8888); 265 | break; 266 | case WL_DRM_FORMAT_XRGB8888: 267 | wl_shm_send_format(host->resource, WL_SHM_FORMAT_XRGB8888); 268 | break; 269 | case WL_DRM_FORMAT_XBGR8888: 270 | wl_shm_send_format(host->resource, WL_SHM_FORMAT_XBGR8888); 271 | break; 272 | } 273 | } 274 | 275 | static void sl_drm_modifier(void* data, 276 | struct zwp_linux_dmabuf_v1* linux_dmabuf, 277 | uint32_t format, 278 | uint32_t modifier_hi, 279 | uint32_t modifier_lo) {} 280 | 281 | static const struct zwp_linux_dmabuf_v1_listener sl_linux_dmabuf_listener = { 282 | sl_drm_format, sl_drm_modifier}; 283 | 284 | static void sl_destroy_host_shm(struct wl_resource* resource) { 285 | struct sl_host_shm* host = wl_resource_get_user_data(resource); 286 | 287 | if (host->shm_proxy) 288 | wl_shm_destroy(host->shm_proxy); 289 | if (host->linux_dmabuf_proxy) 290 | zwp_linux_dmabuf_v1_destroy(host->linux_dmabuf_proxy); 291 | wl_resource_set_user_data(resource, NULL); 292 | free(host); 293 | } 294 | 295 | static void sl_bind_host_shm(struct wl_client* client, 296 | void* data, 297 | uint32_t version, 298 | uint32_t id) { 299 | struct sl_context* ctx = (struct sl_context*)data; 300 | struct sl_host_shm* host; 301 | 302 | host = malloc(sizeof(*host)); 303 | assert(host); 304 | host->shm = ctx->shm; 305 | host->shm_proxy = NULL; 306 | host->linux_dmabuf_proxy = NULL; 307 | host->resource = wl_resource_create(client, &wl_shm_interface, 1, id); 308 | wl_resource_set_implementation(host->resource, &sl_shm_implementation, host, 309 | sl_destroy_host_shm); 310 | 311 | switch (ctx->shm_driver) { 312 | case SHM_DRIVER_NOOP: 313 | case SHM_DRIVER_VIRTWL: 314 | host->shm_proxy = wl_registry_bind( 315 | wl_display_get_registry(ctx->display), ctx->shm->id, 316 | &wl_shm_interface, wl_resource_get_version(host->resource)); 317 | wl_shm_set_user_data(host->shm_proxy, host); 318 | wl_shm_add_listener(host->shm_proxy, &sl_shm_listener, host); 319 | break; 320 | case SHM_DRIVER_VIRTWL_DMABUF: 321 | case SHM_DRIVER_DMABUF: 322 | assert(ctx->linux_dmabuf); 323 | host->linux_dmabuf_proxy = wl_registry_bind( 324 | wl_display_get_registry(ctx->display), ctx->linux_dmabuf->id, 325 | &zwp_linux_dmabuf_v1_interface, 326 | wl_resource_get_version(host->resource)); 327 | zwp_linux_dmabuf_v1_set_user_data(host->linux_dmabuf_proxy, host); 328 | zwp_linux_dmabuf_v1_add_listener(host->linux_dmabuf_proxy, 329 | &sl_linux_dmabuf_listener, host); 330 | break; 331 | } 332 | } 333 | 334 | struct sl_global* sl_shm_global_create(struct sl_context* ctx) { 335 | return sl_global_create(ctx, &wl_shm_interface, 1, ctx, sl_bind_host_shm); 336 | } 337 | -------------------------------------------------------------------------------- /sommelier-subcompositor.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | struct sl_host_subcompositor { 12 | struct sl_context* ctx; 13 | struct wl_resource* resource; 14 | struct wl_subcompositor* proxy; 15 | }; 16 | 17 | struct sl_host_subsurface { 18 | struct sl_context* ctx; 19 | struct wl_resource* resource; 20 | struct wl_subsurface* proxy; 21 | }; 22 | 23 | static void sl_subsurface_destroy(struct wl_client* client, 24 | struct wl_resource* resource) { 25 | wl_resource_destroy(resource); 26 | } 27 | 28 | static void sl_subsurface_set_position(struct wl_client* client, 29 | struct wl_resource* resource, 30 | int32_t x, 31 | int32_t y) { 32 | struct sl_host_subsurface* host = wl_resource_get_user_data(resource); 33 | double scale = host->ctx->scale; 34 | 35 | wl_subsurface_set_position(host->proxy, x / scale, y / scale); 36 | } 37 | 38 | static void sl_subsurface_place_above(struct wl_client* client, 39 | struct wl_resource* resource, 40 | struct wl_resource* sibling_resource) { 41 | struct sl_host_subsurface* host = wl_resource_get_user_data(resource); 42 | struct sl_host_surface* host_sibling = 43 | wl_resource_get_user_data(sibling_resource); 44 | 45 | wl_subsurface_place_above(host->proxy, host_sibling->proxy); 46 | } 47 | 48 | static void sl_subsurface_place_below(struct wl_client* client, 49 | struct wl_resource* resource, 50 | struct wl_resource* sibling_resource) { 51 | struct sl_host_subsurface* host = wl_resource_get_user_data(resource); 52 | struct sl_host_surface* host_sibling = 53 | wl_resource_get_user_data(sibling_resource); 54 | 55 | wl_subsurface_place_below(host->proxy, host_sibling->proxy); 56 | } 57 | 58 | static void sl_subsurface_set_sync(struct wl_client* client, 59 | struct wl_resource* resource) { 60 | struct sl_host_subsurface* host = wl_resource_get_user_data(resource); 61 | 62 | wl_subsurface_set_sync(host->proxy); 63 | } 64 | 65 | static void sl_subsurface_set_desync(struct wl_client* client, 66 | struct wl_resource* resource) { 67 | struct sl_host_subsurface* host = wl_resource_get_user_data(resource); 68 | 69 | wl_subsurface_set_desync(host->proxy); 70 | } 71 | 72 | static const struct wl_subsurface_interface sl_subsurface_implementation = { 73 | sl_subsurface_destroy, sl_subsurface_set_position, 74 | sl_subsurface_place_above, sl_subsurface_place_below, 75 | sl_subsurface_set_sync, sl_subsurface_set_desync}; 76 | 77 | static void sl_destroy_host_subsurface(struct wl_resource* resource) { 78 | struct sl_host_subsurface* host = wl_resource_get_user_data(resource); 79 | 80 | wl_subsurface_destroy(host->proxy); 81 | wl_resource_set_user_data(resource, NULL); 82 | free(host); 83 | } 84 | 85 | static void sl_subcompositor_destroy(struct wl_client* client, 86 | struct wl_resource* resource) { 87 | wl_resource_destroy(resource); 88 | } 89 | 90 | static void sl_subcompositor_get_subsurface( 91 | struct wl_client* client, 92 | struct wl_resource* resource, 93 | uint32_t id, 94 | struct wl_resource* surface_resource, 95 | struct wl_resource* parent_resource) { 96 | struct sl_host_subcompositor* host = wl_resource_get_user_data(resource); 97 | struct sl_host_surface* host_surface = 98 | wl_resource_get_user_data(surface_resource); 99 | struct sl_host_surface* host_parent = 100 | wl_resource_get_user_data(parent_resource); 101 | struct sl_host_subsurface* host_subsurface; 102 | 103 | host_subsurface = malloc(sizeof(*host_subsurface)); 104 | assert(host_subsurface); 105 | 106 | host_subsurface->ctx = host->ctx; 107 | host_subsurface->resource = 108 | wl_resource_create(client, &wl_subsurface_interface, 1, id); 109 | wl_resource_set_implementation(host_subsurface->resource, 110 | &sl_subsurface_implementation, host_subsurface, 111 | sl_destroy_host_subsurface); 112 | host_subsurface->proxy = wl_subcompositor_get_subsurface( 113 | host->proxy, host_surface->proxy, host_parent->proxy); 114 | wl_subsurface_set_user_data(host_subsurface->proxy, host_subsurface); 115 | host_surface->has_role = 1; 116 | } 117 | 118 | static const struct wl_subcompositor_interface sl_subcompositor_implementation = 119 | {sl_subcompositor_destroy, sl_subcompositor_get_subsurface}; 120 | 121 | static void sl_destroy_host_subcompositor(struct wl_resource* resource) { 122 | struct sl_host_subcompositor* host = wl_resource_get_user_data(resource); 123 | 124 | wl_subcompositor_destroy(host->proxy); 125 | wl_resource_set_user_data(resource, NULL); 126 | free(host); 127 | } 128 | 129 | static void sl_bind_host_subcompositor(struct wl_client* client, 130 | void* data, 131 | uint32_t version, 132 | uint32_t id) { 133 | struct sl_context* ctx = (struct sl_context*)data; 134 | struct sl_host_subcompositor* host; 135 | 136 | host = malloc(sizeof(*host)); 137 | assert(host); 138 | host->ctx = ctx; 139 | host->resource = 140 | wl_resource_create(client, &wl_subcompositor_interface, 1, id); 141 | wl_resource_set_implementation(host->resource, 142 | &sl_subcompositor_implementation, host, 143 | sl_destroy_host_subcompositor); 144 | host->proxy = 145 | wl_registry_bind(wl_display_get_registry(ctx->display), 146 | ctx->subcompositor->id, &wl_subcompositor_interface, 1); 147 | wl_subcompositor_set_user_data(host->proxy, host); 148 | } 149 | 150 | struct sl_global* sl_subcompositor_global_create(struct sl_context* ctx) { 151 | return sl_global_create(ctx, &wl_subcompositor_interface, 1, ctx, 152 | sl_bind_host_subcompositor); 153 | } -------------------------------------------------------------------------------- /sommelier-text-input.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "text-input-unstable-v1-client-protocol.h" 12 | #include "text-input-unstable-v1-server-protocol.h" 13 | 14 | struct sl_host_text_input_manager { 15 | struct sl_context* ctx; 16 | struct wl_resource* resource; 17 | struct zwp_text_input_manager_v1* proxy; 18 | }; 19 | 20 | struct sl_host_text_input { 21 | struct sl_context* ctx; 22 | struct wl_resource* resource; 23 | struct zwp_text_input_v1* proxy; 24 | }; 25 | 26 | static void sl_text_input_activate(struct wl_client* client, 27 | struct wl_resource* resource, 28 | struct wl_resource* seat, 29 | struct wl_resource* surface) { 30 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 31 | struct sl_host_seat* host_seat = wl_resource_get_user_data(seat); 32 | struct sl_host_surface* host_surface = wl_resource_get_user_data(surface); 33 | 34 | zwp_text_input_v1_activate(host->proxy, host_seat->proxy, 35 | host_surface->proxy); 36 | } 37 | 38 | static void sl_text_input_deactivate(struct wl_client* client, 39 | struct wl_resource* resource, 40 | struct wl_resource* seat) { 41 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 42 | struct sl_host_seat* host_seat = wl_resource_get_user_data(seat); 43 | 44 | zwp_text_input_v1_deactivate(host->proxy, host_seat->proxy); 45 | } 46 | 47 | static void sl_text_input_show_input_panel(struct wl_client* client, 48 | struct wl_resource* resource) { 49 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 50 | 51 | zwp_text_input_v1_show_input_panel(host->proxy); 52 | } 53 | 54 | static void sl_text_input_hide_input_panel(struct wl_client* client, 55 | struct wl_resource* resource) { 56 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 57 | 58 | zwp_text_input_v1_hide_input_panel(host->proxy); 59 | } 60 | 61 | static void sl_text_input_reset(struct wl_client* client, 62 | struct wl_resource* resource) { 63 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 64 | 65 | zwp_text_input_v1_reset(host->proxy); 66 | } 67 | 68 | static void sl_text_input_set_surrounding_text(struct wl_client* client, 69 | struct wl_resource* resource, 70 | const char* text, 71 | uint32_t cursor, 72 | uint32_t anchor) { 73 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 74 | 75 | zwp_text_input_v1_set_surrounding_text(host->proxy, text, cursor, anchor); 76 | } 77 | 78 | static void sl_text_input_set_content_type(struct wl_client* client, 79 | struct wl_resource* resource, 80 | uint32_t hint, 81 | uint32_t purpose) { 82 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 83 | 84 | zwp_text_input_v1_set_content_type(host->proxy, hint, purpose); 85 | } 86 | 87 | static void sl_text_input_set_cursor_rectangle(struct wl_client* client, 88 | struct wl_resource* resource, 89 | int32_t x, 90 | int32_t y, 91 | int32_t width, 92 | int32_t height) { 93 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 94 | 95 | zwp_text_input_v1_set_cursor_rectangle(host->proxy, x, y, width, height); 96 | } 97 | 98 | static void sl_text_input_set_preferred_language(struct wl_client* client, 99 | struct wl_resource* resource, 100 | const char* language) { 101 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 102 | 103 | zwp_text_input_v1_set_preferred_language(host->proxy, language); 104 | } 105 | 106 | static void sl_text_input_commit_state(struct wl_client* client, 107 | struct wl_resource* resource, 108 | uint32_t serial) { 109 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 110 | 111 | zwp_text_input_v1_commit_state(host->proxy, serial); 112 | } 113 | 114 | static void sl_text_input_invoke_action(struct wl_client* client, 115 | struct wl_resource* resource, 116 | uint32_t button, 117 | uint32_t index) { 118 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 119 | 120 | zwp_text_input_v1_invoke_action(host->proxy, button, index); 121 | } 122 | 123 | static const struct zwp_text_input_v1_interface sl_text_input_implementation = { 124 | sl_text_input_activate, 125 | sl_text_input_deactivate, 126 | sl_text_input_show_input_panel, 127 | sl_text_input_hide_input_panel, 128 | sl_text_input_reset, 129 | sl_text_input_set_surrounding_text, 130 | sl_text_input_set_content_type, 131 | sl_text_input_set_cursor_rectangle, 132 | sl_text_input_set_preferred_language, 133 | sl_text_input_commit_state, 134 | sl_text_input_invoke_action, 135 | }; 136 | 137 | static void sl_text_input_enter(void* data, 138 | struct zwp_text_input_v1* text_input, 139 | struct wl_surface* surface) { 140 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 141 | struct sl_host_surface* host_surface = wl_surface_get_user_data(surface); 142 | 143 | zwp_text_input_v1_send_enter(host->resource, host_surface->resource); 144 | } 145 | 146 | static void sl_text_input_leave(void* data, 147 | struct zwp_text_input_v1* text_input) { 148 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 149 | 150 | zwp_text_input_v1_send_leave(host->resource); 151 | } 152 | 153 | static void sl_text_input_modifiers_map(void* data, 154 | struct zwp_text_input_v1* text_input, 155 | struct wl_array* map) { 156 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 157 | 158 | zwp_text_input_v1_send_modifiers_map(host->resource, map); 159 | } 160 | 161 | static void sl_text_input_input_panel_state( 162 | void* data, struct zwp_text_input_v1* text_input, uint32_t state) { 163 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 164 | 165 | zwp_text_input_v1_send_input_panel_state(host->resource, state); 166 | } 167 | 168 | static void sl_text_input_preedit_string(void* data, 169 | struct zwp_text_input_v1* text_input, 170 | uint32_t serial, 171 | const char* text, 172 | const char* commit) { 173 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 174 | 175 | zwp_text_input_v1_send_preedit_string(host->resource, serial, text, commit); 176 | } 177 | 178 | static void sl_text_input_preedit_styling(void* data, 179 | struct zwp_text_input_v1* text_input, 180 | uint32_t index, 181 | uint32_t length, 182 | uint32_t style) { 183 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 184 | 185 | zwp_text_input_v1_send_preedit_styling(host->resource, index, length, style); 186 | } 187 | 188 | static void sl_text_input_preedit_cursor(void* data, 189 | struct zwp_text_input_v1* text_input, 190 | int32_t index) { 191 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 192 | 193 | zwp_text_input_v1_send_preedit_cursor(host->resource, index); 194 | } 195 | 196 | static void sl_text_input_commit_string(void* data, 197 | struct zwp_text_input_v1* text_input, 198 | uint32_t serial, 199 | const char* text) { 200 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 201 | 202 | zwp_text_input_v1_send_commit_string(host->resource, serial, text); 203 | } 204 | 205 | static void sl_text_input_cursor_position(void* data, 206 | struct zwp_text_input_v1* text_input, 207 | int32_t index, 208 | int32_t anchor) { 209 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 210 | 211 | zwp_text_input_v1_send_cursor_position(host->resource, index, anchor); 212 | } 213 | 214 | static void sl_text_input_delete_surrounding_text( 215 | void* data, 216 | struct zwp_text_input_v1* text_input, 217 | int32_t index, 218 | uint32_t length) { 219 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 220 | 221 | zwp_text_input_v1_send_delete_surrounding_text(host->resource, index, length); 222 | } 223 | 224 | static void sl_text_input_keysym(void* data, 225 | struct zwp_text_input_v1* text_input, 226 | uint32_t serial, 227 | uint32_t time, 228 | uint32_t sym, 229 | uint32_t state, 230 | uint32_t modifiers) { 231 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 232 | 233 | zwp_text_input_v1_send_keysym(host->resource, serial, time, sym, state, 234 | modifiers); 235 | } 236 | 237 | static void sl_text_input_language(void* data, 238 | struct zwp_text_input_v1* text_input, 239 | uint32_t serial, 240 | const char* language) { 241 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 242 | 243 | zwp_text_input_v1_send_language(host->resource, serial, language); 244 | } 245 | 246 | static void sl_text_input_text_direction(void* data, 247 | struct zwp_text_input_v1* text_input, 248 | uint32_t serial, 249 | uint32_t direction) { 250 | struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input); 251 | 252 | zwp_text_input_v1_send_text_direction(host->resource, serial, direction); 253 | } 254 | 255 | static const struct zwp_text_input_v1_listener sl_text_input_listener = { 256 | sl_text_input_enter, sl_text_input_leave, 257 | sl_text_input_modifiers_map, sl_text_input_input_panel_state, 258 | sl_text_input_preedit_string, sl_text_input_preedit_styling, 259 | sl_text_input_preedit_cursor, sl_text_input_commit_string, 260 | sl_text_input_cursor_position, sl_text_input_delete_surrounding_text, 261 | sl_text_input_keysym, sl_text_input_language, 262 | sl_text_input_text_direction, 263 | }; 264 | 265 | static void sl_destroy_host_text_input(struct wl_resource* resource) { 266 | struct sl_host_text_input* host = wl_resource_get_user_data(resource); 267 | 268 | zwp_text_input_v1_destroy(host->proxy); 269 | wl_resource_set_user_data(resource, NULL); 270 | free(host); 271 | } 272 | 273 | static void sl_text_input_manager_create_text_input( 274 | struct wl_client* client, struct wl_resource* resource, uint32_t id) { 275 | struct sl_host_text_input_manager* host = wl_resource_get_user_data(resource); 276 | struct wl_resource* text_input_resource = 277 | wl_resource_create(client, &zwp_text_input_v1_interface, 1, id); 278 | struct sl_host_text_input* text_input_host = 279 | malloc(sizeof(struct sl_host_text_input)); 280 | 281 | text_input_host->resource = text_input_resource; 282 | text_input_host->ctx = host->ctx; 283 | text_input_host->proxy = zwp_text_input_manager_v1_create_text_input( 284 | host->ctx->text_input_manager->internal); 285 | wl_resource_set_implementation(text_input_resource, 286 | &sl_text_input_implementation, text_input_host, 287 | sl_destroy_host_text_input); 288 | zwp_text_input_v1_set_user_data(text_input_host->proxy, text_input_host); 289 | zwp_text_input_v1_add_listener(text_input_host->proxy, 290 | &sl_text_input_listener, text_input_host); 291 | } 292 | 293 | static void sl_destroy_host_text_input_manager(struct wl_resource* resource) { 294 | struct sl_host_text_input_manager* host = wl_resource_get_user_data(resource); 295 | 296 | zwp_text_input_manager_v1_destroy(host->proxy); 297 | wl_resource_set_user_data(resource, NULL); 298 | free(host); 299 | } 300 | 301 | static struct zwp_text_input_manager_v1_interface 302 | sl_text_input_manager_implementation = { 303 | sl_text_input_manager_create_text_input, 304 | }; 305 | 306 | static void sl_bind_host_text_input_manager(struct wl_client* client, 307 | void* data, 308 | uint32_t version, 309 | uint32_t id) { 310 | struct sl_context* ctx = (struct sl_context*)data; 311 | struct sl_text_input_manager* text_input_manager = ctx->text_input_manager; 312 | struct sl_host_text_input_manager* host; 313 | 314 | host = malloc(sizeof(*host)); 315 | assert(host); 316 | host->ctx = ctx; 317 | host->resource = 318 | wl_resource_create(client, &zwp_text_input_manager_v1_interface, 1, id); 319 | wl_resource_set_implementation(host->resource, 320 | &sl_text_input_manager_implementation, host, 321 | sl_destroy_host_text_input_manager); 322 | host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display), 323 | text_input_manager->id, 324 | &zwp_text_input_manager_v1_interface, 325 | wl_resource_get_version(host->resource)); 326 | zwp_text_input_manager_v1_set_user_data(host->proxy, host); 327 | } 328 | 329 | struct sl_global* sl_text_input_manager_global_create(struct sl_context* ctx) { 330 | return sl_global_create(ctx, &zwp_text_input_manager_v1_interface, 1, ctx, 331 | sl_bind_host_text_input_manager); 332 | } 333 | -------------------------------------------------------------------------------- /sommelier-viewporter.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 "sommelier.h" 6 | 7 | #include 8 | #include 9 | 10 | #include "viewporter-client-protocol.h" 11 | #include "viewporter-server-protocol.h" 12 | 13 | struct sl_host_viewporter { 14 | struct sl_viewporter* viewporter; 15 | struct wl_resource* resource; 16 | struct wp_viewporter* proxy; 17 | }; 18 | 19 | struct sl_host_viewport { 20 | struct wl_resource* resource; 21 | struct sl_viewport viewport; 22 | }; 23 | 24 | static void sl_viewport_destroy(struct wl_client* client, 25 | struct wl_resource* resource) { 26 | wl_resource_destroy(resource); 27 | } 28 | 29 | static void sl_viewport_set_source(struct wl_client* client, 30 | struct wl_resource* resource, 31 | wl_fixed_t x, 32 | wl_fixed_t y, 33 | wl_fixed_t width, 34 | wl_fixed_t height) { 35 | struct sl_host_viewport* host = wl_resource_get_user_data(resource); 36 | 37 | host->viewport.src_x = x; 38 | host->viewport.src_y = y; 39 | host->viewport.src_width = width; 40 | host->viewport.src_height = height; 41 | } 42 | 43 | static void sl_viewport_set_destination(struct wl_client* client, 44 | struct wl_resource* resource, 45 | int32_t width, 46 | int32_t height) { 47 | struct sl_host_viewport* host = wl_resource_get_user_data(resource); 48 | 49 | host->viewport.dst_width = width; 50 | host->viewport.dst_height = height; 51 | } 52 | 53 | static const struct wp_viewport_interface sl_viewport_implementation = { 54 | sl_viewport_destroy, sl_viewport_set_source, sl_viewport_set_destination}; 55 | 56 | static void sl_destroy_host_viewport(struct wl_resource* resource) { 57 | struct sl_host_viewport* host = wl_resource_get_user_data(resource); 58 | 59 | wl_resource_set_user_data(resource, NULL); 60 | wl_list_remove(&host->viewport.link); 61 | free(host); 62 | } 63 | 64 | static void sl_viewporter_destroy(struct wl_client* client, 65 | struct wl_resource* resource) { 66 | wl_resource_destroy(resource); 67 | } 68 | 69 | static void sl_viewporter_get_viewport(struct wl_client* client, 70 | struct wl_resource* resource, 71 | uint32_t id, 72 | struct wl_resource* surface_resource) { 73 | struct sl_host_surface* host_surface = 74 | wl_resource_get_user_data(surface_resource); 75 | struct sl_host_viewport* host_viewport; 76 | 77 | host_viewport = malloc(sizeof(*host_viewport)); 78 | assert(host_viewport); 79 | 80 | host_viewport->viewport.src_x = -1; 81 | host_viewport->viewport.src_y = -1; 82 | host_viewport->viewport.src_width = -1; 83 | host_viewport->viewport.src_height = -1; 84 | host_viewport->viewport.dst_width = -1; 85 | host_viewport->viewport.dst_height = -1; 86 | wl_list_insert(&host_surface->contents_viewport, 87 | &host_viewport->viewport.link); 88 | host_viewport->resource = 89 | wl_resource_create(client, &wp_viewport_interface, 1, id); 90 | wl_resource_set_implementation(host_viewport->resource, 91 | &sl_viewport_implementation, host_viewport, 92 | sl_destroy_host_viewport); 93 | } 94 | 95 | static const struct wp_viewporter_interface sl_viewporter_implementation = { 96 | sl_viewporter_destroy, sl_viewporter_get_viewport}; 97 | 98 | static void sl_destroy_host_viewporter(struct wl_resource* resource) { 99 | struct sl_host_viewporter* host = wl_resource_get_user_data(resource); 100 | 101 | wp_viewporter_destroy(host->proxy); 102 | wl_resource_set_user_data(resource, NULL); 103 | free(host); 104 | } 105 | 106 | static void sl_bind_host_viewporter(struct wl_client* client, 107 | void* data, 108 | uint32_t version, 109 | uint32_t id) { 110 | struct sl_context* ctx = (struct sl_context*)data; 111 | struct sl_host_viewporter* host; 112 | 113 | host = malloc(sizeof(*host)); 114 | assert(host); 115 | host->viewporter = ctx->viewporter; 116 | host->resource = wl_resource_create(client, &wp_viewporter_interface, 1, id); 117 | wl_resource_set_implementation(host->resource, &sl_viewporter_implementation, 118 | host, sl_destroy_host_viewporter); 119 | host->proxy = 120 | wl_registry_bind(wl_display_get_registry(ctx->display), 121 | ctx->viewporter->id, &wp_viewporter_interface, 1); 122 | wp_viewporter_set_user_data(host->proxy, host); 123 | } 124 | 125 | struct sl_global* sl_viewporter_global_create(struct sl_context* ctx) { 126 | return sl_global_create(ctx, &wp_viewporter_interface, 1, ctx, 127 | sl_bind_host_viewporter); 128 | } -------------------------------------------------------------------------------- /sommelier.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'conditions': [ 3 | ['USE_amd64 == 1', { 4 | 'variables': { 5 | 'peer_cmd_prefix%': '"/opt/google/cros-containers/lib/ld-linux-x86-64.so.2 --library-path /opt/google/cros-containers/lib --inhibit-rpath \\"\\""', 6 | }, 7 | }], 8 | ['USE_arm == 1', { 9 | 'variables': { 10 | 'peer_cmd_prefix%': '"/opt/google/cros-containers/lib/ld-linux-armhf.so.3 --library-path /opt/google/cros-containers/lib --inhibit-rpath \\"\\""', 11 | }, 12 | }], 13 | ], 14 | 'variables': { 15 | # Set this to the Xwayland path. 16 | 'xwayland_path%': '"/opt/google/cros-containers/bin/Xwayland"', 17 | 18 | # Set this to the GL driver path to use for Xwayland. 19 | 'xwayland_gl_driver_path%': '"/opt/google/cros-containers/lib"', 20 | 21 | # Set this to the shm driver to use for Xwayland. 22 | 'xwayland_shm_driver%': '"virtwl"', 23 | 24 | # Set this to the shm driver to use for wayland clients. 25 | 'shm_driver%': '"virtwl-dmabuf"', 26 | 27 | # Set this to the virtwl device. 28 | 'virtwl_device%': '"/dev/wl0"', 29 | 30 | # Set this to the frame color to use for Xwayland clients. 31 | 'frame_color%': '"#f2f2f2"', 32 | 33 | # Set this to the dark frame color to use for Xwayland clients. 34 | 'dark_frame_color%': '"#323639"', 35 | }, 36 | 'targets': [ 37 | { 38 | 'target_name': 'sommelier-protocol', 39 | 'type': 'static_library', 40 | 'variables': { 41 | 'wayland_in_dir': 'protocol', 42 | 'wayland_out_dir': '.', 43 | }, 44 | 'sources': [ 45 | 'protocol/aura-shell.xml', 46 | 'protocol/drm.xml', 47 | 'protocol/gtk-shell.xml', 48 | 'protocol/keyboard-extension-unstable-v1.xml', 49 | 'protocol/linux-dmabuf-unstable-v1.xml', 50 | 'protocol/text-input-unstable-v1.xml', 51 | 'protocol/viewporter.xml', 52 | 'protocol/xdg-shell.xml', 53 | ], 54 | 'includes': ['wayland-protocol.gypi'], 55 | }, 56 | { 57 | 'target_name': 'sommelier', 58 | 'type': 'executable', 59 | 'variables': { 60 | 'exported_deps': [ 61 | 'gbm', 62 | 'libdrm', 63 | 'pixman-1', 64 | 'wayland-client', 65 | 'wayland-server', 66 | 'xcb', 67 | 'xcb-composite', 68 | 'xcb-xfixes', 69 | 'xkbcommon', 70 | ], 71 | 'deps': ['<@(exported_deps)'], 72 | }, 73 | 'link_settings': { 74 | 'libraries': [ 75 | '-lm', 76 | ], 77 | }, 78 | 'dependencies': [ 79 | 'sommelier-protocol', 80 | ], 81 | 'sources': [ 82 | 'sommelier-compositor.c', 83 | 'sommelier-data-device-manager.c', 84 | 'sommelier-display.c', 85 | 'sommelier-drm.c', 86 | 'sommelier-gtk-shell.c', 87 | 'sommelier-output.c', 88 | 'sommelier-seat.c', 89 | 'sommelier-shell.c', 90 | 'sommelier-shm.c', 91 | 'sommelier-subcompositor.c', 92 | 'sommelier-text-input.c', 93 | 'sommelier-viewporter.c', 94 | 'sommelier-xdg-shell.c', 95 | 'sommelier.c', 96 | ], 97 | 'defines': [ 98 | '_GNU_SOURCE', 99 | 'WL_HIDE_DEPRECATED', 100 | 'XWAYLAND_PATH=<@(xwayland_path)', 101 | 'XWAYLAND_GL_DRIVER_PATH=<@(xwayland_gl_driver_path)', 102 | 'XWAYLAND_SHM_DRIVER=<@(xwayland_shm_driver)', 103 | 'SHM_DRIVER=<@(shm_driver)', 104 | 'VIRTWL_DEVICE=<@(virtwl_device)', 105 | 'PEER_CMD_PREFIX=<@(peer_cmd_prefix)', 106 | 'FRAME_COLOR=<@(frame_color)', 107 | 'DARK_FRAME_COLOR=<@(dark_frame_color)', 108 | ], 109 | }, 110 | { 111 | 'target_name': 'wayland_demo', 112 | 'type': 'executable', 113 | 'variables': { 114 | 'deps': [ 115 | 'libbrillo-<(libbase_ver)', 116 | 'libchrome-<(libbase_ver)', 117 | 'wayland-client', 118 | ], 119 | }, 120 | 'link_settings': { 121 | 'libraries': [ 122 | '-lwayland-client', 123 | ], 124 | }, 125 | 'sources': [ 126 | 'demos/wayland_demo.cc', 127 | ], 128 | }, 129 | { 130 | 'target_name': 'x11_demo', 131 | 'type': 'executable', 132 | 'variables': { 133 | 'deps': [ 134 | 'libbrillo-<(libbase_ver)', 135 | 'libchrome-<(libbase_ver)', 136 | ], 137 | }, 138 | 'link_settings': { 139 | 'libraries': [ 140 | '-lX11', 141 | ], 142 | }, 143 | 'sources': [ 144 | 'demos/x11_demo.cc', 145 | ], 146 | }, 147 | ], 148 | } 149 | -------------------------------------------------------------------------------- /sommelier.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Chromium OS 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 | #ifndef VM_TOOLS_SOMMELIER_SOMMELIER_H_ 6 | #define VM_TOOLS_SOMMELIER_SOMMELIER_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define SOMMELIER_VERSION "0.20" 15 | 16 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 17 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 18 | 19 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 20 | 21 | #define UNUSED(x) ((void)(x)) 22 | 23 | #define CONTROL_MASK (1 << 0) 24 | #define ALT_MASK (1 << 1) 25 | #define SHIFT_MASK (1 << 2) 26 | 27 | struct sl_global; 28 | struct sl_compositor; 29 | struct sl_shm; 30 | struct sl_shell; 31 | struct sl_data_device_manager; 32 | struct sl_data_offer; 33 | struct sl_data_source; 34 | struct sl_xdg_shell; 35 | struct sl_subcompositor; 36 | struct sl_aura_shell; 37 | struct sl_viewporter; 38 | struct sl_linux_dmabuf; 39 | struct sl_keyboard_extension; 40 | struct sl_text_input_manager; 41 | struct sl_relative_pointer_manager; 42 | struct sl_pointer_constraints; 43 | struct sl_window; 44 | struct zaura_shell; 45 | struct zcr_keyboard_extension_v1; 46 | 47 | enum { 48 | ATOM_WM_S0, 49 | ATOM_WM_PROTOCOLS, 50 | ATOM_WM_STATE, 51 | ATOM_WM_CHANGE_STATE, 52 | ATOM_WM_DELETE_WINDOW, 53 | ATOM_WM_TAKE_FOCUS, 54 | ATOM_WM_CLIENT_LEADER, 55 | ATOM_WL_SURFACE_ID, 56 | ATOM_UTF8_STRING, 57 | ATOM_MOTIF_WM_HINTS, 58 | ATOM_NET_ACTIVE_WINDOW, 59 | ATOM_NET_FRAME_EXTENTS, 60 | ATOM_NET_STARTUP_ID, 61 | ATOM_NET_SUPPORTED, 62 | ATOM_NET_SUPPORTING_WM_CHECK, 63 | ATOM_NET_WM_NAME, 64 | ATOM_NET_WM_MOVERESIZE, 65 | ATOM_NET_WM_STATE, 66 | ATOM_NET_WM_STATE_FULLSCREEN, 67 | ATOM_NET_WM_STATE_MAXIMIZED_VERT, 68 | ATOM_NET_WM_STATE_MAXIMIZED_HORZ, 69 | ATOM_CLIPBOARD, 70 | ATOM_CLIPBOARD_MANAGER, 71 | ATOM_TARGETS, 72 | ATOM_TIMESTAMP, 73 | ATOM_TEXT, 74 | ATOM_INCR, 75 | ATOM_WL_SELECTION, 76 | ATOM_GTK_THEME_VARIANT, 77 | ATOM_LAST = ATOM_GTK_THEME_VARIANT, 78 | }; 79 | 80 | enum { 81 | SHM_DRIVER_NOOP, 82 | SHM_DRIVER_DMABUF, 83 | SHM_DRIVER_VIRTWL, 84 | SHM_DRIVER_VIRTWL_DMABUF, 85 | }; 86 | 87 | enum { 88 | DATA_DRIVER_NOOP, 89 | DATA_DRIVER_VIRTWL, 90 | }; 91 | 92 | struct sl_context { 93 | char** runprog; 94 | struct wl_display* display; 95 | struct wl_display* host_display; 96 | struct wl_client* client; 97 | struct sl_compositor* compositor; 98 | struct sl_subcompositor* subcompositor; 99 | struct sl_shm* shm; 100 | struct sl_shell* shell; 101 | struct sl_data_device_manager* data_device_manager; 102 | struct sl_xdg_shell* xdg_shell; 103 | struct sl_aura_shell* aura_shell; 104 | struct sl_viewporter* viewporter; 105 | struct sl_linux_dmabuf* linux_dmabuf; 106 | struct sl_keyboard_extension* keyboard_extension; 107 | struct sl_text_input_manager* text_input_manager; 108 | struct sl_relative_pointer_manager* relative_pointer_manager; 109 | struct sl_pointer_constraints* pointer_constraints; 110 | struct wl_list outputs; 111 | struct wl_list seats; 112 | struct wl_event_source* display_event_source; 113 | struct wl_event_source* display_ready_event_source; 114 | struct wl_event_source* sigchld_event_source; 115 | struct wl_array dpi; 116 | int shm_driver; 117 | int data_driver; 118 | int wm_fd; 119 | int virtwl_fd; 120 | int virtwl_ctx_fd; 121 | int virtwl_socket_fd; 122 | struct wl_event_source* virtwl_ctx_event_source; 123 | struct wl_event_source* virtwl_socket_event_source; 124 | const char* drm_device; 125 | struct gbm_device* gbm; 126 | int xwayland; 127 | pid_t xwayland_pid; 128 | pid_t child_pid; 129 | pid_t peer_pid; 130 | struct xkb_context* xkb_context; 131 | struct wl_list accelerators; 132 | struct wl_list registries; 133 | struct wl_list globals; 134 | struct wl_list host_outputs; 135 | int next_global_id; 136 | xcb_connection_t* connection; 137 | struct wl_event_source* connection_event_source; 138 | const xcb_query_extension_reply_t* xfixes_extension; 139 | xcb_screen_t* screen; 140 | xcb_window_t window; 141 | struct wl_list windows, unpaired_windows; 142 | struct sl_window* host_focus_window; 143 | int needs_set_input_focus; 144 | double desired_scale; 145 | double scale; 146 | const char* application_id; 147 | int exit_with_child; 148 | const char* sd_notify; 149 | int clipboard_manager; 150 | uint32_t frame_color; 151 | uint32_t dark_frame_color; 152 | int fullscreen_mode; 153 | const char* overridden_output_scales; 154 | int pointer_scale; 155 | struct sl_host_seat* default_seat; 156 | xcb_window_t selection_window; 157 | xcb_window_t selection_owner; 158 | int selection_incremental_transfer; 159 | xcb_selection_request_event_t selection_request; 160 | xcb_timestamp_t selection_timestamp; 161 | struct wl_data_device* selection_data_device; 162 | struct sl_data_offer* selection_data_offer; 163 | struct sl_data_source* selection_data_source; 164 | int selection_data_source_send_fd; 165 | struct wl_list selection_data_source_send_pending; 166 | struct wl_event_source* selection_send_event_source; 167 | xcb_get_property_reply_t* selection_property_reply; 168 | int selection_property_offset; 169 | struct wl_event_source* selection_event_source; 170 | xcb_atom_t selection_data_type; 171 | struct wl_array selection_data; 172 | int selection_data_offer_receive_fd; 173 | int selection_data_ack_pending; 174 | union { 175 | const char* name; 176 | xcb_intern_atom_cookie_t cookie; 177 | xcb_atom_t value; 178 | } atoms[ATOM_LAST + 1]; 179 | xcb_visualid_t visual_ids[256]; 180 | xcb_colormap_t colormaps[256]; 181 | }; 182 | 183 | struct sl_compositor { 184 | struct sl_context* ctx; 185 | uint32_t id; 186 | uint32_t version; 187 | struct sl_global* host_global; 188 | struct wl_compositor* internal; 189 | }; 190 | 191 | struct sl_shm { 192 | struct sl_context* ctx; 193 | uint32_t id; 194 | struct sl_global* host_global; 195 | struct wl_shm* internal; 196 | }; 197 | 198 | struct sl_seat { 199 | struct sl_context* ctx; 200 | uint32_t id; 201 | uint32_t version; 202 | struct sl_global* host_global; 203 | uint32_t last_serial; 204 | struct wl_list link; 205 | }; 206 | 207 | struct sl_host_pointer { 208 | struct sl_seat* seat; 209 | struct wl_resource* resource; 210 | struct wl_pointer* proxy; 211 | struct wl_resource* focus_resource; 212 | struct wl_listener focus_resource_listener; 213 | uint32_t focus_serial; 214 | uint32_t time; 215 | wl_fixed_t axis_delta[2]; 216 | int32_t axis_discrete[2]; 217 | }; 218 | 219 | struct sl_relative_pointer_manager { 220 | struct sl_context* ctx; 221 | uint32_t id; 222 | struct sl_global* host_global; 223 | struct zwp_relative_pointer_manager_v1* internal; 224 | }; 225 | 226 | struct sl_viewport { 227 | struct wl_list link; 228 | wl_fixed_t src_x; 229 | wl_fixed_t src_y; 230 | wl_fixed_t src_width; 231 | wl_fixed_t src_height; 232 | int32_t dst_width; 233 | int32_t dst_height; 234 | }; 235 | 236 | struct sl_host_callback { 237 | struct wl_resource* resource; 238 | struct wl_callback* proxy; 239 | }; 240 | 241 | struct sl_host_surface { 242 | struct sl_context* ctx; 243 | struct wl_resource* resource; 244 | struct wl_surface* proxy; 245 | struct wp_viewport* viewport; 246 | uint32_t contents_width; 247 | uint32_t contents_height; 248 | int32_t contents_scale; 249 | struct wl_list contents_viewport; 250 | struct sl_mmap* contents_shm_mmap; 251 | int has_role; 252 | int has_output; 253 | uint32_t last_event_serial; 254 | struct sl_output_buffer* current_buffer; 255 | struct wl_list released_buffers; 256 | struct wl_list busy_buffers; 257 | int defer_commits_until_configure; 258 | int is_pointer; 259 | }; 260 | 261 | struct sl_host_region { 262 | struct sl_context* ctx; 263 | struct wl_resource* resource; 264 | struct wl_region* proxy; 265 | }; 266 | 267 | struct sl_host_buffer { 268 | struct wl_resource* resource; 269 | struct wl_buffer* proxy; 270 | uint32_t width; 271 | uint32_t height; 272 | struct sl_mmap* shm_mmap; 273 | uint32_t shm_format; 274 | struct sl_sync_point* sync_point; 275 | }; 276 | 277 | struct sl_data_source_send_request { 278 | int fd; 279 | xcb_intern_atom_cookie_t cookie; 280 | struct sl_data_source* data_source; 281 | struct wl_list link; 282 | }; 283 | 284 | struct sl_subcompositor { 285 | struct sl_context* ctx; 286 | uint32_t id; 287 | struct sl_global* host_global; 288 | }; 289 | 290 | struct sl_shell { 291 | struct sl_context* ctx; 292 | uint32_t id; 293 | struct sl_global* host_global; 294 | }; 295 | 296 | struct sl_output { 297 | struct sl_context* ctx; 298 | uint32_t id; 299 | uint32_t version; 300 | struct sl_global* host_global; 301 | struct wl_list link; 302 | }; 303 | 304 | struct sl_host_output { 305 | struct sl_context* ctx; 306 | struct wl_resource* resource; 307 | struct wl_output* proxy; 308 | struct zaura_output* aura_output; 309 | int internal; 310 | int x; 311 | int y; 312 | int physical_width; 313 | int physical_height; 314 | int subpixel; 315 | char* make; 316 | char* model; 317 | char* name; 318 | int transform; 319 | uint32_t flags; 320 | int width; 321 | int height; 322 | int refresh; 323 | int scale_factor; 324 | int current_scale; 325 | int preferred_scale; 326 | int device_scale_factor; 327 | int expecting_scale; 328 | double applied_scale; 329 | struct wl_list link; 330 | }; 331 | 332 | struct sl_host_seat { 333 | struct sl_seat* seat; 334 | struct wl_resource* resource; 335 | struct wl_seat* proxy; 336 | }; 337 | 338 | struct sl_accelerator { 339 | struct wl_list link; 340 | uint32_t modifiers; 341 | xkb_keysym_t symbol; 342 | }; 343 | 344 | struct sl_keyboard_extension { 345 | struct sl_context* ctx; 346 | uint32_t id; 347 | struct zcr_keyboard_extension_v1* internal; 348 | }; 349 | 350 | struct sl_data_device_manager { 351 | struct sl_context* ctx; 352 | uint32_t id; 353 | uint32_t version; 354 | struct sl_global* host_global; 355 | struct wl_data_device_manager* internal; 356 | }; 357 | 358 | struct sl_data_offer { 359 | struct sl_context* ctx; 360 | struct wl_data_offer* internal; 361 | struct wl_array atoms; // Contains xcb_atom_t 362 | struct wl_array cookies; // Contains xcb_intern_atom_cookie_t 363 | }; 364 | 365 | struct sl_text_input_manager { 366 | struct sl_context* ctx; 367 | uint32_t id; 368 | struct sl_global* host_global; 369 | struct zwp_text_input_manager_v1* internal; 370 | }; 371 | 372 | struct sl_pointer_constraints { 373 | struct sl_context* ctx; 374 | uint32_t id; 375 | struct sl_global* host_global; 376 | struct zwp_pointer_constraints_v1* internal; 377 | }; 378 | 379 | struct sl_viewporter { 380 | struct sl_context* ctx; 381 | uint32_t id; 382 | struct sl_global* host_viewporter_global; 383 | struct wp_viewporter* internal; 384 | }; 385 | 386 | struct sl_xdg_shell { 387 | struct sl_context* ctx; 388 | uint32_t id; 389 | struct sl_global* host_global; 390 | struct xdg_wm_base* internal; 391 | }; 392 | 393 | struct sl_aura_shell { 394 | struct sl_context* ctx; 395 | uint32_t id; 396 | uint32_t version; 397 | struct sl_global* host_gtk_shell_global; 398 | struct zaura_shell* internal; 399 | }; 400 | 401 | struct sl_linux_dmabuf { 402 | struct sl_context* ctx; 403 | uint32_t id; 404 | uint32_t version; 405 | struct sl_global* host_drm_global; 406 | struct zwp_linux_dmabuf_v1* internal; 407 | }; 408 | 409 | struct sl_global { 410 | struct sl_context* ctx; 411 | const struct wl_interface* interface; 412 | uint32_t name; 413 | uint32_t version; 414 | void* data; 415 | wl_global_bind_func_t bind; 416 | struct wl_list link; 417 | }; 418 | 419 | struct sl_host_registry { 420 | struct sl_context* ctx; 421 | struct wl_resource* resource; 422 | struct wl_list link; 423 | }; 424 | 425 | typedef void (*sl_begin_end_access_func_t)(int fd); 426 | 427 | struct sl_mmap { 428 | int refcount; 429 | int fd; 430 | void* addr; 431 | size_t size; 432 | size_t bpp; 433 | size_t num_planes; 434 | size_t offset[2]; 435 | size_t stride[2]; 436 | size_t y_ss[2]; 437 | sl_begin_end_access_func_t begin_write; 438 | sl_begin_end_access_func_t end_write; 439 | struct wl_resource* buffer_resource; 440 | }; 441 | 442 | typedef void (*sl_sync_func_t)(struct sl_context* ctx, 443 | struct sl_sync_point* sync_point); 444 | 445 | struct sl_sync_point { 446 | int fd; 447 | sl_sync_func_t sync; 448 | }; 449 | 450 | struct sl_config { 451 | uint32_t serial; 452 | uint32_t mask; 453 | uint32_t values[5]; 454 | uint32_t states_length; 455 | uint32_t states[3]; 456 | }; 457 | 458 | struct sl_window { 459 | struct sl_context* ctx; 460 | xcb_window_t id; 461 | xcb_window_t frame_id; 462 | uint32_t host_surface_id; 463 | int unpaired; 464 | int x; 465 | int y; 466 | int width; 467 | int height; 468 | int border_width; 469 | int depth; 470 | int managed; 471 | int realized; 472 | int activated; 473 | int maximized; 474 | int allow_resize; 475 | xcb_window_t transient_for; 476 | xcb_window_t client_leader; 477 | int decorated; 478 | char* name; 479 | char* clazz; 480 | char* startup_id; 481 | int dark_frame; 482 | uint32_t size_flags; 483 | int focus_model_take_focus; 484 | int min_width; 485 | int min_height; 486 | int max_width; 487 | int max_height; 488 | struct sl_config next_config; 489 | struct sl_config pending_config; 490 | struct xdg_surface* xdg_surface; 491 | struct xdg_toplevel* xdg_toplevel; 492 | struct xdg_popup* xdg_popup; 493 | struct zaura_surface* aura_surface; 494 | struct wl_list link; 495 | }; 496 | 497 | struct sl_host_buffer* sl_create_host_buffer(struct wl_client* client, 498 | uint32_t id, 499 | struct wl_buffer* proxy, 500 | int32_t width, 501 | int32_t height); 502 | 503 | struct sl_global* sl_global_create(struct sl_context* ctx, 504 | const struct wl_interface* interface, 505 | int version, 506 | void* data, 507 | wl_global_bind_func_t bind); 508 | 509 | struct sl_global* sl_compositor_global_create(struct sl_context* ctx); 510 | 511 | size_t sl_shm_bpp_for_shm_format(uint32_t format); 512 | 513 | size_t sl_shm_num_planes_for_shm_format(uint32_t format); 514 | 515 | struct sl_global* sl_shm_global_create(struct sl_context* ctx); 516 | 517 | struct sl_global* sl_subcompositor_global_create(struct sl_context* ctx); 518 | 519 | struct sl_global* sl_shell_global_create(struct sl_context* ctx); 520 | 521 | double sl_output_aura_scale_factor_to_double(int scale_factor); 522 | 523 | void sl_output_send_host_output_state(struct sl_host_output* host); 524 | 525 | struct sl_global* sl_output_global_create(struct sl_output* output); 526 | 527 | struct sl_global* sl_seat_global_create(struct sl_seat* seat); 528 | 529 | struct sl_global* sl_relative_pointer_manager_global_create( 530 | struct sl_context* ctx); 531 | 532 | struct sl_global* sl_data_device_manager_global_create(struct sl_context* ctx); 533 | 534 | struct sl_global* sl_viewporter_global_create(struct sl_context* ctx); 535 | 536 | struct sl_global* sl_xdg_shell_global_create(struct sl_context* ctx); 537 | 538 | struct sl_global* sl_gtk_shell_global_create(struct sl_context* ctx); 539 | 540 | struct sl_global* sl_drm_global_create(struct sl_context* ctx); 541 | 542 | struct sl_global* sl_text_input_manager_global_create(struct sl_context* ctx); 543 | 544 | struct sl_global* sl_pointer_constraints_global_create(struct sl_context* ctx); 545 | 546 | void sl_set_display_implementation(struct sl_context* ctx); 547 | 548 | struct sl_mmap* sl_mmap_create(int fd, 549 | size_t size, 550 | size_t bpp, 551 | size_t num_planes, 552 | size_t offset0, 553 | size_t stride0, 554 | size_t offset1, 555 | size_t stride1, 556 | size_t y_ss0, 557 | size_t y_ss1); 558 | struct sl_mmap* sl_mmap_ref(struct sl_mmap* map); 559 | void sl_mmap_unref(struct sl_mmap* map); 560 | 561 | struct sl_sync_point* sl_sync_point_create(int fd); 562 | void sl_sync_point_destroy(struct sl_sync_point* sync_point); 563 | 564 | void sl_host_seat_added(struct sl_host_seat* host); 565 | void sl_host_seat_removed(struct sl_host_seat* host); 566 | 567 | void sl_restack_windows(struct sl_context* ctx, uint32_t focus_resource_id); 568 | 569 | void sl_roundtrip(struct sl_context* ctx); 570 | 571 | int sl_process_pending_configure_acks(struct sl_window* window, 572 | struct sl_host_surface* host_surface); 573 | 574 | void sl_window_update(struct sl_window* window); 575 | 576 | #endif // VM_TOOLS_SOMMELIER_SOMMELIER_H_ 577 | -------------------------------------------------------------------------------- /wayland-protocol.gypi: -------------------------------------------------------------------------------- 1 | { 2 | 'variables': { 3 | 'wayland_dir': '<(SHARED_INTERMEDIATE_DIR)/<(wayland_out_dir)', 4 | 'wayland_in_dir%': '.', 5 | }, 6 | 'rules': [ 7 | { 8 | 'rule_name': 'genwayland', 9 | 'extension': 'xml', 10 | 'outputs': [ 11 | '<(wayland_dir)/<(RULE_INPUT_ROOT)-protocol.c', 12 | '<(wayland_dir)/<(RULE_INPUT_ROOT)-client-protocol.h', 13 | '<(wayland_dir)/<(RULE_INPUT_ROOT)-server-protocol.h', 14 | ], 15 | 'action': [ 16 | 'sh', 17 | '-c', 18 | 'wayland-scanner code < <(wayland_in_dir)/<(RULE_INPUT_NAME) > <(wayland_dir)/<(RULE_INPUT_ROOT)-protocol.c; wayland-scanner client-header < <(wayland_in_dir)/<(RULE_INPUT_NAME) > <(wayland_dir)/<(RULE_INPUT_ROOT)-client-protocol.h; wayland-scanner server-header < <(wayland_in_dir)/<(RULE_INPUT_NAME) > <(wayland_dir)/<(RULE_INPUT_ROOT)-server-protocol.h', 19 | ], 20 | 'message': 'Generating Wayland C code from <(RULE_INPUT_PATH)', 21 | 'process_outputs_as_sources': 1, 22 | }, 23 | ], 24 | # This target exports a hard dependency because it generates header 25 | # files. 26 | 'hard_dependency': 1, 27 | 'direct_dependent_settings': { 28 | 'include_dirs': [ 29 | '<(wayland_dir)', 30 | ], 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /wayland_protocol.gni: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Chromium OS 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 | # GN template to generate static library for given Wayland protorol description files. 6 | # Parameters: 7 | # sources 8 | # Wayland protocol description XML file paths. 9 | # out_dir (optional) 10 | # Directory to output generated source files. Relative to gen/ directory. 11 | template("wayland_protocol_library") { 12 | forward_variables_from(invoker, [ "out_dir" ]) 13 | if (!defined(out_dir)) { 14 | out_dir = "." 15 | } 16 | wayland_dir = "${root_gen_dir}/${out_dir}" 17 | 18 | generators = [ 19 | { 20 | subcommand = "code" 21 | output_suffix = "-protocol.c" 22 | }, 23 | { 24 | subcommand = "client-header" 25 | output_suffix = "-client-protocol.h" 26 | }, 27 | { 28 | subcommand = "server-header" 29 | output_suffix = "-server-protocol.h" 30 | }, 31 | ] 32 | generator_actions = [] 33 | foreach(g, generators) { 34 | action_name = "${target_name}_${g.subcommand}" 35 | generator_actions += [ ":" + action_name ] 36 | action_foreach(action_name) { 37 | sources = invoker.sources 38 | script = "//common-mk/file_generator_wrapper.py" 39 | output_file = "${wayland_dir}/{{source_name_part}}${g.output_suffix}" 40 | outputs = [ output_file ] 41 | args = [ 42 | "wayland-scanner", 43 | g.subcommand, 44 | "{{source}}", 45 | output_file, 46 | ] 47 | } 48 | } 49 | 50 | static_library(target_name) { 51 | if (defined(invoker.configs)) { 52 | configs += invoker.configs 53 | } 54 | deps = generator_actions 55 | sources = [] 56 | foreach(t, deps) { 57 | sources += get_target_outputs(t) 58 | } 59 | if (defined(invoker.deps)) { 60 | deps += invoker.deps 61 | } 62 | } 63 | } 64 | --------------------------------------------------------------------------------