add sommelier
This commit is contained in:
parent
d962bb4d46
commit
1dcad9f1f4
145
sommelier/BUILD.gn
Normal file
145
sommelier/BUILD.gn
Normal file
@ -0,0 +1,145 @@
|
||||
# Copyright 2019 The Chromium OS Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("wayland_protocol.gni")
|
||||
|
||||
group("all") {
|
||||
deps = [
|
||||
":sommelier",
|
||||
":wayland_demo",
|
||||
":x11_demo",
|
||||
]
|
||||
}
|
||||
|
||||
if (!defined(peer_cmd_prefix)) {
|
||||
# if (use.amd64) {
|
||||
peer_cmd_prefix = "\"/opt/google/cros-containers/lib/ld-linux-x86-64.so.2 --library-path /opt/google/cros-containers/lib --inhibit-rpath \\\"\\\"\""
|
||||
# }
|
||||
# if (use.arm) {
|
||||
# peer_cmd_prefix = "\"/opt/google/cros-containers/lib/ld-linux-armhf.so.3 --library-path /opt/google/cros-containers/lib --inhibit-rpath \\\"\\\"\""
|
||||
# }
|
||||
}
|
||||
|
||||
# Set this to the Xwayland path.
|
||||
if (!defined(xwayland_path)) {
|
||||
xwayland_path = "\"/opt/google/cros-containers/bin/Xwayland\""
|
||||
}
|
||||
|
||||
# Set this to the GL driver path to use for Xwayland.
|
||||
if (!defined(xwayland_gl_driver_path)) {
|
||||
xwayland_gl_driver_path = "\"/opt/google/cros-containers/lib\""
|
||||
}
|
||||
|
||||
# Set this to the shm driver to use for Xwayland.
|
||||
if (!defined(xwayland_shm_driver)) {
|
||||
xwayland_shm_driver = "\"virtwl\""
|
||||
}
|
||||
|
||||
# Set this to the shm driver to use for wayland clients.
|
||||
if (!defined(shm_driver)) {
|
||||
shm_driver = "\"virtwl-dmabuf\""
|
||||
}
|
||||
|
||||
# Set this to the virtwl device.
|
||||
if (!defined(virtwl_device)) {
|
||||
virtwl_device = "\"/dev/wl0\""
|
||||
}
|
||||
|
||||
# Set this to the frame color to use for Xwayland clients.
|
||||
if (!defined(frame_color)) {
|
||||
frame_color = "\"#f2f2f2\""
|
||||
}
|
||||
|
||||
# Set this to the dark frame color to use for Xwayland clients.
|
||||
if (!defined(dark_frame_color)) {
|
||||
dark_frame_color = "\"#323639\""
|
||||
}
|
||||
|
||||
wayland_protocol_library("sommelier-protocol") {
|
||||
out_dir = "include"
|
||||
sources = [
|
||||
"protocol/aura-shell.xml",
|
||||
"protocol/drm.xml",
|
||||
"protocol/gtk-shell.xml",
|
||||
"protocol/keyboard-extension-unstable-v1.xml",
|
||||
"protocol/linux-dmabuf-unstable-v1.xml",
|
||||
"protocol/relative-pointer-unstable-v1.xml",
|
||||
"protocol/text-input-unstable-v1.xml",
|
||||
"protocol/viewporter.xml",
|
||||
"protocol/xdg-shell-unstable-v6.xml",
|
||||
]
|
||||
}
|
||||
|
||||
executable("sommelier") {
|
||||
pkg_deps = [
|
||||
"gbm",
|
||||
"grpc++",
|
||||
"libdrm",
|
||||
"pixman-1",
|
||||
"protobuf",
|
||||
"vm_protos",
|
||||
"wayland-client",
|
||||
"wayland-server",
|
||||
"xcb",
|
||||
"xcb-composite",
|
||||
"xcb-xfixes",
|
||||
"xkbcommon",
|
||||
]
|
||||
libs = [ "m" ]
|
||||
deps = [
|
||||
":sommelier-protocol",
|
||||
]
|
||||
sources = [
|
||||
"sommelier-compositor.c",
|
||||
"sommelier-data-device-manager.c",
|
||||
"sommelier-display.c",
|
||||
"sommelier-drm.c",
|
||||
"sommelier-gtk-shell.c",
|
||||
"sommelier-output.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",
|
||||
]
|
||||
defines = [
|
||||
"_GNU_SOURCE",
|
||||
"WL_HIDE_DEPRECATED",
|
||||
"XWAYLAND_PATH=${xwayland_path}",
|
||||
"XWAYLAND_GL_DRIVER_PATH=${xwayland_gl_driver_path}",
|
||||
"XWAYLAND_SHM_DRIVER=${xwayland_shm_driver}",
|
||||
"SHM_DRIVER=${shm_driver}",
|
||||
"VIRTWL_DEVICE=${virtwl_device}",
|
||||
"PEER_CMD_PREFIX=${peer_cmd_prefix}",
|
||||
"FRAME_COLOR=${frame_color}",
|
||||
"DARK_FRAME_COLOR=${dark_frame_color}",
|
||||
]
|
||||
}
|
||||
|
||||
executable("wayland_demo") {
|
||||
pkg_deps = [
|
||||
"libbrillo-${libbase_ver}",
|
||||
"libchrome-${libbase_ver}",
|
||||
"wayland-client",
|
||||
]
|
||||
libs = [ "wayland-client" ]
|
||||
sources = [
|
||||
"demos/wayland_demo.cc",
|
||||
]
|
||||
}
|
||||
|
||||
executable("x11_demo") {
|
||||
pkg_deps = [
|
||||
"libbrillo-${libbase_ver}",
|
||||
"libchrome-${libbase_ver}",
|
||||
]
|
||||
libs = [ "X11" ]
|
||||
sources = [
|
||||
"demos/x11_demo.cc",
|
||||
]
|
||||
}
|
129
sommelier/Makefile
Normal file
129
sommelier/Makefile
Normal file
@ -0,0 +1,129 @@
|
||||
CC=gcc
|
||||
SED=sed
|
||||
CLANG_FORMAT=clang-format-3.9
|
||||
CLANG_TIDY=clang-tidy-3.9
|
||||
PREFIX = /usr
|
||||
SYSCONFDIR = /etc
|
||||
BINDIR = $(PREFIX)/bin
|
||||
SRCFILES := sommelier.c version.h
|
||||
XMLFILES := protocol/aura-shell.xml protocol/viewporter.xml protocol/xdg-shell-unstable-v6.xml protocol/linux-dmabuf-unstable-v1.xml protocol/drm.xml protocol/keyboard-extension-unstable-v1.xml protocol/gtk-shell.xml protocol/relative-pointer-unstable-v1.xml protocol/text-input-unstable-v1.xml
|
||||
AUXFILES := Makefile README LICENSE AUTHORS sommelier@.service.in sommelier-x@.service.in sommelierrc sommelier.sh
|
||||
ALLFILES := $(SRCFILES) $(XMLFILES) $(AUXFILES)
|
||||
#GIT_VERSION := $(shell git describe --abbrev=4 --dirty --always --tags)
|
||||
#DIST_VERSION := $(shell git describe --abbrev=0 --tags)
|
||||
DIST_VERSION_BITS := $(subst ., ,$(DIST_VERSION))
|
||||
DIST_VERSION_MAJOR := $(word 1,$(DIST_VERSION_BITS))
|
||||
DIST_VERSION_MINOR := $(word 2,$(DIST_VERSION_BITS))
|
||||
DIST_VERSION_MINOR_NEXT := $(shell expr $(DIST_VERSION_MINOR) + 1)
|
||||
CFLAGS=-g -Wall `pkg-config --cflags libdrm xcb xcb-composite xcb-xfixes wayland-server wayland-client gbm pixman-1` -I. -D_GNU_SOURCE=1 -DWL_HIDE_DEPRECATED=1 -DXWAYLAND_PATH=\"$(PREFIX)/bin/Xwayland\"
|
||||
LDFLAGS=-lpthread -lm `pkg-config --libs libdrm xcb xcb-composite xcb-xfixes wayland-server wayland-client gbm pixman-1 xkbcommon`
|
||||
DEPS = xdg-shell-unstable-v6-client-protocol.h xdg-shell-unstable-v6-server-protocol.h aura-shell-client-protocol.h viewporter-client-protocol.h viewporter-server-protocol.h linux-dmabuf-unstable-v1-client-protocol.h drm-server-protocol.h keyboard-extension-unstable-v1-client-protocol.h gtk-shell-server-protocol.h relative-pointer-unstable-v1-server-protocol.h relative-pointer-unstable-v1-client-protocol.h text-input-unstable-v1-client-protocol.h text-input-unstable-v1-server-protocol.h
|
||||
OBJECTS = sommelier.o sommelier-compositor.o sommelier-data-device-manager.o sommelier-display.o sommelier-drm.o sommelier-gtk-shell.o sommelier-output.o sommelier-relative-pointer-manager.o sommelier-seat.o sommelier-shell.o sommelier-shm.o sommelier-subcompositor.o sommelier-text-input.o sommelier-viewporter.o sommelier-xdg-shell.o xdg-shell-unstable-v6-protocol.o aura-shell-protocol.o viewporter-protocol.o linux-dmabuf-unstable-v1-protocol.o drm-protocol.o keyboard-extension-unstable-v1-protocol.o gtk-shell-protocol.o relative-pointer-unstable-v1-protocol.o text-input-unstable-v1-protocol.o
|
||||
|
||||
#all: sommelier sommelier@.service sommelier-x@.service
|
||||
all: sommelier
|
||||
|
||||
%.service: %.service.in
|
||||
$(SED) \
|
||||
-e 's|@bindir[@]|$(BINDIR)|g' \
|
||||
-e 's|@sysconfdir[@]|$(SYSCONFDIR)|g' \
|
||||
-e 's|@version[@]|$(DIST_VERSION)|g' \
|
||||
$< > $@
|
||||
|
||||
sommelier: $(OBJECTS)
|
||||
$(CC) $(OBJECTS) -o sommelier $(LDFLAGS)
|
||||
strip -s sommelier
|
||||
|
||||
%-protocol.c: protocol/%.xml
|
||||
wayland-scanner private-code < $< > $@
|
||||
|
||||
%-client-protocol.h: protocol/%.xml
|
||||
wayland-scanner client-header < $< > $@
|
||||
|
||||
%-server-protocol.h: protocol/%.xml
|
||||
wayland-scanner server-header < $< > $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
$(OBJECTS): $(DEPS)
|
||||
|
||||
.PHONY: all install uninstall update-version dist deb version-clean clean style check-style tidy
|
||||
|
||||
install: all
|
||||
install -D sommelier \
|
||||
$(DESTDIR)$(PREFIX)/bin/sommelier
|
||||
install -D sommelierrc $(DESTDIR)$(SYSCONFDIR)/sommelierrc
|
||||
install -m 644 -D sommelier@.service \
|
||||
$(DESTDIR)$(PREFIX)/lib/systemd/user/sommelier@.service
|
||||
install -m 644 -D sommelier-x@.service \
|
||||
$(DESTDIR)$(PREFIX)/lib/systemd/user/sommelier-x@.service
|
||||
install -m 644 -D sommelier.sh $(DESTDIR)$(SYSCONFDIR)/profile.d/sommelier.sh
|
||||
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(PREFIX)/bin/sommelier
|
||||
rm -f $(DESTDIR)$(SYSCONFDIR)/sommelierrc
|
||||
rm -f $(DESTDIR)$(PREFIX)/lib/systemd/user/sommelier@.service
|
||||
rm -f $(DESTDIR)$(PREFIX)/lib/systemd/user/sommelier-x@.service
|
||||
rm -f $(DESTDIR)$(SYSCONFDIR)/profile.d/sommelier.sh
|
||||
|
||||
update-version:
|
||||
dch -v $(DIST_VERSION_MAJOR).$(DIST_VERSION_MINOR_NEXT)-1
|
||||
git commit -m 'debian/changelog: bump to version $(DIST_VERSION_MAJOR).$(DIST_VERSION_MINOR_NEXT)' debian/changelog
|
||||
$(SED) -i -e 's/VERSION "[0-9.]*"/VERSION "$(DIST_VERSION_MAJOR).$(DIST_VERSION_MINOR_NEXT)"/g' version.h
|
||||
git tag $(DIST_VERSION_MAJOR).$(DIST_VERSION_MINOR_NEXT)
|
||||
|
||||
dist: $(DEPS)
|
||||
mkdir -p sommelier-$(DIST_VERSION)
|
||||
cp -r $(ALLFILES) $(DEPS) debian sommelier-$(DIST_VERSION)
|
||||
tar czf sommelier-$(DIST_VERSION).tar.gz sommelier-$(DIST_VERSION)
|
||||
rm -rf sommelier-$(DIST_VERSION)
|
||||
|
||||
deb: dist
|
||||
ln -sf sommelier-$(DIST_VERSION).tar.gz sommelier_$(DIST_VERSION).orig.tar.gz
|
||||
tar xzf sommelier-$(DIST_VERSION).tar.gz
|
||||
cd sommelier-$(DIST_VERSION) && debuild -i -us -uc -b
|
||||
rm -rf sommelier-$(DIST_VERSION) sommelier_$(DIST_VERSION).orig.tar.gz
|
||||
|
||||
clean:
|
||||
rm -f *~ *-protocol.c *-protocol.h *.o sommelier sommelier@.service \
|
||||
sommelier-x@.service sommelier-*.tar.gz sommelier*.deb \
|
||||
sommelier_*.build sommelier_*.buildinfo sommelier_*.changes
|
||||
|
||||
style: $(DEPS)
|
||||
@for src in $(SRCFILES) ; do \
|
||||
echo "Formatting $$src..."; \
|
||||
$(CLANG_FORMAT) -i "$$src"; \
|
||||
$(CLANG_TIDY) -checks='-*,readability-identifier-naming' \
|
||||
-config="{CheckOptions: [ \
|
||||
{ key: readability-identifier-naming.StructCase, value: lower_case }, \
|
||||
{ key: readability-identifier-naming.FunctionCase, value: lower_case }, \
|
||||
{ key: readability-identifier-naming.VariableCase, value: lower_case }, \
|
||||
{ key: readability-identifier-naming.GlobalConstantCase, value: lower_case }, \
|
||||
{ key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE } \
|
||||
]}" "$$src"; \
|
||||
done
|
||||
@echo "Done"
|
||||
|
||||
check-style:
|
||||
@for src in $(SRCFILES) ; do \
|
||||
var=`$(CLANG_FORMAT) "$$src" | diff "$$src" - | wc -l`; \
|
||||
if [ $$var -ne 0 ] ; then \
|
||||
echo "$$src does not respect the coding style (diff: $$var lines)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@echo "Style check passed"
|
||||
|
||||
tidy: $(DEPS)
|
||||
@for src in $(SRCFILES); do \
|
||||
echo "Running tidy on $$src..."; \
|
||||
$(CLANG_TIDY) -checks="-*,modernize-use-auto,modernize-use-nullptr, \
|
||||
readability-else-after-return,readability-simplify-boolean-expr, \
|
||||
readability-redundant-member-init,modernize-use-default-member-init, \
|
||||
modernize-use-equals-default,modernize-use-equals-delete, \
|
||||
modernize-use-using,modernize-loop-convert, \
|
||||
cppcoreguidelines-no-malloc,misc-redundant-expression" \
|
||||
"$$src"; \
|
||||
done
|
||||
@echo "Done"
|
5
sommelier/OWNERS
Normal file
5
sommelier/OWNERS
Normal file
@ -0,0 +1,5 @@
|
||||
set noparent
|
||||
reveman@chromium.org
|
||||
hollingum@google.com
|
||||
sidereal@google.com
|
||||
davidriley@chromium.org
|
247
sommelier/README.md
Normal file
247
sommelier/README.md
Normal file
@ -0,0 +1,247 @@
|
||||
# Sommelier - Nested Wayland compositor with support for X11 forwarding
|
||||
|
||||
Sommelier is an implementation of a Wayland compositor that delegates
|
||||
compositing to a 'host' compositor. Sommelier includes a set of features that
|
||||
allows it to run inside a tight jail or virtual machine.
|
||||
|
||||
Sommelier can run as service or as a wrapper around the execution of a
|
||||
program. As a service, it spawns new processes as needed to service clients.
|
||||
The parent process is called the master sommelier.
|
||||
|
||||
## Sommeliers
|
||||
|
||||
### Master Sommelier
|
||||
|
||||
The master sommelier instance will create a wayland socket in XDG_RUNTIME_DIR
|
||||
and accept connections from regular wayland clients. Each connection will be
|
||||
serviced by spawning a child sommelier process.
|
||||
|
||||
### X11 Sommelier
|
||||
|
||||
An X11 sommelier instance provides X11 forwarding. Xwayland is used to
|
||||
accomplish this. A single X11 sommelier instance is typically shared across
|
||||
all X11 clients as they often expect that they can use a shared X server for
|
||||
communication. If the X11 sommelier instance crashes in this setup, it takes
|
||||
all running X11 programs down with it. Multiple X11 sommelier instances
|
||||
can be used for improved isolation or when per-client configuration is
|
||||
needed, but it will be at the cost of losing the ability for programs to use
|
||||
the X server for communication between each other.
|
||||
|
||||
### Peer Sommelier
|
||||
|
||||
Each Linux program that support the Wayland protocol can have its own sommelier.
|
||||
This provides better use of multiple cores when servicing clients, and it
|
||||
prevents errors in one client from causing other clients to crash.
|
||||
|
||||
## Host Compositor Channel
|
||||
|
||||
Sommelier needs a channel to the host compositor in order to serve Wayland
|
||||
clients inside a container. If the container environment provides a socket
|
||||
that can be used to establish a connection to the host compositor, then
|
||||
pointing sommelier to this socket using the `--display=DISPLAY` flag is
|
||||
sufficient.
|
||||
|
||||
### VirtWL
|
||||
|
||||
The VirtWL device can be used to establish a new connection when no socket
|
||||
is available (typically when running inside a VM). If a VirtWL device has been
|
||||
specified (e.g. `--virtwl-device=/dev/wl0`) then sommelier will use this
|
||||
mechanism by default to establish new channels between the host compositor and
|
||||
sommelier instances. Data is forwarded between the VirtWL device and the core
|
||||
Wayland dispatch mechanism using non-blocking I/O multiplexing.
|
||||
|
||||
## Shared Memory Drivers
|
||||
|
||||
Shared memory allocated inside a container cannot always be shared with the
|
||||
host compositor. Sommelier provides a shared memory driver option as a
|
||||
solution for this. What's the most appropriate option depends on the host
|
||||
compositor and device drivers available for allocating buffers.
|
||||
|
||||
### Noop
|
||||
|
||||
The `noop` shared memory driver simply forwards buffers to the host without
|
||||
any special processing. This requires that the client inside the container is
|
||||
using memory that can be shared with the host compositor.
|
||||
|
||||
### VirtWL
|
||||
|
||||
The `virtwl` driver creates a set of intermediate virtwl buffers for each
|
||||
surface, and copies minimal damaged areas from the client’s standard shared
|
||||
memory buffers into the virtwl buffers that can be shared with the host
|
||||
compositor.
|
||||
|
||||
### VirtWL-DMABuf
|
||||
|
||||
The `virtwl-dmabuf` works the same way as the `virtwl` driver but allocates
|
||||
buffers that can be shared with the host compositor using the linux_dmabuf
|
||||
protocol. The benefits of using this driver over the basic `virtwl` driver
|
||||
are:
|
||||
|
||||
* Larger set of supported formats (E.g NV12).
|
||||
* Host compositor can avoid expensive texture uploads.
|
||||
* HW overlays can be used for presentation if support by the host compositor.
|
||||
|
||||
### DMABuf
|
||||
|
||||
The `dmabuf` driver is similar to the `virtwl-dmabuf` driver. It creates a set
|
||||
of intermediate buffers for each surface and copies minimal damaged areas from
|
||||
the client’s standard shared memory buffer into the DMABuf buffer. However,
|
||||
the buffer is allocated using a DRM device and a prime FD is used to access
|
||||
buffer memory inside the container. Intermediate buffers are shared with the
|
||||
host compositor using the linux_dmabuf protocol.
|
||||
|
||||
## Damage Tracking
|
||||
|
||||
Shared memory drivers that use intermediate buffers require some form of
|
||||
damage tracking in order to update intermediate buffers.
|
||||
|
||||
### Surface Buffer Queue
|
||||
|
||||
Each client surface in sommelier is associated with a buffer queue. Each
|
||||
buffer in the buffer queue has a region (list of rectangles) that describes
|
||||
the part of the buffer that is damaged compared to the last frame submitted
|
||||
by the client. This provides high precision damage tracking across multiple
|
||||
frames. Each new frame from the client adds damage to existing buffers. When
|
||||
submitting a frame to the host compositor, the next available buffer is
|
||||
dequeued and updated to not contain any damage. This is done by copying
|
||||
contents from the current client buffer into the dequeued buffer.
|
||||
|
||||
The client's buffer is released as soon as this copy operation described above
|
||||
is complete and the client can then reuse the shared memory buffer for another
|
||||
frame.
|
||||
|
||||
Note: It is important to release the buffer immediately as clients don’t
|
||||
expect it to be held by the compositor for long when using shared memory.
|
||||
|
||||
### Back Pressure
|
||||
|
||||
Sommelier doesn’t provide any back pressure for when the client is producing
|
||||
contents faster than the host compositor can consume it. The size of the
|
||||
buffer queue can as a result grow large. This is not a problem as Xwayland
|
||||
and other clients handle back pressure themselves using Wayland frame
|
||||
callbacks or similar mechanism.
|
||||
|
||||
## Data Drivers
|
||||
|
||||
Socket pairs created inside a container cannot always be shared with the
|
||||
host compositor. Sommelier provides a data driver option as a solution
|
||||
for this.
|
||||
|
||||
### Noop
|
||||
|
||||
The `noop` driver simply forwards socket pair FDs to the host without any
|
||||
special processing. This requires that the client inside the container is
|
||||
using socket pairs that can be shared with the host compositor.
|
||||
|
||||
### VirtWL
|
||||
|
||||
The `virtwl` driver creates a special pipe that can be shared with the host
|
||||
compositor and forwards all data received over this pipe to the client FD.
|
||||
Forwarding is done using non-blocking I/O multiplexing.
|
||||
|
||||
## Flags and Settings
|
||||
|
||||
Sommelier has two forms of configuration. Command line flags and environment
|
||||
variables. Standard practice is to expose each option both as a command line
|
||||
flag and as an environment variable. Command line flags will always override
|
||||
the configuration provided by environment variables. This makes it easy to
|
||||
run sommelier as a systemd service and allow the system-wide configuration
|
||||
to be overridden using a local user provided systemd override file.
|
||||
|
||||
## Density and Scaling
|
||||
|
||||
A protocol aware proxy compositor between the client and the host compositor
|
||||
makes it easier to support Linux programs that lack good HiDPI support.
|
||||
It can also be used to adjust the scale of contents to support the dynamic
|
||||
density changes that Chrome OS UI provide, and it gives the user an option
|
||||
override any density decisions made by the host compositor. For example,
|
||||
HiDPI aware programs can run at native display resolution, while some older
|
||||
programs can use half of that resolution.
|
||||
|
||||
### Contents Scaling
|
||||
|
||||
Contents scaling can be applied to both native wayland clients and X11
|
||||
clients. It can be controlled using the `--scale=SCALE` flag or
|
||||
`SOMMELIER_SCALE=SCALE` variable. Where `SCALE` is a display density
|
||||
multiplier. For example, if the default density is 200 DPI, then using
|
||||
`--scale=0.5` will result in contents produced for 100 DPI.
|
||||
|
||||
### Scale Factor
|
||||
|
||||
An optimal scale factor is calculated for Wayland clients based on contents
|
||||
scale setting and the current host compositor scaling. This allows Wayland
|
||||
clients to produce contents at an optimal resolution for all combinations of
|
||||
scaling used by sommelier and the host compositor.
|
||||
|
||||
### DPI
|
||||
|
||||
An exact value for DPI is calculated by sommelier. However, many Linux
|
||||
programs expect DPI to be one out of a well known set of values. Sommelier
|
||||
solves this by adjusting DPI using a set of buckets. For example, given the
|
||||
default set of buckets (72, 96, 160, 240), Sommelier will use 96 as DPI when
|
||||
the exact value is 112, or 160 when exact value is 188. The DPI buckets that
|
||||
sommelier should use can be specified with `--dpi=[DPI[,DPI...]]`. Where,
|
||||
`--dpi=””` will result in sommelier exposing the exact DPI value to clients.
|
||||
|
||||
### XCursor
|
||||
|
||||
Sommelier will set `XCURSOR_SIZE` environment variable automatically based on
|
||||
the contents scale and preferred host compositor scale factor.
|
||||
|
||||
## Accelerators
|
||||
|
||||
If the host compositor support dynamic handling of keyboard events, then
|
||||
keyboard shortcuts are forwarded to the Linux program by default. A small set
|
||||
of shortcuts are expected to be reserved by the host compositor. A list of
|
||||
reserved shortcuts on Chrome OS can be found
|
||||
[here](https://chromium.googlesource.com/chromium/src/+/master/ash/accelerators/accelerator_table.h#22).
|
||||
|
||||
There’s unfortunately no reliable way to detect if a Linux program handled a
|
||||
key event or not. This means that all non-reserved shortcuts that the user
|
||||
want the host compositor to handle needs to be explicitly listed as an
|
||||
accelerator. For example, on Chrome OS, the launcher can be brought up using
|
||||
the "launcher" button during normal usage. The "launcher" button event is
|
||||
forwarded to Linux programs by default so it won’t work when a Linux program
|
||||
has keyboard focus unless this shortcut is explicitly listed as an accelerator.
|
||||
|
||||
Sommelier provides the `--accelerator=ACCELERATORS` flag for this purpose.
|
||||
`ACCELERATORS` is a comma separated list of accelerators that shouldn’t be
|
||||
forwarded to the Linux program but instead handled by the host compositor.
|
||||
Each accelerator can contain a list of modifiers (e.g. `<Control><Alt>`) and
|
||||
must be followed by an XKB keysym. The `xev` utility can be used to determine
|
||||
what the XKB keysym is for a specific key. Given the launcher button example
|
||||
above (which happens to have XKB keysym `Super_L` on the Chromebook Pixel),
|
||||
`--accelerators=Super_L` needs to be passed to sommelier for the this button to
|
||||
bring up the application launcher when Linux programs have keyboard focus.
|
||||
|
||||
Consistent with other flags, `SOMMELIER_ACCELERATORS` environment variable can
|
||||
be used as an alternative to the command line flag.
|
||||
|
||||
## Examples
|
||||
|
||||
Start master sommelier and use wayland-1 as name of socket to listen on:
|
||||
|
||||
```
|
||||
sommelier --master --socket=wayland-1
|
||||
```
|
||||
|
||||
Start sommelier that runs weston-terminal with density scale multiplier 1.5:
|
||||
|
||||
```
|
||||
sommelier --scale=1.5 weston-terminal
|
||||
```
|
||||
|
||||
Start sommelier that runs inkscape with density scale multiplier 0.75 and 120
|
||||
dots per inch (note that -X is specified as inkscape is an X11 client and
|
||||
requires X11 forwarding):
|
||||
|
||||
```
|
||||
sommelier -X --scale=0.75 --dpi=120 inkscape
|
||||
```
|
||||
|
||||
Start sommelier that runs gedit with some accelerators reserved to the host
|
||||
compositor instead of being sent to gedit:
|
||||
|
||||
```
|
||||
sommelier --accelerators="<Alt>Bracketright,<Alt>Bracketleft" gedit
|
||||
```
|
8
sommelier/build/args.gn
Normal file
8
sommelier/build/args.gn
Normal file
@ -0,0 +1,8 @@
|
||||
# Set build arguments here. See `gn buildargs`.
|
||||
pkg_config = "/usr/bin/pkg-config"
|
||||
libdir = "/usr/lib/x86_64-linux-gnu/"
|
||||
platform_subdir="vm_tools/sommelier"
|
||||
cxx="g++"
|
||||
cc="gcc"
|
||||
ar="/usr/bin/ar"
|
||||
#use.amd64=true
|
16
sommelier/config.h
Normal file
16
sommelier/config.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
/*
|
||||
#ifndef XWAYLAND_PATH
|
||||
#define XWAYLAND_PATH "/usr/bin/Xwayland"
|
||||
#endif
|
||||
*/
|
||||
#define XWAYLAND_GL_DRIVER_PATH "/lib/x86_64-linux-gnu/dri"
|
||||
#define XWAYLAND_SHM_DRIVER "virtwl"
|
||||
#define SHM_DRIVER "virtwl"
|
||||
#define VIRTWL_DEVICE "/dev/wl0"
|
||||
#define PEER_CMD_PREFIX ""
|
||||
#define FRAME_COLOR "#f2f2f2"
|
||||
#define DARK_FRAME_COLOR "#323639"
|
||||
#endif
|
319
sommelier/demos/wayland_demo.cc
Normal file
319
sommelier/demos/wayland_demo.cc
Normal file
@ -0,0 +1,319 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/shared_memory.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "brillo/syslog_logging.h"
|
||||
|
||||
constexpr char kBgColorFlag[] = "bgcolor";
|
||||
constexpr char kWidthFlag[] = "width";
|
||||
constexpr char kHeightFlag[] = "height";
|
||||
constexpr char kTitleFlag[] = "title";
|
||||
|
||||
struct demo_data {
|
||||
uint32_t bgcolor;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
std::string title;
|
||||
int scale;
|
||||
struct wl_compositor* compositor;
|
||||
struct wl_shell* shell;
|
||||
struct wl_shm* shm;
|
||||
struct wl_surface* surface;
|
||||
struct wl_shell_surface* shell_surface;
|
||||
struct wl_buffer* buffer;
|
||||
struct wl_callback* callback;
|
||||
struct wl_callback_listener* callback_listener;
|
||||
struct wl_output* output;
|
||||
struct wl_output_listener* output_listener;
|
||||
struct wl_keyboard_listener* keyboard_listener;
|
||||
void* shm_ptr;
|
||||
bool done;
|
||||
};
|
||||
|
||||
void keyboard_keymap(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t format,
|
||||
int32_t fd,
|
||||
uint32_t size) {}
|
||||
|
||||
void keyboard_enter(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface,
|
||||
struct wl_array* keys) {}
|
||||
|
||||
void keyboard_leave(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface) {}
|
||||
|
||||
void keyboard_key(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t key,
|
||||
uint32_t state) {
|
||||
struct demo_data* data_ptr = reinterpret_cast<struct demo_data*>(data);
|
||||
// Key pressed.
|
||||
if (state == 1) {
|
||||
LOG(INFO) << "wayland_demo application detected keypress";
|
||||
data_ptr->done = true;
|
||||
}
|
||||
}
|
||||
|
||||
void keyboard_modifiers(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
uint32_t mods_depressed,
|
||||
uint32_t mods_latched,
|
||||
uint32_t mods_locked,
|
||||
uint32_t group) {}
|
||||
|
||||
void keyboard_repeat_info(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
int32_t rate,
|
||||
int32_t delay) {}
|
||||
|
||||
void demo_registry_listener(void* data,
|
||||
struct wl_registry* registry,
|
||||
uint32_t id,
|
||||
const char* interface,
|
||||
uint32_t version) {
|
||||
struct demo_data* data_ptr = reinterpret_cast<struct demo_data*>(data);
|
||||
if (!strcmp("wl_compositor", interface)) {
|
||||
data_ptr->compositor = reinterpret_cast<struct wl_compositor*>(
|
||||
wl_registry_bind(registry, id, &wl_compositor_interface, version));
|
||||
} else if (!strcmp("wl_shell", interface)) {
|
||||
data_ptr->shell = reinterpret_cast<struct wl_shell*>(
|
||||
wl_registry_bind(registry, id, &wl_shell_interface, version));
|
||||
} else if (!strcmp("wl_shm", interface)) {
|
||||
data_ptr->shm = reinterpret_cast<struct wl_shm*>(
|
||||
wl_registry_bind(registry, id, &wl_shm_interface, version));
|
||||
} else if (!strcmp("wl_output", interface)) {
|
||||
data_ptr->output = reinterpret_cast<struct wl_output*>(
|
||||
wl_registry_bind(registry, id, &wl_output_interface, version));
|
||||
wl_output_add_listener(data_ptr->output, data_ptr->output_listener,
|
||||
data_ptr);
|
||||
} else if (!strcmp("wl_seat", interface)) {
|
||||
struct wl_seat* seat = reinterpret_cast<struct wl_seat*>(
|
||||
wl_registry_bind(registry, id, &wl_seat_interface, version));
|
||||
wl_keyboard_add_listener(wl_seat_get_keyboard(seat),
|
||||
data_ptr->keyboard_listener, data_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void demo_registry_remover(void* data,
|
||||
struct wl_registry* registry,
|
||||
uint32_t id) {}
|
||||
|
||||
void shell_surface_ping(void* data,
|
||||
struct wl_shell_surface* shell_surface,
|
||||
uint32_t serial) {
|
||||
wl_shell_surface_pong(shell_surface, serial);
|
||||
}
|
||||
|
||||
void shell_surface_configure(void* data,
|
||||
struct wl_shell_surface* shell_surface,
|
||||
uint32_t edges,
|
||||
int32_t width,
|
||||
int32_t height) {}
|
||||
|
||||
void shell_surface_popup_done(void* data,
|
||||
struct wl_shell_surface* shell_surface) {}
|
||||
|
||||
void demo_draw(void* data, struct wl_callback* callback, uint32_t time) {
|
||||
struct demo_data* data_ptr = reinterpret_cast<struct demo_data*>(data);
|
||||
wl_callback_destroy(data_ptr->callback);
|
||||
wl_surface_damage(data_ptr->surface, 0, 0, data_ptr->width, data_ptr->height);
|
||||
uint32_t* surface_data = reinterpret_cast<uint32_t*>(data_ptr->shm_ptr);
|
||||
for (int i = 0; i < data_ptr->width * data_ptr->height; ++i) {
|
||||
surface_data[i] = data_ptr->bgcolor;
|
||||
}
|
||||
data_ptr->callback = wl_surface_frame(data_ptr->surface);
|
||||
wl_surface_attach(data_ptr->surface, data_ptr->buffer, 0, 0);
|
||||
wl_callback_add_listener(data_ptr->callback, data_ptr->callback_listener,
|
||||
data_ptr);
|
||||
wl_surface_commit(data_ptr->surface);
|
||||
}
|
||||
|
||||
void output_geometry(void* data,
|
||||
struct wl_output* output,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t physical_width,
|
||||
int32_t physical_height,
|
||||
int32_t subpixel,
|
||||
const char* make,
|
||||
const char* model,
|
||||
int32_t transform) {}
|
||||
|
||||
void output_mode(void* data,
|
||||
struct wl_output* output,
|
||||
uint32_t flags,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
int32_t refresh) {
|
||||
struct demo_data* data_ptr = reinterpret_cast<struct demo_data*>(data);
|
||||
if (data_ptr->width == 0) {
|
||||
data_ptr->width = width;
|
||||
if (data_ptr->scale != 0) {
|
||||
data_ptr->width /= data_ptr->scale;
|
||||
}
|
||||
}
|
||||
if (data_ptr->height == 0) {
|
||||
data_ptr->height = height;
|
||||
if (data_ptr->scale != 0) {
|
||||
data_ptr->height /= data_ptr->scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void output_done(void* data, struct wl_output* output) {}
|
||||
|
||||
void output_scale(void* data, struct wl_output* output, int32_t factor) {
|
||||
struct demo_data* data_ptr = reinterpret_cast<struct demo_data*>(data);
|
||||
data_ptr->scale = factor;
|
||||
if (data_ptr->width != 0) {
|
||||
data_ptr->width /= factor;
|
||||
}
|
||||
if (data_ptr->height != 0) {
|
||||
data_ptr->height /= factor;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
brillo::InitLog(brillo::kLogToSyslog);
|
||||
LOG(INFO) << "Starting wayland_demo application";
|
||||
|
||||
base::CommandLine::Init(argc, argv);
|
||||
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
|
||||
struct demo_data data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.done = false;
|
||||
|
||||
data.bgcolor = 0x3388DD;
|
||||
if (cl->HasSwitch(kBgColorFlag)) {
|
||||
data.bgcolor =
|
||||
strtoul(cl->GetSwitchValueASCII(kBgColorFlag).c_str(), nullptr, 0);
|
||||
}
|
||||
if (cl->HasSwitch(kWidthFlag)) {
|
||||
if (!base::StringToUint(cl->GetSwitchValueASCII(kWidthFlag), &data.width)) {
|
||||
LOG(ERROR) << "Invalid width parameter passed";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (cl->HasSwitch(kHeightFlag)) {
|
||||
if (!base::StringToUint(cl->GetSwitchValueASCII(kHeightFlag),
|
||||
&data.height)) {
|
||||
LOG(ERROR) << "Invalid height parameter passed";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
data.title = "wayland_demo";
|
||||
if (cl->HasSwitch(kTitleFlag)) {
|
||||
data.title = cl->GetSwitchValueASCII(kTitleFlag);
|
||||
}
|
||||
|
||||
struct wl_display* display = wl_display_connect(nullptr);
|
||||
if (!display) {
|
||||
LOG(ERROR) << "Failed connecting to display";
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct wl_output_listener output_listener = {output_geometry, output_mode,
|
||||
output_done, output_scale};
|
||||
data.output_listener = &output_listener;
|
||||
struct wl_registry_listener registry_listener = {
|
||||
demo_registry_listener, demo_registry_remover,
|
||||
};
|
||||
struct wl_keyboard_listener keyboard_listener = {
|
||||
keyboard_keymap, keyboard_enter, keyboard_leave,
|
||||
keyboard_key, keyboard_modifiers, keyboard_repeat_info};
|
||||
data.keyboard_listener = &keyboard_listener;
|
||||
|
||||
struct wl_registry* registry = wl_display_get_registry(display);
|
||||
wl_registry_add_listener(registry, ®istry_listener, &data);
|
||||
|
||||
wl_display_dispatch(display);
|
||||
wl_display_roundtrip(display);
|
||||
|
||||
if (!data.compositor) {
|
||||
LOG(ERROR) << "Failed to find compositor";
|
||||
return -1;
|
||||
}
|
||||
if (!data.output) {
|
||||
LOG(ERROR) << "Failed to get output";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Do another roundtrip to ensure we get the wl_output callbacks.
|
||||
wl_display_roundtrip(display);
|
||||
|
||||
data.surface = wl_compositor_create_surface(data.compositor);
|
||||
if (!data.surface) {
|
||||
LOG(ERROR) << "Failed creating surface";
|
||||
return -1;
|
||||
}
|
||||
if (!data.shell) {
|
||||
LOG(ERROR) << "Failed getting shell";
|
||||
return -1;
|
||||
}
|
||||
|
||||
data.shell_surface = wl_shell_get_shell_surface(data.shell, data.surface);
|
||||
if (!data.shell_surface) {
|
||||
LOG(ERROR) << "Failed getting shell surface";
|
||||
return -1;
|
||||
}
|
||||
const struct wl_shell_surface_listener shell_surface_listener = {
|
||||
shell_surface_ping, shell_surface_configure, shell_surface_popup_done};
|
||||
wl_shell_surface_add_listener(data.shell_surface, &shell_surface_listener,
|
||||
nullptr);
|
||||
|
||||
wl_shell_surface_set_toplevel(data.shell_surface);
|
||||
wl_shell_surface_set_class(data.shell_surface, data.title.c_str());
|
||||
wl_shell_surface_set_title(data.shell_surface, data.title.c_str());
|
||||
data.callback = wl_surface_frame(data.surface);
|
||||
struct wl_callback_listener callback_listener = {demo_draw};
|
||||
data.callback_listener = &callback_listener;
|
||||
wl_callback_add_listener(data.callback, data.callback_listener, &data);
|
||||
|
||||
if (!data.shm) {
|
||||
LOG(ERROR) << "Failed getting shared memory";
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t stride = data.width * 4 /* 32bpp */;
|
||||
size_t shm_size = stride * data.height;
|
||||
base::SharedMemory shared_mem;
|
||||
shared_mem.CreateAndMapAnonymous(shm_size);
|
||||
data.shm_ptr = shared_mem.memory();
|
||||
|
||||
struct wl_shm_pool* pool =
|
||||
wl_shm_create_pool(data.shm, shared_mem.handle().fd, shm_size);
|
||||
data.buffer = wl_shm_pool_create_buffer(pool, 0, data.width, data.height,
|
||||
stride, WL_SHM_FORMAT_XRGB8888);
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
wl_surface_attach(data.surface, data.buffer, 0, 0);
|
||||
wl_surface_commit(data.surface);
|
||||
|
||||
demo_draw(&data, nullptr, 0);
|
||||
LOG(INFO) << "wayland_demo application displaying, waiting for keypress";
|
||||
do {
|
||||
} while (wl_display_dispatch(display) != -1 && !data.done);
|
||||
|
||||
wl_display_disconnect(display);
|
||||
LOG(INFO) << "wayland_demo application exiting";
|
||||
return 0;
|
||||
}
|
90
sommelier/demos/x11_demo.cc
Normal file
90
sommelier/demos/x11_demo.cc
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "brillo/syslog_logging.h"
|
||||
|
||||
constexpr char kBgColorFlag[] = "bgcolor";
|
||||
constexpr char kWidthFlag[] = "width";
|
||||
constexpr char kHeightFlag[] = "height";
|
||||
constexpr char kTitleFlag[] = "title";
|
||||
|
||||
// Creates an X window the same size as the display and fills its background
|
||||
// with a solid color that can be specified as the only parameter (in hex or
|
||||
// base 10). Closes on any keypress.
|
||||
int main(int argc, char* argv[]) {
|
||||
brillo::InitLog(brillo::kLogToSyslog);
|
||||
LOG(INFO) << "Starting x11_demo application";
|
||||
|
||||
base::CommandLine::Init(argc, argv);
|
||||
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
|
||||
uint32_t bgcolor = 0x99EE44;
|
||||
if (cl->HasSwitch(kBgColorFlag)) {
|
||||
bgcolor =
|
||||
strtoul(cl->GetSwitchValueASCII(kBgColorFlag).c_str(), nullptr, 0);
|
||||
}
|
||||
std::string title = "x11_demo";
|
||||
if (cl->HasSwitch(kTitleFlag)) {
|
||||
title = cl->GetSwitchValueASCII(kTitleFlag);
|
||||
}
|
||||
|
||||
Display* dpy = XOpenDisplay(nullptr);
|
||||
if (!dpy) {
|
||||
LOG(ERROR) << "Failed opening display";
|
||||
return -1;
|
||||
}
|
||||
|
||||
int screen = DefaultScreen(dpy);
|
||||
Window win;
|
||||
int x, y;
|
||||
unsigned int width, height, border, depth;
|
||||
if (XGetGeometry(dpy, RootWindow(dpy, screen), &win, &x, &y, &width, &height,
|
||||
&border, &depth) == 0) {
|
||||
LOG(ERROR) << "Failed getting screen geometry";
|
||||
return -1;
|
||||
}
|
||||
if (cl->HasSwitch(kWidthFlag)) {
|
||||
if (!base::StringToUint(cl->GetSwitchValueASCII(kWidthFlag), &width)) {
|
||||
LOG(ERROR) << "Invalid width parameter passed";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (cl->HasSwitch(kHeightFlag)) {
|
||||
if (!base::StringToUint(cl->GetSwitchValueASCII(kHeightFlag), &height)) {
|
||||
LOG(ERROR) << "Invalid height parameter passed";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), x, y, width, height,
|
||||
0, 0 /* black */, bgcolor);
|
||||
|
||||
XClassHint* wmclass_hint = XAllocClassHint();
|
||||
wmclass_hint->res_name = wmclass_hint->res_class = strdup(title.c_str());
|
||||
XSetClassHint(dpy, win, wmclass_hint);
|
||||
XSelectInput(dpy, win, KeyPressMask);
|
||||
XMapWindow(dpy, win);
|
||||
XStoreName(dpy, win, title.c_str());
|
||||
|
||||
LOG(INFO) << "x11_demo application displaying, waiting for keypress";
|
||||
XEvent evt;
|
||||
for (;;) {
|
||||
XNextEvent(dpy, &evt);
|
||||
if (evt.type == KeyPress) {
|
||||
LOG(INFO) << "x11_demo application detected keypress";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XCloseDisplay(dpy);
|
||||
LOG(INFO) << "x11_demo application exiting";
|
||||
return 0;
|
||||
}
|
135
sommelier/linux/virtio_wl.h
Normal file
135
sommelier/linux/virtio_wl.h
Normal file
@ -0,0 +1,135 @@
|
||||
#ifndef _LINUX_VIRTIO_WL_H
|
||||
#define _LINUX_VIRTIO_WL_H
|
||||
/*
|
||||
* This header is BSD licensed so anyone can use the definitions to implement
|
||||
* compatible drivers/servers.
|
||||
*/
|
||||
#include <linux/virtio_ids.h>
|
||||
#include <linux/virtio_config.h>
|
||||
#include <linux/virtwl.h>
|
||||
|
||||
#define VIRTWL_IN_BUFFER_SIZE 4096
|
||||
#define VIRTWL_OUT_BUFFER_SIZE 4096
|
||||
#define VIRTWL_VQ_IN 0
|
||||
#define VIRTWL_VQ_OUT 1
|
||||
#define VIRTWL_QUEUE_COUNT 2
|
||||
#define VIRTWL_MAX_ALLOC 0x800
|
||||
#define VIRTWL_PFN_SHIFT 12
|
||||
|
||||
/* Enables the transition to new flag semantics */
|
||||
#define VIRTIO_WL_F_TRANS_FLAGS 1
|
||||
|
||||
struct virtio_wl_config {
|
||||
};
|
||||
|
||||
/*
|
||||
* The structure of each of these is virtio_wl_ctrl_hdr or one of its subclasses
|
||||
* where noted.
|
||||
*/
|
||||
enum virtio_wl_ctrl_type {
|
||||
VIRTIO_WL_CMD_VFD_NEW = 0x100, /* virtio_wl_ctrl_vfd_new */
|
||||
VIRTIO_WL_CMD_VFD_CLOSE, /* virtio_wl_ctrl_vfd */
|
||||
VIRTIO_WL_CMD_VFD_SEND, /* virtio_wl_ctrl_vfd_send + data */
|
||||
VIRTIO_WL_CMD_VFD_RECV, /* virtio_wl_ctrl_vfd_recv + data */
|
||||
VIRTIO_WL_CMD_VFD_NEW_CTX, /* virtio_wl_ctrl_vfd_new */
|
||||
VIRTIO_WL_CMD_VFD_NEW_PIPE, /* virtio_wl_ctrl_vfd_new */
|
||||
VIRTIO_WL_CMD_VFD_HUP, /* virtio_wl_ctrl_vfd */
|
||||
VIRTIO_WL_CMD_VFD_NEW_DMABUF, /* virtio_wl_ctrl_vfd_new */
|
||||
VIRTIO_WL_CMD_VFD_DMABUF_SYNC, /* virtio_wl_ctrl_vfd_dmabuf_sync */
|
||||
VIRTIO_WL_CMD_VFD_SEND_FOREIGN_ID, /* virtio_wl_ctrl_vfd_send + data */
|
||||
|
||||
VIRTIO_WL_RESP_OK = 0x1000,
|
||||
VIRTIO_WL_RESP_VFD_NEW = 0x1001, /* virtio_wl_ctrl_vfd_new */
|
||||
VIRTIO_WL_RESP_VFD_NEW_DMABUF = 0x1002, /* virtio_wl_ctrl_vfd_new */
|
||||
|
||||
VIRTIO_WL_RESP_ERR = 0x1100,
|
||||
VIRTIO_WL_RESP_OUT_OF_MEMORY,
|
||||
VIRTIO_WL_RESP_INVALID_ID,
|
||||
VIRTIO_WL_RESP_INVALID_TYPE,
|
||||
VIRTIO_WL_RESP_INVALID_FLAGS,
|
||||
VIRTIO_WL_RESP_INVALID_CMD,
|
||||
};
|
||||
|
||||
struct virtio_wl_ctrl_hdr {
|
||||
__le32 type; /* one of virtio_wl_ctrl_type */
|
||||
__le32 flags; /* always 0 */
|
||||
};
|
||||
|
||||
enum virtio_wl_vfd_flags {
|
||||
VIRTIO_WL_VFD_WRITE = 0x1, /* intended to be written by guest */
|
||||
VIRTIO_WL_VFD_READ = 0x2, /* intended to be read by guest */
|
||||
};
|
||||
|
||||
struct virtio_wl_ctrl_vfd {
|
||||
struct virtio_wl_ctrl_hdr hdr;
|
||||
__le32 vfd_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* If this command is sent to the guest, it indicates that the VFD has been
|
||||
* created and the fields indicate the properties of the VFD being offered.
|
||||
*
|
||||
* If this command is sent to the host, it represents a request to create a VFD
|
||||
* of the given properties. The pfn field is ignored by the host.
|
||||
*/
|
||||
struct virtio_wl_ctrl_vfd_new {
|
||||
struct virtio_wl_ctrl_hdr hdr;
|
||||
__le32 vfd_id; /* MSB indicates device allocated vfd */
|
||||
__le32 flags; /* virtio_wl_vfd_flags */
|
||||
__le64 pfn; /* first guest physical page frame number if VFD_MAP */
|
||||
__le32 size; /* size in bytes if VIRTIO_WL_CMD_VFD_NEW* */
|
||||
/* buffer description if VIRTIO_WL_CMD_VFD_NEW_DMABUF */
|
||||
struct {
|
||||
__le32 width; /* width in pixels */
|
||||
__le32 height; /* height in pixels */
|
||||
__le32 format; /* fourcc format */
|
||||
__le32 stride0; /* return stride0 */
|
||||
__le32 stride1; /* return stride1 */
|
||||
__le32 stride2; /* return stride2 */
|
||||
__le32 offset0; /* return offset0 */
|
||||
__le32 offset1; /* return offset1 */
|
||||
__le32 offset2; /* return offset2 */
|
||||
} dmabuf;
|
||||
};
|
||||
|
||||
|
||||
enum virtio_wl_ctrl_vfd_send_kind {
|
||||
/* The id after this one indicates an ordinary vfd_id. */
|
||||
VIRTIO_WL_CTRL_VFD_SEND_KIND_LOCAL,
|
||||
/* The id after this one is a virtio-gpu resource id. */
|
||||
VIRTIO_WL_CTRL_VFD_SEND_KIND_VIRTGPU,
|
||||
};
|
||||
|
||||
struct virtio_wl_ctrl_vfd_send_vfd {
|
||||
__le32 kind; /* virtio_wl_ctrl_vfd_send_kind */
|
||||
__le32 id;
|
||||
};
|
||||
|
||||
struct virtio_wl_ctrl_vfd_send {
|
||||
struct virtio_wl_ctrl_hdr hdr;
|
||||
__le32 vfd_id;
|
||||
__le32 vfd_count; /* struct is followed by this many IDs */
|
||||
|
||||
/*
|
||||
* If hdr.type == VIRTIO_WL_CMD_VFD_SEND_FOREIGN_ID, there is a
|
||||
* vfd_count array of virtio_wl_ctrl_vfd_send_vfd. Otherwise, there is a
|
||||
* vfd_count array of vfd_ids.
|
||||
*/
|
||||
|
||||
/* the remainder is raw data */
|
||||
};
|
||||
|
||||
struct virtio_wl_ctrl_vfd_recv {
|
||||
struct virtio_wl_ctrl_hdr hdr;
|
||||
__le32 vfd_id;
|
||||
__le32 vfd_count; /* struct is followed by this many IDs */
|
||||
/* the remainder is raw data */
|
||||
};
|
||||
|
||||
struct virtio_wl_ctrl_vfd_dmabuf_sync {
|
||||
struct virtio_wl_ctrl_hdr hdr;
|
||||
__le32 vfd_id;
|
||||
__le32 flags;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_VIRTIO_WL_H */
|
64
sommelier/linux/virtwl.h
Normal file
64
sommelier/linux/virtwl.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef _LINUX_VIRTWL_H
|
||||
#define _LINUX_VIRTWL_H
|
||||
|
||||
#include <asm/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define VIRTWL_SEND_MAX_ALLOCS 28
|
||||
|
||||
#define VIRTWL_IOCTL_BASE 'w'
|
||||
#define VIRTWL_IO(nr) _IO(VIRTWL_IOCTL_BASE, nr)
|
||||
#define VIRTWL_IOR(nr, type) _IOR(VIRTWL_IOCTL_BASE, nr, type)
|
||||
#define VIRTWL_IOW(nr, type) _IOW(VIRTWL_IOCTL_BASE, nr, type)
|
||||
#define VIRTWL_IOWR(nr, type) _IOWR(VIRTWL_IOCTL_BASE, nr, type)
|
||||
|
||||
enum virtwl_ioctl_new_type {
|
||||
VIRTWL_IOCTL_NEW_CTX, /* open a new wayland connection context */
|
||||
VIRTWL_IOCTL_NEW_ALLOC, /* create a new virtwl shm allocation */
|
||||
/* create a new virtwl pipe that is readable via the returned fd */
|
||||
VIRTWL_IOCTL_NEW_PIPE_READ,
|
||||
/* create a new virtwl pipe that is writable via the returned fd */
|
||||
VIRTWL_IOCTL_NEW_PIPE_WRITE,
|
||||
/* create a new virtwl dmabuf that is writable via the returned fd */
|
||||
VIRTWL_IOCTL_NEW_DMABUF,
|
||||
};
|
||||
|
||||
struct virtwl_ioctl_new {
|
||||
__u32 type; /* VIRTWL_IOCTL_NEW_* */
|
||||
int fd; /* return fd */
|
||||
__u32 flags; /* currently always 0 */
|
||||
union {
|
||||
/* size of allocation if type == VIRTWL_IOCTL_NEW_ALLOC */
|
||||
__u32 size;
|
||||
/* buffer description if type == VIRTWL_IOCTL_NEW_DMABUF */
|
||||
struct {
|
||||
__u32 width; /* width in pixels */
|
||||
__u32 height; /* height in pixels */
|
||||
__u32 format; /* fourcc format */
|
||||
__u32 stride0; /* return stride0 */
|
||||
__u32 stride1; /* return stride1 */
|
||||
__u32 stride2; /* return stride2 */
|
||||
__u32 offset0; /* return offset0 */
|
||||
__u32 offset1; /* return offset1 */
|
||||
__u32 offset2; /* return offset2 */
|
||||
} dmabuf;
|
||||
};
|
||||
};
|
||||
|
||||
struct virtwl_ioctl_txn {
|
||||
int fds[VIRTWL_SEND_MAX_ALLOCS];
|
||||
__u32 len;
|
||||
__u8 data[0];
|
||||
};
|
||||
|
||||
struct virtwl_ioctl_dmabuf_sync {
|
||||
__u32 flags; /* synchronization flags (see dma-buf.h) */
|
||||
};
|
||||
|
||||
#define VIRTWL_IOCTL_NEW VIRTWL_IOWR(0x00, struct virtwl_ioctl_new)
|
||||
#define VIRTWL_IOCTL_SEND VIRTWL_IOR(0x01, struct virtwl_ioctl_txn)
|
||||
#define VIRTWL_IOCTL_RECV VIRTWL_IOW(0x02, struct virtwl_ioctl_txn)
|
||||
#define VIRTWL_IOCTL_DMABUF_SYNC VIRTWL_IOR(0x03, \
|
||||
struct virtwl_ioctl_dmabuf_sync)
|
||||
|
||||
#endif /* _LINUX_VIRTWL_H */
|
238
sommelier/protocol/aura-shell.xml
Normal file
238
sommelier/protocol/aura-shell.xml
Normal file
@ -0,0 +1,238 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="aura_shell">
|
||||
|
||||
<copyright>
|
||||
Copyright 2017 The Chromium Authors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="zaura_shell" version="6">
|
||||
<description summary="aura_shell">
|
||||
The global interface exposing aura shell capabilities is used to
|
||||
instantiate an interface extension for a wl_surface object.
|
||||
This extended interface will then allow the client to use aura shell
|
||||
specific functionality.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="aura_surface_exists" value="0"
|
||||
summary="the surface already has an aura surface object associated"/>
|
||||
<entry name="aura_output_exists" value="1"
|
||||
summary="the output already has an aura output object associated"/>
|
||||
</enum>
|
||||
|
||||
<request name="get_aura_surface">
|
||||
<description summary="extend surface interface for aura shell">
|
||||
Instantiate an interface extension for the given wl_surface to
|
||||
provide aura shell functionality. If the given wl_surface is not
|
||||
associated with a shell surface, the shell_surface_missing protocol
|
||||
error is raised.
|
||||
</description>
|
||||
|
||||
<arg name="id" type="new_id" interface="zaura_surface"
|
||||
summary="the new aura surface interface id"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"
|
||||
summary="the surface"/>
|
||||
</request>
|
||||
|
||||
<!-- Version 2 additions -->
|
||||
|
||||
<request name="get_aura_output" since="2">
|
||||
<description summary="extend output interface for aura shell">
|
||||
Instantiate an interface extension for the given wl_output to
|
||||
provide aura shell functionality.
|
||||
</description>
|
||||
|
||||
<arg name="id" type="new_id" interface="zaura_output"
|
||||
summary="the new aura output interface id"/>
|
||||
<arg name="output" type="object" interface="wl_output"
|
||||
summary="the output"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zaura_surface" version="5">
|
||||
<description summary="aura shell interface to a wl_surface">
|
||||
An additional interface to a wl_surface object, which allows the
|
||||
client to access aura shell specific functionality for surface.
|
||||
</description>
|
||||
|
||||
<enum name="frame_type">
|
||||
<description summary="different frame types">
|
||||
Frame types that can be used to decorate a surface.
|
||||
</description>
|
||||
<entry name="none" value="0" summary="no frame"/>
|
||||
<entry name="normal" value="1" summary="caption with shadow" />
|
||||
<entry name="shadow" value="2" summary="shadow only"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_frame">
|
||||
<description summary="request a frame for surface">
|
||||
Suggests a surface should use a specific frame.
|
||||
</description>
|
||||
<arg name="type" type="uint" summary="the new frame type"/>
|
||||
</request>
|
||||
|
||||
<!-- Version 2 additions -->
|
||||
|
||||
<request name="set_parent" since="2">
|
||||
<description summary="set the parent of this surface">
|
||||
Set the "parent" of this surface. "x" and "y" arguments specify the
|
||||
initial position for surface relative to parent.
|
||||
</description>
|
||||
<arg name="parent" type="object" interface="zaura_surface" allow-null="true"/>
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
</request>
|
||||
|
||||
<!-- Version 3 additions -->
|
||||
|
||||
<request name="set_frame_colors" since="3">
|
||||
<description summary="set the frame colors of this surface">
|
||||
Set the frame colors.
|
||||
</description>
|
||||
<arg name="active_color" type="uint" summary="32 bit ARGB color value, not premultiplied"/>
|
||||
<arg name="inactive_color" type="uint" summary="32 bit ARGB color value, not premultiplied"/>
|
||||
</request>
|
||||
|
||||
<!-- Version 4 additions -->
|
||||
|
||||
<request name="set_startup_id" since="4">
|
||||
<description summary="set the startup ID of this surface">
|
||||
Set the startup ID.
|
||||
</description>
|
||||
<arg name="startup_id" type="string" allow-null="true"/>
|
||||
</request>
|
||||
|
||||
<!-- Version 5 additions -->
|
||||
|
||||
<request name="set_application_id" since="5">
|
||||
<description summary="set the application ID of this surface">
|
||||
Set the application ID.
|
||||
</description>
|
||||
<arg name="application_id" type="string" allow-null="true"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zaura_output" version="6">
|
||||
<description summary="aura shell interface to a wl_output">
|
||||
An additional interface to a wl_output object, which allows the
|
||||
client to access aura shell specific functionality for output.
|
||||
</description>
|
||||
|
||||
<!-- Version 2 additions -->
|
||||
|
||||
<enum name="scale_property" bitfield="true">
|
||||
<description summary="scale information">
|
||||
These flags describe properties of an output scale.
|
||||
They are used in the flags bitfield of the scale event.
|
||||
</description>
|
||||
<entry name="current" value="0x1"
|
||||
summary="indicates this is the current scale"/>
|
||||
<entry name="preferred" value="0x2"
|
||||
summary="indicates this is the preferred scale"/>
|
||||
</enum>
|
||||
|
||||
<enum name="scale_factor">
|
||||
<entry name="0400" value="400"/>
|
||||
<entry name="0500" value="500"/>
|
||||
<entry name="0550" value="550"/>
|
||||
<entry name="0600" value="600"/>
|
||||
<entry name="0625" value="625"/>
|
||||
<entry name="0650" value="650"/>
|
||||
<entry name="0700" value="700"/>
|
||||
<entry name="0750" value="750"/>
|
||||
<entry name="0800" value="800"/>
|
||||
<entry name="0850" value="850"/>
|
||||
<entry name="0900" value="900"/>
|
||||
<entry name="0950" value="950"/>
|
||||
<entry name="1000" value="1000"/>
|
||||
<entry name="1050" value="1050"/>
|
||||
<entry name="1100" value="1100"/>
|
||||
<entry name="1150" value="1150"/>
|
||||
<entry name="1125" value="1125"/>
|
||||
<entry name="1200" value="1200"/>
|
||||
<entry name="1250" value="1250"/>
|
||||
<entry name="1300" value="1300"/>
|
||||
<entry name="1400" value="1400"/>
|
||||
<entry name="1450" value="1450"/>
|
||||
<entry name="1500" value="1500"/>
|
||||
<entry name="1600" value="1600"/>
|
||||
<entry name="1750" value="1750"/>
|
||||
<entry name="1800" value="1800"/>
|
||||
<entry name="2000" value="2000"/>
|
||||
<entry name="2200" value="2200"/>
|
||||
<entry name="2250" value="2250"/>
|
||||
<entry name="2500" value="2500"/>
|
||||
<entry name="2750" value="2750"/>
|
||||
<entry name="3000" value="3000"/>
|
||||
<entry name="3500" value="3500"/>
|
||||
<entry name="4000" value="4000"/>
|
||||
<entry name="4500" value="4500"/>
|
||||
<entry name="5000" value="5000"/>
|
||||
</enum>
|
||||
|
||||
<event name="scale" since="2">
|
||||
<description summary="advertise available scales for the output">
|
||||
The scale event describes an available scale for the output.
|
||||
|
||||
The event is sent when binding to the output object and there
|
||||
will always be one scale, the current scale. The event is sent
|
||||
again if an output changes scale, for the scale that is now
|
||||
current. In other words, the current scale is always the last
|
||||
scale that was received with the current flag set.
|
||||
</description>
|
||||
<arg name="flags" type="uint" enum="scale_property" summary="bitfield of scale flags"/>
|
||||
<arg name="scale" type="uint" enum="scale_factor" summary="output scale"/>
|
||||
</event>
|
||||
|
||||
<!-- Version 5 additions -->
|
||||
|
||||
<enum name="connection_type">
|
||||
<entry name="unknown" value="0"/>
|
||||
<entry name="internal" value="1"/>
|
||||
</enum>
|
||||
|
||||
<event name="connection" since="5">
|
||||
<description summary="advertise connection for the output">
|
||||
The connection event describes how the output is connected.
|
||||
|
||||
The event is sent when binding to the output object.
|
||||
</description>
|
||||
<arg name="connection" type="uint" enum="connection_type" summary="output connection"/>
|
||||
</event>
|
||||
|
||||
<event name="device_scale_factor" since="5">
|
||||
<description summary="advertise device scale factor for the output">
|
||||
This event describes the device specific scale factor for the output.
|
||||
|
||||
The device specific scale factor is not expected the change during
|
||||
the lifetime of the output. And it is not limited to an integer value
|
||||
like the scale factor provided by wl_output interface. The exact
|
||||
contents scale used by the compositor can be determined by combining
|
||||
this device scale factor with the current output scale.
|
||||
|
||||
The event is sent when binding to the output object.
|
||||
</description>
|
||||
<arg name="scale" type="uint" enum="scale_factor" summary="output device scale factor"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
182
sommelier/protocol/drm.xml
Normal file
182
sommelier/protocol/drm.xml
Normal file
@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="drm">
|
||||
|
||||
<copyright>
|
||||
Copyright © 2008-2011 Kristian Høgsberg
|
||||
Copyright © 2010-2011 Intel Corporation
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that\n the above copyright notice appear in
|
||||
all copies and that both that copyright notice and this permission
|
||||
notice appear in supporting documentation, and that the name of
|
||||
the copyright holders not be used in advertising or publicity
|
||||
pertaining to distribution of the software without specific,
|
||||
written prior permission. The copyright holders make no
|
||||
representations about the suitability of this software for any
|
||||
purpose. It is provided "as is" without express or implied
|
||||
warranty.
|
||||
|
||||
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<!-- drm support. This object is created by the server and published
|
||||
using the display's global event. -->
|
||||
<interface name="wl_drm" version="2">
|
||||
<enum name="error">
|
||||
<entry name="authenticate_fail" value="0"/>
|
||||
<entry name="invalid_format" value="1"/>
|
||||
<entry name="invalid_name" value="2"/>
|
||||
</enum>
|
||||
|
||||
<enum name="format">
|
||||
<!-- The drm format codes match the #defines in drm_fourcc.h.
|
||||
The formats actually supported by the compositor will be
|
||||
reported by the format event. -->
|
||||
<entry name="c8" value="0x20203843"/>
|
||||
<entry name="rgb332" value="0x38424752"/>
|
||||
<entry name="bgr233" value="0x38524742"/>
|
||||
<entry name="xrgb4444" value="0x32315258"/>
|
||||
<entry name="xbgr4444" value="0x32314258"/>
|
||||
<entry name="rgbx4444" value="0x32315852"/>
|
||||
<entry name="bgrx4444" value="0x32315842"/>
|
||||
<entry name="argb4444" value="0x32315241"/>
|
||||
<entry name="abgr4444" value="0x32314241"/>
|
||||
<entry name="rgba4444" value="0x32314152"/>
|
||||
<entry name="bgra4444" value="0x32314142"/>
|
||||
<entry name="xrgb1555" value="0x35315258"/>
|
||||
<entry name="xbgr1555" value="0x35314258"/>
|
||||
<entry name="rgbx5551" value="0x35315852"/>
|
||||
<entry name="bgrx5551" value="0x35315842"/>
|
||||
<entry name="argb1555" value="0x35315241"/>
|
||||
<entry name="abgr1555" value="0x35314241"/>
|
||||
<entry name="rgba5551" value="0x35314152"/>
|
||||
<entry name="bgra5551" value="0x35314142"/>
|
||||
<entry name="rgb565" value="0x36314752"/>
|
||||
<entry name="bgr565" value="0x36314742"/>
|
||||
<entry name="rgb888" value="0x34324752"/>
|
||||
<entry name="bgr888" value="0x34324742"/>
|
||||
<entry name="xrgb8888" value="0x34325258"/>
|
||||
<entry name="xbgr8888" value="0x34324258"/>
|
||||
<entry name="rgbx8888" value="0x34325852"/>
|
||||
<entry name="bgrx8888" value="0x34325842"/>
|
||||
<entry name="argb8888" value="0x34325241"/>
|
||||
<entry name="abgr8888" value="0x34324241"/>
|
||||
<entry name="rgba8888" value="0x34324152"/>
|
||||
<entry name="bgra8888" value="0x34324142"/>
|
||||
<entry name="xrgb2101010" value="0x30335258"/>
|
||||
<entry name="xbgr2101010" value="0x30334258"/>
|
||||
<entry name="rgbx1010102" value="0x30335852"/>
|
||||
<entry name="bgrx1010102" value="0x30335842"/>
|
||||
<entry name="argb2101010" value="0x30335241"/>
|
||||
<entry name="abgr2101010" value="0x30334241"/>
|
||||
<entry name="rgba1010102" value="0x30334152"/>
|
||||
<entry name="bgra1010102" value="0x30334142"/>
|
||||
<entry name="yuyv" value="0x56595559"/>
|
||||
<entry name="yvyu" value="0x55595659"/>
|
||||
<entry name="uyvy" value="0x59565955"/>
|
||||
<entry name="vyuy" value="0x59555956"/>
|
||||
<entry name="ayuv" value="0x56555941"/>
|
||||
<entry name="nv12" value="0x3231564e"/>
|
||||
<entry name="nv21" value="0x3132564e"/>
|
||||
<entry name="nv16" value="0x3631564e"/>
|
||||
<entry name="nv61" value="0x3136564e"/>
|
||||
<entry name="yuv410" value="0x39565559"/>
|
||||
<entry name="yvu410" value="0x39555659"/>
|
||||
<entry name="yuv411" value="0x31315559"/>
|
||||
<entry name="yvu411" value="0x31315659"/>
|
||||
<entry name="yuv420" value="0x32315559"/>
|
||||
<entry name="yvu420" value="0x32315659"/>
|
||||
<entry name="yuv422" value="0x36315559"/>
|
||||
<entry name="yvu422" value="0x36315659"/>
|
||||
<entry name="yuv444" value="0x34325559"/>
|
||||
<entry name="yvu444" value="0x34325659"/>
|
||||
</enum>
|
||||
|
||||
<!-- Call this request with the magic received from drmGetMagic().
|
||||
It will be passed on to the drmAuthMagic() or
|
||||
DRIAuthConnection() call. This authentication must be
|
||||
completed before create_buffer could be used. -->
|
||||
<request name="authenticate">
|
||||
<arg name="id" type="uint"/>
|
||||
</request>
|
||||
|
||||
<!-- Create a wayland buffer for the named DRM buffer. The DRM
|
||||
surface must have a name using the flink ioctl -->
|
||||
<request name="create_buffer">
|
||||
<arg name="id" type="new_id" interface="wl_buffer"/>
|
||||
<arg name="name" type="uint"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
<arg name="stride" type="uint"/>
|
||||
<arg name="format" type="uint"/>
|
||||
</request>
|
||||
|
||||
<!-- Create a wayland buffer for the named DRM buffer. The DRM
|
||||
surface must have a name using the flink ioctl -->
|
||||
<request name="create_planar_buffer">
|
||||
<arg name="id" type="new_id" interface="wl_buffer"/>
|
||||
<arg name="name" type="uint"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
<arg name="format" type="uint"/>
|
||||
<arg name="offset0" type="int"/>
|
||||
<arg name="stride0" type="int"/>
|
||||
<arg name="offset1" type="int"/>
|
||||
<arg name="stride1" type="int"/>
|
||||
<arg name="offset2" type="int"/>
|
||||
<arg name="stride2" type="int"/>
|
||||
</request>
|
||||
|
||||
<!-- Create a wayland buffer for the prime fd. Use for regular and planar
|
||||
buffers. Pass 0 for offset and stride for unused planes. -->
|
||||
<request name="create_prime_buffer" since="2">
|
||||
<arg name="id" type="new_id" interface="wl_buffer"/>
|
||||
<arg name="name" type="fd"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
<arg name="format" type="uint"/>
|
||||
<arg name="offset0" type="int"/>
|
||||
<arg name="stride0" type="int"/>
|
||||
<arg name="offset1" type="int"/>
|
||||
<arg name="stride1" type="int"/>
|
||||
<arg name="offset2" type="int"/>
|
||||
<arg name="stride2" type="int"/>
|
||||
</request>
|
||||
|
||||
<!-- Notification of the path of the drm device which is used by
|
||||
the server. The client should use this device for creating
|
||||
local buffers. Only buffers created from this device should
|
||||
be be passed to the server using this drm object's
|
||||
create_buffer request. -->
|
||||
<event name="device">
|
||||
<arg name="name" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="format">
|
||||
<arg name="format" type="uint"/>
|
||||
</event>
|
||||
|
||||
<!-- Raised if the authenticate request succeeded -->
|
||||
<event name="authenticated"/>
|
||||
|
||||
<enum name="capability" since="2">
|
||||
<description summary="wl_drm capability bitmask">
|
||||
Bitmask of capabilities.
|
||||
</description>
|
||||
<entry name="prime" value="1" summary="wl_drm prime available"/>
|
||||
</enum>
|
||||
|
||||
<event name="capabilities">
|
||||
<arg name="value" type="uint"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
61
sommelier/protocol/gtk-shell.xml
Normal file
61
sommelier/protocol/gtk-shell.xml
Normal file
@ -0,0 +1,61 @@
|
||||
<protocol name="gtk">
|
||||
|
||||
<interface name="gtk_shell1" version="1">
|
||||
<description summary="gtk specific extensions">
|
||||
gtk_shell is a protocol extension providing additional features for
|
||||
clients implementing it.
|
||||
</description>
|
||||
|
||||
<enum name="capability">
|
||||
<entry name="global_app_menu" value="1"/>
|
||||
<entry name="global_menu_bar" value="2"/>
|
||||
<entry name="desktop_icons" value="3"/>
|
||||
</enum>
|
||||
|
||||
<event name="capabilities">
|
||||
<arg name="capabilities" type="uint"/>
|
||||
</event>
|
||||
|
||||
<request name="get_gtk_surface">
|
||||
<arg name="gtk_surface" type="new_id" interface="gtk_surface1"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
|
||||
<request name="set_startup_id">
|
||||
<arg name="startup_id" type="string" allow-null="true"/>
|
||||
</request>
|
||||
|
||||
<request name="system_bell">
|
||||
<arg name="surface" type="object" interface="gtk_surface1" allow-null="true"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="gtk_surface1" version="1">
|
||||
<request name="set_dbus_properties">
|
||||
<arg name="application_id" type="string" allow-null="true"/>
|
||||
<arg name="app_menu_path" type="string" allow-null="true"/>
|
||||
<arg name="menubar_path" type="string" allow-null="true"/>
|
||||
<arg name="window_object_path" type="string" allow-null="true"/>
|
||||
<arg name="application_object_path" type="string" allow-null="true"/>
|
||||
<arg name="unique_bus_name" type="string" allow-null="true"/>
|
||||
</request>
|
||||
|
||||
<request name="set_modal"/>
|
||||
<request name="unset_modal"/>
|
||||
|
||||
<request name="present">
|
||||
<arg name="time" type="uint"/>
|
||||
</request>
|
||||
|
||||
<!-- Version 2 additions -->
|
||||
|
||||
<enum name="state">
|
||||
<entry name="tiled" value="1"/>
|
||||
</enum>
|
||||
|
||||
<event name="configure">
|
||||
<arg name="states" type="array"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
82
sommelier/protocol/keyboard-extension-unstable-v1.xml
Normal file
82
sommelier/protocol/keyboard-extension-unstable-v1.xml
Normal file
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="keyboard_extension_unstable_v1">
|
||||
|
||||
<copyright>
|
||||
Copyright 2017 The Chromium Authors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="zcr_keyboard_extension_v1" version="1">
|
||||
<description summary="extends wl_keyboard with ack_key events">
|
||||
Allows a wl_keyboard to send ack_key requests for each key event of
|
||||
the keyboard to the server.
|
||||
|
||||
Warning! The protocol described in this file is experimental and
|
||||
backward incompatible changes may be made. Backward compatible changes
|
||||
may be added together with the corresponding uinterface version bump.
|
||||
Backward incompatible changes are done by bumping the version number in
|
||||
the protocol and uinterface names and resetting the interface version.
|
||||
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
version number in the protocol and interface names are removed and the
|
||||
interface version number is reset.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="extended_keyboard_exists" value="0"
|
||||
summary="the keyboard already has an extended_keyboard object associated"/>
|
||||
</enum>
|
||||
|
||||
<request name="get_extended_keyboard">
|
||||
<description summary="get extended_keyboard for a keyboard">
|
||||
Create extended_keyboard object.
|
||||
See zcr_extended_keyboard interface for details.
|
||||
If the given wl_keyboard object already has a extended_keyboard object
|
||||
associated, the extended_keyboard_exists protocol error is raised.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zcr_extended_keyboard_v1"/>
|
||||
<arg name="keyboard" type="object" interface="wl_keyboard"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zcr_extended_keyboard_v1" version="1">
|
||||
<description summary="extension of wl_keyboard protocol">
|
||||
The zcr_extended_keyboard_v1 interface extends the wl_keyboard interface
|
||||
with requests to notify whether sent key events are handled or not by
|
||||
the client.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy extended_keyboard object"/>
|
||||
</request>
|
||||
|
||||
<enum name="handled_state">
|
||||
<description summary="whether a key event is handled by client or not"/>
|
||||
<entry name="not_handled" value="0"/>
|
||||
<entry name="handled" value="1"/>
|
||||
</enum>
|
||||
|
||||
<request name="ack_key">
|
||||
<description summary="acknowledge a key event"/>
|
||||
<arg name="serial" type="uint"/>
|
||||
<arg name="handled" type="uint" enum="handled_state"/>
|
||||
</request>
|
||||
</interface>
|
||||
</protocol>
|
348
sommelier/protocol/linux-dmabuf-unstable-v1.xml
Normal file
348
sommelier/protocol/linux-dmabuf-unstable-v1.xml
Normal file
@ -0,0 +1,348 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="linux_dmabuf_unstable_v1">
|
||||
|
||||
<copyright>
|
||||
Copyright © 2014, 2015 Collabora, Ltd.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="zwp_linux_dmabuf_v1" version="3">
|
||||
<description summary="factory for creating dmabuf-based wl_buffers">
|
||||
Following the interfaces from:
|
||||
https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
|
||||
and the Linux DRM sub-system's AddFb2 ioctl.
|
||||
|
||||
This interface offers ways to create generic dmabuf-based
|
||||
wl_buffers. Immediately after a client binds to this interface,
|
||||
the set of supported formats and format modifiers is sent with
|
||||
'format' and 'modifier' events.
|
||||
|
||||
The following are required from clients:
|
||||
|
||||
- Clients must ensure that either all data in the dma-buf is
|
||||
coherent for all subsequent read access or that coherency is
|
||||
correctly handled by the underlying kernel-side dma-buf
|
||||
implementation.
|
||||
|
||||
- Don't make any more attachments after sending the buffer to the
|
||||
compositor. Making more attachments later increases the risk of
|
||||
the compositor not being able to use (re-import) an existing
|
||||
dmabuf-based wl_buffer.
|
||||
|
||||
The underlying graphics stack must ensure the following:
|
||||
|
||||
- The dmabuf file descriptors relayed to the server will stay valid
|
||||
for the whole lifetime of the wl_buffer. This means the server may
|
||||
at any time use those fds to import the dmabuf into any kernel
|
||||
sub-system that might accept it.
|
||||
|
||||
To create a wl_buffer from one or more dmabufs, a client creates a
|
||||
zwp_linux_dmabuf_params_v1 object with a zwp_linux_dmabuf_v1.create_params
|
||||
request. All planes required by the intended format are added with
|
||||
the 'add' request. Finally, a 'create' or 'create_immed' request is
|
||||
issued, which has the following outcome depending on the import success.
|
||||
|
||||
The 'create' request,
|
||||
- on success, triggers a 'created' event which provides the final
|
||||
wl_buffer to the client.
|
||||
- on failure, triggers a 'failed' event to convey that the server
|
||||
cannot use the dmabufs received from the client.
|
||||
|
||||
For the 'create_immed' request,
|
||||
- on success, the server immediately imports the added dmabufs to
|
||||
create a wl_buffer. No event is sent from the server in this case.
|
||||
- on failure, the server can choose to either:
|
||||
- terminate the client by raising a fatal error.
|
||||
- mark the wl_buffer as failed, and send a 'failed' event to the
|
||||
client. If the client uses a failed wl_buffer as an argument to any
|
||||
request, the behaviour is compositor implementation-defined.
|
||||
|
||||
Warning! The protocol described in this file is experimental and
|
||||
backward incompatible changes may be made. Backward compatible changes
|
||||
may be added together with the corresponding interface version bump.
|
||||
Backward incompatible changes are done by bumping the version number in
|
||||
the protocol and interface names and resetting the interface version.
|
||||
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
version number in the protocol and interface names are removed and the
|
||||
interface version number is reset.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="unbind the factory">
|
||||
Objects created through this interface, especially wl_buffers, will
|
||||
remain valid.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="create_params">
|
||||
<description summary="create a temporary object for buffer parameters">
|
||||
This temporary object is used to collect multiple dmabuf handles into
|
||||
a single batch to create a wl_buffer. It can only be used once and
|
||||
should be destroyed after a 'created' or 'failed' event has been
|
||||
received.
|
||||
</description>
|
||||
<arg name="params_id" type="new_id" interface="zwp_linux_buffer_params_v1"
|
||||
summary="the new temporary"/>
|
||||
</request>
|
||||
|
||||
<event name="format">
|
||||
<description summary="supported buffer format">
|
||||
This event advertises one buffer format that the server supports.
|
||||
All the supported formats are advertised once when the client
|
||||
binds to this interface. A roundtrip after binding guarantees
|
||||
that the client has received all supported formats.
|
||||
|
||||
For the definition of the format codes, see the
|
||||
zwp_linux_buffer_params_v1::create request.
|
||||
|
||||
Warning: the 'format' event is likely to be deprecated and replaced
|
||||
with the 'modifier' event introduced in zwp_linux_dmabuf_v1
|
||||
version 3, described below. Please refrain from using the information
|
||||
received from this event.
|
||||
</description>
|
||||
<arg name="format" type="uint" summary="DRM_FORMAT code"/>
|
||||
</event>
|
||||
|
||||
<event name="modifier" since="3">
|
||||
<description summary="supported buffer format modifier">
|
||||
This event advertises the formats that the server supports, along with
|
||||
the modifiers supported for each format. All the supported modifiers
|
||||
for all the supported formats are advertised once when the client
|
||||
binds to this interface. A roundtrip after binding guarantees that
|
||||
the client has received all supported format-modifier pairs.
|
||||
|
||||
For the definition of the format and modifier codes, see the
|
||||
zwp_linux_buffer_params_v1::create request.
|
||||
</description>
|
||||
<arg name="format" type="uint" summary="DRM_FORMAT code"/>
|
||||
<arg name="modifier_hi" type="uint"
|
||||
summary="high 32 bits of layout modifier"/>
|
||||
<arg name="modifier_lo" type="uint"
|
||||
summary="low 32 bits of layout modifier"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="zwp_linux_buffer_params_v1" version="3">
|
||||
<description summary="parameters for creating a dmabuf-based wl_buffer">
|
||||
This temporary object is a collection of dmabufs and other
|
||||
parameters that together form a single logical buffer. The temporary
|
||||
object may eventually create one wl_buffer unless cancelled by
|
||||
destroying it before requesting 'create'.
|
||||
|
||||
Single-planar formats only require one dmabuf, however
|
||||
multi-planar formats may require more than one dmabuf. For all
|
||||
formats, an 'add' request must be called once per plane (even if the
|
||||
underlying dmabuf fd is identical).
|
||||
|
||||
You must use consecutive plane indices ('plane_idx' argument for 'add')
|
||||
from zero to the number of planes used by the drm_fourcc format code.
|
||||
All planes required by the format must be given exactly once, but can
|
||||
be given in any order. Each plane index can be set only once.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="already_used" value="0"
|
||||
summary="the dmabuf_batch object has already been used to create a wl_buffer"/>
|
||||
<entry name="plane_idx" value="1"
|
||||
summary="plane index out of bounds"/>
|
||||
<entry name="plane_set" value="2"
|
||||
summary="the plane index was already set"/>
|
||||
<entry name="incomplete" value="3"
|
||||
summary="missing or too many planes to create a buffer"/>
|
||||
<entry name="invalid_format" value="4"
|
||||
summary="format not supported"/>
|
||||
<entry name="invalid_dimensions" value="5"
|
||||
summary="invalid width or height"/>
|
||||
<entry name="out_of_bounds" value="6"
|
||||
summary="offset + stride * height goes out of dmabuf bounds"/>
|
||||
<entry name="invalid_wl_buffer" value="7"
|
||||
summary="invalid wl_buffer resulted from importing dmabufs via
|
||||
the create_immed request on given buffer_params"/>
|
||||
</enum>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="delete this object, used or not">
|
||||
Cleans up the temporary data sent to the server for dmabuf-based
|
||||
wl_buffer creation.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="add">
|
||||
<description summary="add a dmabuf to the temporary set">
|
||||
This request adds one dmabuf to the set in this
|
||||
zwp_linux_buffer_params_v1.
|
||||
|
||||
The 64-bit unsigned value combined from modifier_hi and modifier_lo
|
||||
is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the
|
||||
fb modifier, which is defined in drm_mode.h of Linux UAPI.
|
||||
This is an opaque token. Drivers use this token to express tiling,
|
||||
compression, etc. driver-specific modifications to the base format
|
||||
defined by the DRM fourcc code.
|
||||
|
||||
This request raises the PLANE_IDX error if plane_idx is too large.
|
||||
The error PLANE_SET is raised if attempting to set a plane that
|
||||
was already set.
|
||||
</description>
|
||||
<arg name="fd" type="fd" summary="dmabuf fd"/>
|
||||
<arg name="plane_idx" type="uint" summary="plane index"/>
|
||||
<arg name="offset" type="uint" summary="offset in bytes"/>
|
||||
<arg name="stride" type="uint" summary="stride in bytes"/>
|
||||
<arg name="modifier_hi" type="uint"
|
||||
summary="high 32 bits of layout modifier"/>
|
||||
<arg name="modifier_lo" type="uint"
|
||||
summary="low 32 bits of layout modifier"/>
|
||||
</request>
|
||||
|
||||
<enum name="flags">
|
||||
<entry name="y_invert" value="1" summary="contents are y-inverted"/>
|
||||
<entry name="interlaced" value="2" summary="content is interlaced"/>
|
||||
<entry name="bottom_first" value="4" summary="bottom field first"/>
|
||||
</enum>
|
||||
|
||||
<request name="create">
|
||||
<description summary="create a wl_buffer from the given dmabufs">
|
||||
This asks for creation of a wl_buffer from the added dmabuf
|
||||
buffers. The wl_buffer is not created immediately but returned via
|
||||
the 'created' event if the dmabuf sharing succeeds. The sharing
|
||||
may fail at runtime for reasons a client cannot predict, in
|
||||
which case the 'failed' event is triggered.
|
||||
|
||||
The 'format' argument is a DRM_FORMAT code, as defined by the
|
||||
libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the
|
||||
authoritative source on how the format codes should work.
|
||||
|
||||
The 'flags' is a bitfield of the flags defined in enum "flags".
|
||||
'y_invert' means the that the image needs to be y-flipped.
|
||||
|
||||
Flag 'interlaced' means that the frame in the buffer is not
|
||||
progressive as usual, but interlaced. An interlaced buffer as
|
||||
supported here must always contain both top and bottom fields.
|
||||
The top field always begins on the first pixel row. The temporal
|
||||
ordering between the two fields is top field first, unless
|
||||
'bottom_first' is specified. It is undefined whether 'bottom_first'
|
||||
is ignored if 'interlaced' is not set.
|
||||
|
||||
This protocol does not convey any information about field rate,
|
||||
duration, or timing, other than the relative ordering between the
|
||||
two fields in one buffer. A compositor may have to estimate the
|
||||
intended field rate from the incoming buffer rate. It is undefined
|
||||
whether the time of receiving wl_surface.commit with a new buffer
|
||||
attached, applying the wl_surface state, wl_surface.frame callback
|
||||
trigger, presentation, or any other point in the compositor cycle
|
||||
is used to measure the frame or field times. There is no support
|
||||
for detecting missed or late frames/fields/buffers either, and
|
||||
there is no support whatsoever for cooperating with interlaced
|
||||
compositor output.
|
||||
|
||||
The composited image quality resulting from the use of interlaced
|
||||
buffers is explicitly undefined. A compositor may use elaborate
|
||||
hardware features or software to deinterlace and create progressive
|
||||
output frames from a sequence of interlaced input buffers, or it
|
||||
may produce substandard image quality. However, compositors that
|
||||
cannot guarantee reasonable image quality in all cases are recommended
|
||||
to just reject all interlaced buffers.
|
||||
|
||||
Any argument errors, including non-positive width or height,
|
||||
mismatch between the number of planes and the format, bad
|
||||
format, bad offset or stride, may be indicated by fatal protocol
|
||||
errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS,
|
||||
OUT_OF_BOUNDS.
|
||||
|
||||
Dmabuf import errors in the server that are not obvious client
|
||||
bugs are returned via the 'failed' event as non-fatal. This
|
||||
allows attempting dmabuf sharing and falling back in the client
|
||||
if it fails.
|
||||
|
||||
This request can be sent only once in the object's lifetime, after
|
||||
which the only legal request is destroy. This object should be
|
||||
destroyed after issuing a 'create' request. Attempting to use this
|
||||
object after issuing 'create' raises ALREADY_USED protocol error.
|
||||
|
||||
It is not mandatory to issue 'create'. If a client wants to
|
||||
cancel the buffer creation, it can just destroy this object.
|
||||
</description>
|
||||
<arg name="width" type="int" summary="base plane width in pixels"/>
|
||||
<arg name="height" type="int" summary="base plane height in pixels"/>
|
||||
<arg name="format" type="uint" summary="DRM_FORMAT code"/>
|
||||
<arg name="flags" type="uint" summary="see enum flags"/>
|
||||
</request>
|
||||
|
||||
<event name="created">
|
||||
<description summary="buffer creation succeeded">
|
||||
This event indicates that the attempted buffer creation was
|
||||
successful. It provides the new wl_buffer referencing the dmabuf(s).
|
||||
|
||||
Upon receiving this event, the client should destroy the
|
||||
zlinux_dmabuf_params object.
|
||||
</description>
|
||||
<arg name="buffer" type="new_id" interface="wl_buffer"
|
||||
summary="the newly created wl_buffer"/>
|
||||
</event>
|
||||
|
||||
<event name="failed">
|
||||
<description summary="buffer creation failed">
|
||||
This event indicates that the attempted buffer creation has
|
||||
failed. It usually means that one of the dmabuf constraints
|
||||
has not been fulfilled.
|
||||
|
||||
Upon receiving this event, the client should destroy the
|
||||
zlinux_buffer_params object.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<request name="create_immed" since="2">
|
||||
<description summary="immediately create a wl_buffer from the given
|
||||
dmabufs">
|
||||
This asks for immediate creation of a wl_buffer by importing the
|
||||
added dmabufs.
|
||||
|
||||
In case of import success, no event is sent from the server, and the
|
||||
wl_buffer is ready to be used by the client.
|
||||
|
||||
Upon import failure, either of the following may happen, as seen fit
|
||||
by the implementation:
|
||||
- the client is terminated with one of the following fatal protocol
|
||||
errors:
|
||||
- INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS,
|
||||
in case of argument errors such as mismatch between the number
|
||||
of planes and the format, bad format, non-positive width or
|
||||
height, or bad offset or stride.
|
||||
- INVALID_WL_BUFFER, in case the cause for failure is unknown or
|
||||
plaform specific.
|
||||
- the server creates an invalid wl_buffer, marks it as failed and
|
||||
sends a 'failed' event to the client. The result of using this
|
||||
invalid wl_buffer as an argument in any request by the client is
|
||||
defined by the compositor implementation.
|
||||
|
||||
This takes the same arguments as a 'create' request, and obeys the
|
||||
same restrictions.
|
||||
</description>
|
||||
<arg name="buffer_id" type="new_id" interface="wl_buffer"
|
||||
summary="id for the newly created wl_buffer"/>
|
||||
<arg name="width" type="int" summary="base plane width in pixels"/>
|
||||
<arg name="height" type="int" summary="base plane height in pixels"/>
|
||||
<arg name="format" type="uint" summary="DRM_FORMAT code"/>
|
||||
<arg name="flags" type="uint" summary="see enum flags"/>
|
||||
</request>
|
||||
|
||||
</interface>
|
||||
|
||||
</protocol>
|
136
sommelier/protocol/relative-pointer-unstable-v1.xml
Normal file
136
sommelier/protocol/relative-pointer-unstable-v1.xml
Normal file
@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="relative_pointer_unstable_v1">
|
||||
|
||||
<copyright>
|
||||
Copyright © 2014 Jonas Ådahl
|
||||
Copyright © 2015 Red Hat Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<description summary="protocol for relative pointer motion events">
|
||||
This protocol specifies a set of interfaces used for making clients able to
|
||||
receive relative pointer events not obstructed by barriers (such as the
|
||||
monitor edge or other pointer barriers).
|
||||
|
||||
To start receiving relative pointer events, a client must first bind the
|
||||
global interface "wp_relative_pointer_manager" which, if a compositor
|
||||
supports relative pointer motion events, is exposed by the registry. After
|
||||
having created the relative pointer manager proxy object, the client uses
|
||||
it to create the actual relative pointer object using the
|
||||
"get_relative_pointer" request given a wl_pointer. The relative pointer
|
||||
motion events will then, when applicable, be transmitted via the proxy of
|
||||
the newly created relative pointer object. See the documentation of the
|
||||
relative pointer interface for more details.
|
||||
|
||||
Warning! The protocol described in this file is experimental and backward
|
||||
incompatible changes may be made. Backward compatible changes may be added
|
||||
together with the corresponding interface version bump. Backward
|
||||
incompatible changes are done by bumping the version number in the protocol
|
||||
and interface names and resetting the interface version. Once the protocol
|
||||
is to be declared stable, the 'z' prefix and the version number in the
|
||||
protocol and interface names are removed and the interface version number is
|
||||
reset.
|
||||
</description>
|
||||
|
||||
<interface name="zwp_relative_pointer_manager_v1" version="1">
|
||||
<description summary="get relative pointer objects">
|
||||
A global interface used for getting the relative pointer object for a
|
||||
given pointer.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the relative pointer manager object">
|
||||
Used by the client to notify the server that it will no longer use this
|
||||
relative pointer manager object.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="get_relative_pointer">
|
||||
<description summary="get a relative pointer object">
|
||||
Create a relative pointer interface given a wl_pointer object. See the
|
||||
wp_relative_pointer interface for more details.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwp_relative_pointer_v1"/>
|
||||
<arg name="pointer" type="object" interface="wl_pointer"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zwp_relative_pointer_v1" version="1">
|
||||
<description summary="relative pointer object">
|
||||
A wp_relative_pointer object is an extension to the wl_pointer interface
|
||||
used for emitting relative pointer events. It shares the same focus as
|
||||
wl_pointer objects of the same seat and will only emit events when it has
|
||||
focus.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="release the relative pointer object"/>
|
||||
</request>
|
||||
|
||||
<event name="relative_motion">
|
||||
<description summary="relative pointer motion">
|
||||
Relative x/y pointer motion from the pointer of the seat associated with
|
||||
this object.
|
||||
|
||||
A relative motion is in the same dimension as regular wl_pointer motion
|
||||
events, except they do not represent an absolute position. For example,
|
||||
moving a pointer from (x, y) to (x', y') would have the equivalent
|
||||
relative motion (x' - x, y' - y). If a pointer motion caused the
|
||||
absolute pointer position to be clipped by for example the edge of the
|
||||
monitor, the relative motion is unaffected by the clipping and will
|
||||
represent the unclipped motion.
|
||||
|
||||
This event also contains non-accelerated motion deltas. The
|
||||
non-accelerated delta is, when applicable, the regular pointer motion
|
||||
delta as it was before having applied motion acceleration and other
|
||||
transformations such as normalization.
|
||||
|
||||
Note that the non-accelerated delta does not represent 'raw' events as
|
||||
they were read from some device. Pointer motion acceleration is device-
|
||||
and configuration-specific and non-accelerated deltas and accelerated
|
||||
deltas may have the same value on some devices.
|
||||
|
||||
Relative motions are not coupled to wl_pointer.motion events, and can be
|
||||
sent in combination with such events, but also independently. There may
|
||||
also be scenarios where wl_pointer.motion is sent, but there is no
|
||||
relative motion. The order of an absolute and relative motion event
|
||||
originating from the same physical motion is not guaranteed.
|
||||
|
||||
If the client needs button events or focus state, it can receive them
|
||||
from a wl_pointer object of the same seat that the wp_relative_pointer
|
||||
object is associated with.
|
||||
</description>
|
||||
<arg name="utime_hi" type="uint"
|
||||
summary="high 32 bits of a 64 bit timestamp with microsecond granularity"/>
|
||||
<arg name="utime_lo" type="uint"
|
||||
summary="low 32 bits of a 64 bit timestamp with microsecond granularity"/>
|
||||
<arg name="dx" type="fixed"
|
||||
summary="the x component of the motion vector"/>
|
||||
<arg name="dy" type="fixed"
|
||||
summary="the y component of the motion vector"/>
|
||||
<arg name="dx_unaccel" type="fixed"
|
||||
summary="the x component of the unaccelerated motion vector"/>
|
||||
<arg name="dy_unaccel" type="fixed"
|
||||
summary="the y component of the unaccelerated motion vector"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
385
sommelier/protocol/text-input-unstable-v1.xml
Normal file
385
sommelier/protocol/text-input-unstable-v1.xml
Normal file
@ -0,0 +1,385 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="text_input_unstable_v1">
|
||||
|
||||
<copyright>
|
||||
Copyright © 2012, 2013 Intel Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="zwp_text_input_v1" version="1">
|
||||
<description summary="text input">
|
||||
An object used for text input. Adds support for text input and input
|
||||
methods to applications. A text_input object is created from a
|
||||
wl_text_input_manager and corresponds typically to a text entry in an
|
||||
application.
|
||||
|
||||
Requests are used to activate/deactivate the text_input object and set
|
||||
state information like surrounding and selected text or the content type.
|
||||
The information about entered text is sent to the text_input object via
|
||||
the pre-edit and commit events. Using this interface removes the need
|
||||
for applications to directly process hardware key events and compose text
|
||||
out of them.
|
||||
|
||||
Text is generally UTF-8 encoded, indices and lengths are in bytes.
|
||||
|
||||
Serials are used to synchronize the state between the text input and
|
||||
an input method. New serials are sent by the text input in the
|
||||
commit_state request and are used by the input method to indicate
|
||||
the known text input state in events like preedit_string, commit_string,
|
||||
and keysym. The text input can then ignore events from the input method
|
||||
which are based on an outdated state (for example after a reset).
|
||||
|
||||
Warning! The protocol described in this file is experimental and
|
||||
backward incompatible changes may be made. Backward compatible changes
|
||||
may be added together with the corresponding interface version bump.
|
||||
Backward incompatible changes are done by bumping the version number in
|
||||
the protocol and interface names and resetting the interface version.
|
||||
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
version number in the protocol and interface names are removed and the
|
||||
interface version number is reset.
|
||||
</description>
|
||||
|
||||
<request name="activate">
|
||||
<description summary="request activation">
|
||||
Requests the text_input object to be activated (typically when the
|
||||
text entry gets focus).
|
||||
|
||||
The seat argument is a wl_seat which maintains the focus for this
|
||||
activation. The surface argument is a wl_surface assigned to the
|
||||
text_input object and tracked for focus lost. The enter event
|
||||
is emitted on successful activation.
|
||||
</description>
|
||||
<arg name="seat" type="object" interface="wl_seat"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
|
||||
<request name="deactivate">
|
||||
<description summary="request deactivation">
|
||||
Requests the text_input object to be deactivated (typically when the
|
||||
text entry lost focus). The seat argument is a wl_seat which was used
|
||||
for activation.
|
||||
</description>
|
||||
<arg name="seat" type="object" interface="wl_seat"/>
|
||||
</request>
|
||||
|
||||
<request name="show_input_panel">
|
||||
<description summary="show input panels">
|
||||
Requests input panels (virtual keyboard) to show.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="hide_input_panel">
|
||||
<description summary="hide input panels">
|
||||
Requests input panels (virtual keyboard) to hide.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="reset">
|
||||
<description summary="reset">
|
||||
Should be called by an editor widget when the input state should be
|
||||
reset, for example after the text was changed outside of the normal
|
||||
input method flow.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="set_surrounding_text">
|
||||
<description summary="sets the surrounding text">
|
||||
Sets the plain surrounding text around the input position. Text is
|
||||
UTF-8 encoded. Cursor is the byte offset within the
|
||||
surrounding text. Anchor is the byte offset of the
|
||||
selection anchor within the surrounding text. If there is no selected
|
||||
text anchor, then it is the same as cursor.
|
||||
</description>
|
||||
<arg name="text" type="string"/>
|
||||
<arg name="cursor" type="uint"/>
|
||||
<arg name="anchor" type="uint"/>
|
||||
</request>
|
||||
|
||||
<enum name="content_hint">
|
||||
<description summary="content hint">
|
||||
Content hint is a bitmask to allow to modify the behavior of the text
|
||||
input.
|
||||
</description>
|
||||
<entry name="none" value="0x0" summary="no special behaviour"/>
|
||||
<entry name="default" value="0x7" summary="auto completion, correction and capitalization"/>
|
||||
<entry name="password" value="0xc0" summary="hidden and sensitive text"/>
|
||||
<entry name="auto_completion" value="0x1" summary="suggest word completions"/>
|
||||
<entry name="auto_correction" value="0x2" summary="suggest word corrections"/>
|
||||
<entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/>
|
||||
<entry name="lowercase" value="0x8" summary="prefer lowercase letters"/>
|
||||
<entry name="uppercase" value="0x10" summary="prefer uppercase letters"/>
|
||||
<entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/>
|
||||
<entry name="hidden_text" value="0x40" summary="characters should be hidden"/>
|
||||
<entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/>
|
||||
<entry name="latin" value="0x100" summary="just latin characters should be entered"/>
|
||||
<entry name="multiline" value="0x200" summary="the text input is multiline"/>
|
||||
</enum>
|
||||
|
||||
<enum name="content_purpose">
|
||||
<description summary="content purpose">
|
||||
The content purpose allows to specify the primary purpose of a text
|
||||
input.
|
||||
|
||||
This allows an input method to show special purpose input panels with
|
||||
extra characters or to disallow some characters.
|
||||
</description>
|
||||
<entry name="normal" value="0" summary="default input, allowing all characters"/>
|
||||
<entry name="alpha" value="1" summary="allow only alphabetic characters"/>
|
||||
<entry name="digits" value="2" summary="allow only digits"/>
|
||||
<entry name="number" value="3" summary="input a number (including decimal separator and sign)"/>
|
||||
<entry name="phone" value="4" summary="input a phone number"/>
|
||||
<entry name="url" value="5" summary="input an URL"/>
|
||||
<entry name="email" value="6" summary="input an email address"/>
|
||||
<entry name="name" value="7" summary="input a name of a person"/>
|
||||
<entry name="password" value="8" summary="input a password (combine with password or sensitive_data hint)"/>
|
||||
<entry name="date" value="9" summary="input a date"/>
|
||||
<entry name="time" value="10" summary="input a time"/>
|
||||
<entry name="datetime" value="11" summary="input a date and time"/>
|
||||
<entry name="terminal" value="12" summary="input for a terminal"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_content_type">
|
||||
<description summary="set content purpose and hint">
|
||||
Sets the content purpose and content hint. While the purpose is the
|
||||
basic purpose of an input field, the hint flags allow to modify some
|
||||
of the behavior.
|
||||
|
||||
When no content type is explicitly set, a normal content purpose with
|
||||
default hints (auto completion, auto correction, auto capitalization)
|
||||
should be assumed.
|
||||
</description>
|
||||
<arg name="hint" type="uint"/>
|
||||
<arg name="purpose" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="set_cursor_rectangle">
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
</request>
|
||||
|
||||
<request name="set_preferred_language">
|
||||
<description summary="sets preferred language">
|
||||
Sets a specific language. This allows for example a virtual keyboard to
|
||||
show a language specific layout. The "language" argument is an RFC-3066
|
||||
format language tag.
|
||||
|
||||
It could be used for example in a word processor to indicate the
|
||||
language of the currently edited document or in an instant message
|
||||
application which tracks languages of contacts.
|
||||
</description>
|
||||
<arg name="language" type="string"/>
|
||||
</request>
|
||||
|
||||
<request name="commit_state">
|
||||
<arg name="serial" type="uint" summary="used to identify the known state"/>
|
||||
</request>
|
||||
|
||||
<request name="invoke_action">
|
||||
<arg name="button" type="uint"/>
|
||||
<arg name="index" type="uint"/>
|
||||
</request>
|
||||
|
||||
<event name="enter">
|
||||
<description summary="enter event">
|
||||
Notify the text_input object when it received focus. Typically in
|
||||
response to an activate request.
|
||||
</description>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</event>
|
||||
|
||||
<event name="leave">
|
||||
<description summary="leave event">
|
||||
Notify the text_input object when it lost focus. Either in response
|
||||
to a deactivate request or when the assigned surface lost focus or was
|
||||
destroyed.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<event name="modifiers_map">
|
||||
<description summary="modifiers map">
|
||||
Transfer an array of 0-terminated modifier names. The position in
|
||||
the array is the index of the modifier as used in the modifiers
|
||||
bitmask in the keysym event.
|
||||
</description>
|
||||
<arg name="map" type="array"/>
|
||||
</event>
|
||||
|
||||
<event name="input_panel_state">
|
||||
<description summary="state of the input panel">
|
||||
Notify when the visibility state of the input panel changed.
|
||||
</description>
|
||||
<arg name="state" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="preedit_string">
|
||||
<description summary="pre-edit">
|
||||
Notify when a new composing text (pre-edit) should be set around the
|
||||
current cursor position. Any previously set composing text should
|
||||
be removed.
|
||||
|
||||
The commit text can be used to replace the preedit text on reset
|
||||
(for example on unfocus).
|
||||
|
||||
The text input should also handle all preedit_style and preedit_cursor
|
||||
events occurring directly before preedit_string.
|
||||
</description>
|
||||
<arg name="serial" type="uint" summary="serial of the latest known text input state"/>
|
||||
<arg name="text" type="string"/>
|
||||
<arg name="commit" type="string"/>
|
||||
</event>
|
||||
|
||||
<enum name="preedit_style">
|
||||
<entry name="default" value="0" summary="default style for composing text"/>
|
||||
<entry name="none" value="1" summary="style should be the same as in non-composing text"/>
|
||||
<entry name="active" value="2"/>
|
||||
<entry name="inactive" value="3"/>
|
||||
<entry name="highlight" value="4"/>
|
||||
<entry name="underline" value="5"/>
|
||||
<entry name="selection" value="6"/>
|
||||
<entry name="incorrect" value="7"/>
|
||||
</enum>
|
||||
|
||||
<event name="preedit_styling">
|
||||
<description summary="pre-edit styling">
|
||||
Sets styling information on composing text. The style is applied for
|
||||
length bytes from index relative to the beginning of the composing
|
||||
text (as byte offset). Multiple styles can
|
||||
be applied to a composing text by sending multiple preedit_styling
|
||||
events.
|
||||
|
||||
This event is handled as part of a following preedit_string event.
|
||||
</description>
|
||||
<arg name="index" type="uint"/>
|
||||
<arg name="length" type="uint"/>
|
||||
<arg name="style" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="preedit_cursor">
|
||||
<description summary="pre-edit cursor">
|
||||
Sets the cursor position inside the composing text (as byte
|
||||
offset) relative to the start of the composing text. When index is a
|
||||
negative number no cursor is shown.
|
||||
|
||||
This event is handled as part of a following preedit_string event.
|
||||
</description>
|
||||
<arg name="index" type="int"/>
|
||||
</event>
|
||||
|
||||
<event name="commit_string">
|
||||
<description summary="commit">
|
||||
Notify when text should be inserted into the editor widget. The text to
|
||||
commit could be either just a single character after a key press or the
|
||||
result of some composing (pre-edit). It could also be an empty text
|
||||
when some text should be removed (see delete_surrounding_text) or when
|
||||
the input cursor should be moved (see cursor_position).
|
||||
|
||||
Any previously set composing text should be removed.
|
||||
</description>
|
||||
<arg name="serial" type="uint" summary="serial of the latest known text input state"/>
|
||||
<arg name="text" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="cursor_position">
|
||||
<description summary="set cursor to new position">
|
||||
Notify when the cursor or anchor position should be modified.
|
||||
|
||||
This event should be handled as part of a following commit_string
|
||||
event.
|
||||
</description>
|
||||
<arg name="index" type="int"/>
|
||||
<arg name="anchor" type="int"/>
|
||||
</event>
|
||||
|
||||
<event name="delete_surrounding_text">
|
||||
<description summary="delete surrounding text">
|
||||
Notify when the text around the current cursor position should be
|
||||
deleted.
|
||||
|
||||
Index is relative to the current cursor (in bytes).
|
||||
Length is the length of deleted text (in bytes).
|
||||
|
||||
This event should be handled as part of a following commit_string
|
||||
event.
|
||||
</description>
|
||||
<arg name="index" type="int"/>
|
||||
<arg name="length" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="keysym">
|
||||
<description summary="keysym">
|
||||
Notify when a key event was sent. Key events should not be used
|
||||
for normal text input operations, which should be done with
|
||||
commit_string, delete_surrounding_text, etc. The key event follows
|
||||
the wl_keyboard key event convention. Sym is an XKB keysym, state a
|
||||
wl_keyboard key_state. Modifiers are a mask for effective modifiers
|
||||
(where the modifier indices are set by the modifiers_map event)
|
||||
</description>
|
||||
<arg name="serial" type="uint" summary="serial of the latest known text input state"/>
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="sym" type="uint"/>
|
||||
<arg name="state" type="uint"/>
|
||||
<arg name="modifiers" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="language">
|
||||
<description summary="language">
|
||||
Sets the language of the input text. The "language" argument is an
|
||||
RFC-3066 format language tag.
|
||||
</description>
|
||||
<arg name="serial" type="uint" summary="serial of the latest known text input state"/>
|
||||
<arg name="language" type="string"/>
|
||||
</event>
|
||||
|
||||
<enum name="text_direction">
|
||||
<entry name="auto" value="0" summary="automatic text direction based on text and language"/>
|
||||
<entry name="ltr" value="1" summary="left-to-right"/>
|
||||
<entry name="rtl" value="2" summary="right-to-left"/>
|
||||
</enum>
|
||||
|
||||
<event name="text_direction">
|
||||
<description summary="text direction">
|
||||
Sets the text direction of input text.
|
||||
|
||||
It is mainly needed for showing an input cursor on the correct side of
|
||||
the editor when there is no input done yet and making sure neutral
|
||||
direction text is laid out properly.
|
||||
</description>
|
||||
<arg name="serial" type="uint" summary="serial of the latest known text input state"/>
|
||||
<arg name="direction" type="uint"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="zwp_text_input_manager_v1" version="1">
|
||||
<description summary="text input manager">
|
||||
A factory for text_input objects. This object is a global singleton.
|
||||
</description>
|
||||
|
||||
<request name="create_text_input">
|
||||
<description summary="create text input">
|
||||
Creates a new text_input object.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwp_text_input_v1"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
186
sommelier/protocol/viewporter.xml
Normal file
186
sommelier/protocol/viewporter.xml
Normal file
@ -0,0 +1,186 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="viewporter">
|
||||
|
||||
<copyright>
|
||||
Copyright © 2013-2016 Collabora, Ltd.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="wp_viewporter" version="1">
|
||||
<description summary="surface cropping and scaling">
|
||||
The global interface exposing surface cropping and scaling
|
||||
capabilities is used to instantiate an interface extension for a
|
||||
wl_surface object. This extended interface will then allow
|
||||
cropping and scaling the surface contents, effectively
|
||||
disconnecting the direct relationship between the buffer and the
|
||||
surface size.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="unbind from the cropping and scaling interface">
|
||||
Informs the server that the client will not be using this
|
||||
protocol object anymore. This does not affect any other objects,
|
||||
wp_viewport objects included.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="viewport_exists" value="0"
|
||||
summary="the surface already has a viewport object associated"/>
|
||||
</enum>
|
||||
|
||||
<request name="get_viewport">
|
||||
<description summary="extend surface interface for crop and scale">
|
||||
Instantiate an interface extension for the given wl_surface to
|
||||
crop and scale its content. If the given wl_surface already has
|
||||
a wp_viewport object associated, the viewport_exists
|
||||
protocol error is raised.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="wp_viewport"
|
||||
summary="the new viewport interface id"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"
|
||||
summary="the surface"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="wp_viewport" version="1">
|
||||
<description summary="crop and scale interface to a wl_surface">
|
||||
An additional interface to a wl_surface object, which allows the
|
||||
client to specify the cropping and scaling of the surface
|
||||
contents.
|
||||
|
||||
This interface works with two concepts: the source rectangle (src_x,
|
||||
src_y, src_width, src_height), and the destination size (dst_width,
|
||||
dst_height). The contents of the source rectangle are scaled to the
|
||||
destination size, and content outside the source rectangle is ignored.
|
||||
This state is double-buffered, and is applied on the next
|
||||
wl_surface.commit.
|
||||
|
||||
The two parts of crop and scale state are independent: the source
|
||||
rectangle, and the destination size. Initially both are unset, that
|
||||
is, no scaling is applied. The whole of the current wl_buffer is
|
||||
used as the source, and the surface size is as defined in
|
||||
wl_surface.attach.
|
||||
|
||||
If the destination size is set, it causes the surface size to become
|
||||
dst_width, dst_height. The source (rectangle) is scaled to exactly
|
||||
this size. This overrides whatever the attached wl_buffer size is,
|
||||
unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
|
||||
has no content and therefore no size. Otherwise, the size is always
|
||||
at least 1x1 in surface local coordinates.
|
||||
|
||||
If the source rectangle is set, it defines what area of the wl_buffer is
|
||||
taken as the source. If the source rectangle is set and the destination
|
||||
size is not set, then src_width and src_height must be integers, and the
|
||||
surface size becomes the source rectangle size. This results in cropping
|
||||
without scaling. If src_width or src_height are not integers and
|
||||
destination size is not set, the bad_size protocol error is raised when
|
||||
the surface state is applied.
|
||||
|
||||
The coordinate transformations from buffer pixel coordinates up to
|
||||
the surface-local coordinates happen in the following order:
|
||||
1. buffer_transform (wl_surface.set_buffer_transform)
|
||||
2. buffer_scale (wl_surface.set_buffer_scale)
|
||||
3. crop and scale (wp_viewport.set*)
|
||||
This means, that the source rectangle coordinates of crop and scale
|
||||
are given in the coordinates after the buffer transform and scale,
|
||||
i.e. in the coordinates that would be the surface-local coordinates
|
||||
if the crop and scale was not applied.
|
||||
|
||||
If src_x or src_y are negative, the bad_value protocol error is raised.
|
||||
Otherwise, if the source rectangle is partially or completely outside of
|
||||
the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
|
||||
when the surface state is applied. A NULL wl_buffer does not raise the
|
||||
out_of_buffer error.
|
||||
|
||||
The x, y arguments of wl_surface.attach are applied as normal to
|
||||
the surface. They indicate how many pixels to remove from the
|
||||
surface size from the left and the top. In other words, they are
|
||||
still in the surface-local coordinate system, just like dst_width
|
||||
and dst_height are.
|
||||
|
||||
If the wl_surface associated with the wp_viewport is destroyed,
|
||||
all wp_viewport requests except 'destroy' raise the protocol error
|
||||
no_surface.
|
||||
|
||||
If the wp_viewport object is destroyed, the crop and scale
|
||||
state is removed from the wl_surface. The change will be applied
|
||||
on the next wl_surface.commit.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="remove scaling and cropping from the surface">
|
||||
The associated wl_surface's crop and scale state is removed.
|
||||
The change is applied on the next wl_surface.commit.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="bad_value" value="0"
|
||||
summary="negative or zero values in width or height"/>
|
||||
<entry name="bad_size" value="1"
|
||||
summary="destination size is not integer"/>
|
||||
<entry name="out_of_buffer" value="2"
|
||||
summary="source rectangle extends outside of the content area"/>
|
||||
<entry name="no_surface" value="3"
|
||||
summary="the wl_surface was destroyed"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_source">
|
||||
<description summary="set the source rectangle for cropping">
|
||||
Set the source rectangle of the associated wl_surface. See
|
||||
wp_viewport for the description, and relation to the wl_buffer
|
||||
size.
|
||||
|
||||
If all of x, y, width and height are -1.0, the source rectangle is
|
||||
unset instead. Any other set of values where width or height are zero
|
||||
or negative, or x or y are negative, raise the bad_value protocol
|
||||
error.
|
||||
|
||||
The crop and scale state is double-buffered state, and will be
|
||||
applied on the next wl_surface.commit.
|
||||
</description>
|
||||
<arg name="x" type="fixed" summary="source rectangle x"/>
|
||||
<arg name="y" type="fixed" summary="source rectangle y"/>
|
||||
<arg name="width" type="fixed" summary="source rectangle width"/>
|
||||
<arg name="height" type="fixed" summary="source rectangle height"/>
|
||||
</request>
|
||||
|
||||
<request name="set_destination">
|
||||
<description summary="set the surface size for scaling">
|
||||
Set the destination size of the associated wl_surface. See
|
||||
wp_viewport for the description, and relation to the wl_buffer
|
||||
size.
|
||||
|
||||
If width is -1 and height is -1, the destination size is unset
|
||||
instead. Any other pair of values for width and height that
|
||||
contains zero or negative values raises the bad_value protocol
|
||||
error.
|
||||
|
||||
The crop and scale state is double-buffered state, and will be
|
||||
applied on the next wl_surface.commit.
|
||||
</description>
|
||||
<arg name="width" type="int" summary="surface width"/>
|
||||
<arg name="height" type="int" summary="surface height"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
1044
sommelier/protocol/xdg-shell-unstable-v6.xml
Normal file
1044
sommelier/protocol/xdg-shell-unstable-v6.xml
Normal file
File diff suppressed because it is too large
Load Diff
894
sommelier/sommelier-compositor.c
Normal file
894
sommelier/sommelier-compositor.c
Normal file
@ -0,0 +1,894 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <gbm.h>
|
||||
#include <limits.h>
|
||||
#include <linux/virtwl.h>
|
||||
#include <pixman.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-util.h>
|
||||
|
||||
#include "drm-server-protocol.h"
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
#include "viewporter-client-protocol.h"
|
||||
|
||||
#define MIN_SIZE (INT_MIN / 10)
|
||||
#define MAX_SIZE (INT_MAX / 10)
|
||||
|
||||
#define DMA_BUF_SYNC_READ (1 << 0)
|
||||
#define DMA_BUF_SYNC_WRITE (2 << 0)
|
||||
#define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE)
|
||||
#define DMA_BUF_SYNC_START (0 << 2)
|
||||
#define DMA_BUF_SYNC_END (1 << 2)
|
||||
|
||||
#define DMA_BUF_BASE 'b'
|
||||
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
|
||||
|
||||
struct sl_host_region {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct wl_region* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_compositor {
|
||||
struct sl_compositor* compositor;
|
||||
struct wl_resource* resource;
|
||||
struct wl_compositor* proxy;
|
||||
};
|
||||
|
||||
struct sl_output_buffer {
|
||||
struct wl_list link;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t format;
|
||||
struct wl_buffer* internal;
|
||||
struct sl_mmap* mmap;
|
||||
struct pixman_region32 damage;
|
||||
struct sl_host_surface* surface;
|
||||
};
|
||||
|
||||
struct dma_buf_sync {
|
||||
__u64 flags;
|
||||
};
|
||||
|
||||
static void sl_dmabuf_sync(int fd, __u64 flags) {
|
||||
struct dma_buf_sync sync = {0};
|
||||
int rv;
|
||||
|
||||
sync.flags = flags;
|
||||
do {
|
||||
rv = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync);
|
||||
} while (rv == -1 && errno == EINTR);
|
||||
}
|
||||
|
||||
static void sl_dmabuf_begin_write(int fd) {
|
||||
sl_dmabuf_sync(fd, DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE);
|
||||
}
|
||||
|
||||
static void sl_dmabuf_end_write(int fd) {
|
||||
sl_dmabuf_sync(fd, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
|
||||
}
|
||||
|
||||
static void sl_virtwl_dmabuf_sync(int fd, __u32 flags) {
|
||||
struct virtwl_ioctl_dmabuf_sync sync = {0};
|
||||
int rv;
|
||||
|
||||
sync.flags = flags;
|
||||
rv = ioctl(fd, VIRTWL_IOCTL_DMABUF_SYNC, &sync);
|
||||
assert(!rv);
|
||||
UNUSED(rv);
|
||||
}
|
||||
|
||||
static void sl_virtwl_dmabuf_begin_write(int fd) {
|
||||
sl_virtwl_dmabuf_sync(fd, DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE);
|
||||
}
|
||||
|
||||
static void sl_virtwl_dmabuf_end_write(int fd) {
|
||||
sl_virtwl_dmabuf_sync(fd, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
|
||||
}
|
||||
|
||||
static uint32_t sl_gbm_format_for_shm_format(uint32_t format) {
|
||||
switch (format) {
|
||||
case WL_SHM_FORMAT_NV12:
|
||||
return GBM_FORMAT_NV12;
|
||||
case WL_SHM_FORMAT_RGB565:
|
||||
return GBM_FORMAT_RGB565;
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
return GBM_FORMAT_ARGB8888;
|
||||
case WL_SHM_FORMAT_ABGR8888:
|
||||
return GBM_FORMAT_ABGR8888;
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
return GBM_FORMAT_XRGB8888;
|
||||
case WL_SHM_FORMAT_XBGR8888:
|
||||
return GBM_FORMAT_XBGR8888;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t sl_drm_format_for_shm_format(int format) {
|
||||
switch (format) {
|
||||
case WL_SHM_FORMAT_NV12:
|
||||
return WL_DRM_FORMAT_NV12;
|
||||
case WL_SHM_FORMAT_RGB565:
|
||||
return WL_DRM_FORMAT_RGB565;
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
return WL_DRM_FORMAT_ARGB8888;
|
||||
case WL_SHM_FORMAT_ABGR8888:
|
||||
return WL_DRM_FORMAT_ABGR8888;
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
return WL_DRM_FORMAT_XRGB8888;
|
||||
case WL_SHM_FORMAT_XBGR8888:
|
||||
return WL_DRM_FORMAT_XBGR8888;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sl_output_buffer_destroy(struct sl_output_buffer* buffer) {
|
||||
wl_buffer_destroy(buffer->internal);
|
||||
sl_mmap_unref(buffer->mmap);
|
||||
pixman_region32_fini(&buffer->damage);
|
||||
wl_list_remove(&buffer->link);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void sl_output_buffer_release(void* data, struct wl_buffer* buffer) {
|
||||
struct sl_output_buffer* output_buffer = wl_buffer_get_user_data(buffer);
|
||||
struct sl_host_surface* host_surface = output_buffer->surface;
|
||||
|
||||
wl_list_remove(&output_buffer->link);
|
||||
wl_list_insert(&host_surface->released_buffers, &output_buffer->link);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener sl_output_buffer_listener = {
|
||||
sl_output_buffer_release};
|
||||
|
||||
static void sl_host_surface_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_host_surface_attach(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* buffer_resource,
|
||||
int32_t x,
|
||||
int32_t y) {
|
||||
struct sl_host_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_buffer* host_buffer =
|
||||
buffer_resource ? wl_resource_get_user_data(buffer_resource) : NULL;
|
||||
struct wl_buffer* buffer_proxy = NULL;
|
||||
struct sl_window* window;
|
||||
double scale = host->ctx->scale;
|
||||
|
||||
host->current_buffer = NULL;
|
||||
if (host->contents_shm_mmap) {
|
||||
sl_mmap_unref(host->contents_shm_mmap);
|
||||
host->contents_shm_mmap = NULL;
|
||||
}
|
||||
|
||||
if (host_buffer) {
|
||||
host->contents_width = host_buffer->width;
|
||||
host->contents_height = host_buffer->height;
|
||||
buffer_proxy = host_buffer->proxy;
|
||||
if (host_buffer->shm_mmap)
|
||||
host->contents_shm_mmap = sl_mmap_ref(host_buffer->shm_mmap);
|
||||
}
|
||||
|
||||
if (host->contents_shm_mmap) {
|
||||
while (!wl_list_empty(&host->released_buffers)) {
|
||||
host->current_buffer = wl_container_of(host->released_buffers.next,
|
||||
host->current_buffer, link);
|
||||
|
||||
if (host->current_buffer->width == host_buffer->width &&
|
||||
host->current_buffer->height == host_buffer->height &&
|
||||
host->current_buffer->format == host_buffer->shm_format) {
|
||||
break;
|
||||
}
|
||||
|
||||
sl_output_buffer_destroy(host->current_buffer);
|
||||
host->current_buffer = NULL;
|
||||
}
|
||||
|
||||
// Allocate new output buffer.
|
||||
if (!host->current_buffer) {
|
||||
size_t width = host_buffer->width;
|
||||
size_t height = host_buffer->height;
|
||||
uint32_t shm_format = host_buffer->shm_format;
|
||||
size_t bpp = sl_shm_bpp_for_shm_format(shm_format);
|
||||
size_t num_planes = sl_shm_num_planes_for_shm_format(shm_format);
|
||||
|
||||
host->current_buffer = malloc(sizeof(struct sl_output_buffer));
|
||||
assert(host->current_buffer);
|
||||
wl_list_insert(&host->released_buffers, &host->current_buffer->link);
|
||||
host->current_buffer->width = width;
|
||||
host->current_buffer->height = height;
|
||||
host->current_buffer->format = shm_format;
|
||||
host->current_buffer->surface = host;
|
||||
pixman_region32_init_rect(&host->current_buffer->damage, 0, 0, MAX_SIZE,
|
||||
MAX_SIZE);
|
||||
|
||||
switch (host->ctx->shm_driver) {
|
||||
case SHM_DRIVER_DMABUF: {
|
||||
struct zwp_linux_buffer_params_v1* buffer_params;
|
||||
struct gbm_bo* bo;
|
||||
int stride0;
|
||||
int fd;
|
||||
|
||||
bo = gbm_bo_create(host->ctx->gbm, width, height,
|
||||
sl_gbm_format_for_shm_format(shm_format),
|
||||
GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR);
|
||||
stride0 = gbm_bo_get_stride(bo);
|
||||
fd = gbm_bo_get_fd(bo);
|
||||
|
||||
buffer_params = zwp_linux_dmabuf_v1_create_params(
|
||||
host->ctx->linux_dmabuf->internal);
|
||||
zwp_linux_buffer_params_v1_add(buffer_params, fd, 0, 0, stride0, 0,
|
||||
0);
|
||||
host->current_buffer->internal =
|
||||
zwp_linux_buffer_params_v1_create_immed(
|
||||
buffer_params, width, height,
|
||||
sl_drm_format_for_shm_format(shm_format), 0);
|
||||
zwp_linux_buffer_params_v1_destroy(buffer_params);
|
||||
|
||||
host->current_buffer->mmap = sl_mmap_create(
|
||||
fd, height * stride0, bpp, 1, 0, stride0, 0, 0, 1, 0);
|
||||
host->current_buffer->mmap->begin_write = sl_dmabuf_begin_write;
|
||||
host->current_buffer->mmap->end_write = sl_dmabuf_end_write;
|
||||
|
||||
gbm_bo_destroy(bo);
|
||||
} break;
|
||||
case SHM_DRIVER_VIRTWL: {
|
||||
size_t size = host_buffer->shm_mmap->size;
|
||||
struct virtwl_ioctl_new ioctl_new = {.type = VIRTWL_IOCTL_NEW_ALLOC,
|
||||
.fd = -1,
|
||||
.flags = 0,
|
||||
.size = size};
|
||||
struct wl_shm_pool* pool;
|
||||
int rv;
|
||||
|
||||
rv = ioctl(host->ctx->virtwl_fd, VIRTWL_IOCTL_NEW, &ioctl_new);
|
||||
assert(rv == 0);
|
||||
UNUSED(rv);
|
||||
|
||||
pool =
|
||||
wl_shm_create_pool(host->ctx->shm->internal, ioctl_new.fd, size);
|
||||
host->current_buffer->internal = wl_shm_pool_create_buffer(
|
||||
pool, 0, width, height, host_buffer->shm_mmap->stride[0],
|
||||
shm_format);
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
host->current_buffer->mmap = sl_mmap_create(
|
||||
ioctl_new.fd, size, bpp, num_planes, 0,
|
||||
host_buffer->shm_mmap->stride[0],
|
||||
host_buffer->shm_mmap->offset[1] -
|
||||
host_buffer->shm_mmap->offset[0],
|
||||
host_buffer->shm_mmap->stride[1], host_buffer->shm_mmap->y_ss[0],
|
||||
host_buffer->shm_mmap->y_ss[1]);
|
||||
} break;
|
||||
case SHM_DRIVER_VIRTWL_DMABUF: {
|
||||
uint32_t drm_format = sl_drm_format_for_shm_format(shm_format);
|
||||
struct virtwl_ioctl_new ioctl_new = {
|
||||
.type = VIRTWL_IOCTL_NEW_DMABUF,
|
||||
.fd = -1,
|
||||
.flags = 0,
|
||||
.dmabuf = {
|
||||
.width = width, .height = height, .format = drm_format}};
|
||||
struct zwp_linux_buffer_params_v1* buffer_params;
|
||||
size_t size;
|
||||
int rv;
|
||||
|
||||
rv = ioctl(host->ctx->virtwl_fd, VIRTWL_IOCTL_NEW, &ioctl_new);
|
||||
if (rv) {
|
||||
fprintf(stderr, "error: virtwl dmabuf allocation failed: %s\n",
|
||||
strerror(errno));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
size = ioctl_new.dmabuf.stride0 * height;
|
||||
buffer_params = zwp_linux_dmabuf_v1_create_params(
|
||||
host->ctx->linux_dmabuf->internal);
|
||||
zwp_linux_buffer_params_v1_add(buffer_params, ioctl_new.fd, 0,
|
||||
ioctl_new.dmabuf.offset0,
|
||||
ioctl_new.dmabuf.stride0, 0, 0);
|
||||
if (num_planes > 1) {
|
||||
zwp_linux_buffer_params_v1_add(buffer_params, ioctl_new.fd, 1,
|
||||
ioctl_new.dmabuf.offset1,
|
||||
ioctl_new.dmabuf.stride1, 0, 0);
|
||||
size = MAX(size, ioctl_new.dmabuf.offset1 +
|
||||
ioctl_new.dmabuf.stride1 * height /
|
||||
host_buffer->shm_mmap->y_ss[1]);
|
||||
}
|
||||
host->current_buffer->internal =
|
||||
zwp_linux_buffer_params_v1_create_immed(buffer_params, width,
|
||||
height, drm_format, 0);
|
||||
zwp_linux_buffer_params_v1_destroy(buffer_params);
|
||||
|
||||
host->current_buffer->mmap = sl_mmap_create(
|
||||
ioctl_new.fd, size, bpp, num_planes, ioctl_new.dmabuf.offset0,
|
||||
ioctl_new.dmabuf.stride0, ioctl_new.dmabuf.offset1,
|
||||
ioctl_new.dmabuf.stride1, host_buffer->shm_mmap->y_ss[0],
|
||||
host_buffer->shm_mmap->y_ss[1]);
|
||||
host->current_buffer->mmap->begin_write =
|
||||
sl_virtwl_dmabuf_begin_write;
|
||||
host->current_buffer->mmap->end_write = sl_virtwl_dmabuf_end_write;
|
||||
} break;
|
||||
}
|
||||
|
||||
assert(host->current_buffer->internal);
|
||||
assert(host->current_buffer->mmap);
|
||||
|
||||
wl_buffer_set_user_data(host->current_buffer->internal,
|
||||
host->current_buffer);
|
||||
wl_buffer_add_listener(host->current_buffer->internal,
|
||||
&sl_output_buffer_listener, host->current_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
x /= scale;
|
||||
y /= scale;
|
||||
|
||||
// TODO(davidriley): This should be done in the commit.
|
||||
if (host_buffer && host_buffer->sync_point) {
|
||||
host_buffer->sync_point->sync(host->ctx, host_buffer->sync_point);
|
||||
}
|
||||
|
||||
if (host->current_buffer) {
|
||||
assert(host->current_buffer->internal);
|
||||
wl_surface_attach(host->proxy, host->current_buffer->internal, x, y);
|
||||
} else {
|
||||
wl_surface_attach(host->proxy, buffer_proxy, x, y);
|
||||
}
|
||||
|
||||
wl_list_for_each(window, &host->ctx->windows, link) {
|
||||
if (window->host_surface_id == wl_resource_get_id(resource)) {
|
||||
while (sl_process_pending_configure_acks(window, host))
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_host_surface_damage(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_surface* host = wl_resource_get_user_data(resource);
|
||||
double scale = host->ctx->scale;
|
||||
struct sl_output_buffer* buffer;
|
||||
int64_t x1, y1, x2, y2;
|
||||
|
||||
wl_list_for_each(buffer, &host->busy_buffers, link) {
|
||||
pixman_region32_union_rect(&buffer->damage, &buffer->damage, x, y, width,
|
||||
height);
|
||||
}
|
||||
wl_list_for_each(buffer, &host->released_buffers, link) {
|
||||
pixman_region32_union_rect(&buffer->damage, &buffer->damage, x, y, width,
|
||||
height);
|
||||
}
|
||||
|
||||
x1 = x;
|
||||
y1 = y;
|
||||
x2 = x1 + width;
|
||||
y2 = y1 + height;
|
||||
|
||||
// Enclosing rect after scaling and outset by one pixel to account for
|
||||
// potential filtering.
|
||||
x1 = MAX(MIN_SIZE, x1 - 1) / scale;
|
||||
y1 = MAX(MIN_SIZE, y1 - 1) / scale;
|
||||
x2 = ceil(MIN(x2 + 1, MAX_SIZE) / scale);
|
||||
y2 = ceil(MIN(y2 + 1, MAX_SIZE) / scale);
|
||||
|
||||
wl_surface_damage(host->proxy, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
static void sl_frame_callback_done(void* data,
|
||||
struct wl_callback* callback,
|
||||
uint32_t time) {
|
||||
struct sl_host_callback* host = wl_callback_get_user_data(callback);
|
||||
|
||||
wl_callback_send_done(host->resource, time);
|
||||
wl_resource_destroy(host->resource);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener sl_frame_callback_listener = {
|
||||
sl_frame_callback_done};
|
||||
|
||||
static void sl_host_callback_destroy(struct wl_resource* resource) {
|
||||
struct sl_host_callback* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_callback_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_host_surface_frame(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t callback) {
|
||||
struct sl_host_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_callback* host_callback;
|
||||
|
||||
host_callback = malloc(sizeof(*host_callback));
|
||||
assert(host_callback);
|
||||
|
||||
host_callback->resource =
|
||||
wl_resource_create(client, &wl_callback_interface, 1, callback);
|
||||
wl_resource_set_implementation(host_callback->resource, NULL, host_callback,
|
||||
sl_host_callback_destroy);
|
||||
host_callback->proxy = wl_surface_frame(host->proxy);
|
||||
wl_callback_set_user_data(host_callback->proxy, host_callback);
|
||||
wl_callback_add_listener(host_callback->proxy, &sl_frame_callback_listener,
|
||||
host_callback);
|
||||
}
|
||||
|
||||
static void sl_host_surface_set_opaque_region(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* region_resource) {
|
||||
struct sl_host_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_region* host_region =
|
||||
region_resource ? wl_resource_get_user_data(region_resource) : NULL;
|
||||
|
||||
wl_surface_set_opaque_region(host->proxy,
|
||||
host_region ? host_region->proxy : NULL);
|
||||
}
|
||||
|
||||
static void sl_host_surface_set_input_region(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* region_resource) {
|
||||
struct sl_host_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_region* host_region =
|
||||
region_resource ? wl_resource_get_user_data(region_resource) : NULL;
|
||||
|
||||
wl_surface_set_input_region(host->proxy,
|
||||
host_region ? host_region->proxy : NULL);
|
||||
}
|
||||
|
||||
static void sl_host_surface_commit(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_viewport* viewport = NULL;
|
||||
struct sl_window* window;
|
||||
|
||||
if (!wl_list_empty(&host->contents_viewport))
|
||||
viewport = wl_container_of(host->contents_viewport.next, viewport, link);
|
||||
|
||||
if (host->contents_shm_mmap) {
|
||||
uint8_t* src_addr = host->contents_shm_mmap->addr;
|
||||
uint8_t* dst_addr = host->current_buffer->mmap->addr;
|
||||
size_t* src_offset = host->contents_shm_mmap->offset;
|
||||
size_t* dst_offset = host->current_buffer->mmap->offset;
|
||||
size_t* src_stride = host->contents_shm_mmap->stride;
|
||||
size_t* dst_stride = host->current_buffer->mmap->stride;
|
||||
size_t* y_ss = host->contents_shm_mmap->y_ss;
|
||||
size_t bpp = host->contents_shm_mmap->bpp;
|
||||
size_t num_planes = host->contents_shm_mmap->num_planes;
|
||||
double contents_scale_x = host->contents_scale;
|
||||
double contents_scale_y = host->contents_scale;
|
||||
double contents_offset_x = 0.0;
|
||||
double contents_offset_y = 0.0;
|
||||
pixman_box32_t* rect;
|
||||
int n;
|
||||
|
||||
// Determine scale and offset for damage based on current viewport.
|
||||
if (viewport) {
|
||||
double contents_width = host->contents_width;
|
||||
double contents_height = host->contents_height;
|
||||
|
||||
if (viewport->src_x >= 0 && viewport->src_y >= 0) {
|
||||
contents_offset_x = wl_fixed_to_double(viewport->src_x);
|
||||
contents_offset_y = wl_fixed_to_double(viewport->src_y);
|
||||
}
|
||||
|
||||
if (viewport->dst_width > 0 && viewport->dst_height > 0) {
|
||||
contents_scale_x *= contents_width / viewport->dst_width;
|
||||
contents_scale_y *= contents_height / viewport->dst_height;
|
||||
|
||||
// Take source rectangle into account when both destionation size and
|
||||
// source rectangle are set. If only source rectangle is set, then
|
||||
// it determines the surface size so it can be ignored.
|
||||
if (viewport->src_width >= 0 && viewport->src_height >= 0) {
|
||||
contents_scale_x *=
|
||||
wl_fixed_to_double(viewport->src_width) / contents_width;
|
||||
contents_scale_y *=
|
||||
wl_fixed_to_double(viewport->src_height) / contents_height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (host->current_buffer->mmap->begin_write)
|
||||
host->current_buffer->mmap->begin_write(host->current_buffer->mmap->fd);
|
||||
|
||||
rect = pixman_region32_rectangles(&host->current_buffer->damage, &n);
|
||||
while (n--) {
|
||||
int32_t x1, y1, x2, y2;
|
||||
|
||||
// Enclosing rect after applying scale and offset.
|
||||
x1 = rect->x1 * contents_scale_x + contents_offset_x;
|
||||
y1 = rect->y1 * contents_scale_y + contents_offset_y;
|
||||
x2 = rect->x2 * contents_scale_x + contents_offset_x + 0.5;
|
||||
y2 = rect->y2 * contents_scale_y + contents_offset_y + 0.5;
|
||||
|
||||
x1 = MAX(0, x1);
|
||||
y1 = MAX(0, y1);
|
||||
x2 = MIN(host->contents_width, x2);
|
||||
y2 = MIN(host->contents_height, y2);
|
||||
|
||||
if (x1 < x2 && y1 < y2) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < num_planes; ++i) {
|
||||
uint8_t* src_base = src_addr + src_offset[i];
|
||||
uint8_t* dst_base = dst_addr + dst_offset[i];
|
||||
uint8_t* src = src_base + y1 * src_stride[i] + x1 * bpp;
|
||||
uint8_t* dst = dst_base + y1 * dst_stride[i] + x1 * bpp;
|
||||
int32_t width = x2 - x1;
|
||||
int32_t height = (y2 - y1) / y_ss[i];
|
||||
size_t bytes = width * bpp;
|
||||
|
||||
while (height--) {
|
||||
memcpy(dst, src, bytes);
|
||||
dst += dst_stride[i];
|
||||
src += src_stride[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++rect;
|
||||
}
|
||||
|
||||
if (host->current_buffer->mmap->end_write)
|
||||
host->current_buffer->mmap->end_write(host->current_buffer->mmap->fd);
|
||||
|
||||
pixman_region32_clear(&host->current_buffer->damage);
|
||||
|
||||
wl_list_remove(&host->current_buffer->link);
|
||||
wl_list_insert(&host->busy_buffers, &host->current_buffer->link);
|
||||
}
|
||||
|
||||
if (host->contents_width && host->contents_height) {
|
||||
double scale = host->ctx->scale * host->contents_scale;
|
||||
|
||||
if (host->viewport) {
|
||||
int width = host->contents_width;
|
||||
int height = host->contents_height;
|
||||
|
||||
// We need to take the client's viewport into account while still
|
||||
// making sure our scale is accounted for.
|
||||
if (viewport) {
|
||||
if (viewport->src_x >= 0 && viewport->src_y >= 0 &&
|
||||
viewport->src_width >= 0 && viewport->src_height >= 0) {
|
||||
wp_viewport_set_source(host->viewport, viewport->src_x,
|
||||
viewport->src_y, viewport->src_width,
|
||||
viewport->src_height);
|
||||
|
||||
// If the source rectangle is set and the destination size is not
|
||||
// set, then src_width and src_height should be integers, and the
|
||||
// surface size becomes the source rectangle size.
|
||||
width = wl_fixed_to_int(viewport->src_width);
|
||||
height = wl_fixed_to_int(viewport->src_height);
|
||||
}
|
||||
|
||||
// Use destination size as surface size when set.
|
||||
if (viewport->dst_width >= 0 && viewport->dst_height >= 0) {
|
||||
width = viewport->dst_width;
|
||||
height = viewport->dst_height;
|
||||
}
|
||||
}
|
||||
|
||||
wp_viewport_set_destination(host->viewport, ceil(width / scale),
|
||||
ceil(height / scale));
|
||||
} else {
|
||||
wl_surface_set_buffer_scale(host->proxy, scale);
|
||||
}
|
||||
}
|
||||
|
||||
// No need to defer client commits if surface has a role. E.g. is a cursor
|
||||
// or shell surface.
|
||||
if (host->has_role) {
|
||||
wl_surface_commit(host->proxy);
|
||||
|
||||
// GTK determines the scale based on the output the surface has entered.
|
||||
// If the surface has not entered any output, then have it enter the
|
||||
// internal output. TODO(reveman): Remove this when surface-output tracking
|
||||
// has been implemented in Chrome.
|
||||
if (!host->has_output) {
|
||||
struct sl_host_output* output;
|
||||
|
||||
wl_list_for_each(output, &host->ctx->host_outputs, link) {
|
||||
if (output->internal) {
|
||||
wl_surface_send_enter(host->resource, output->resource);
|
||||
host->has_output = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Commit if surface is associated with a window. Otherwise, defer
|
||||
// commit until window is created.
|
||||
wl_list_for_each(window, &host->ctx->windows, link) {
|
||||
if (window->host_surface_id == wl_resource_get_id(resource)) {
|
||||
if (window->xdg_surface) {
|
||||
wl_surface_commit(host->proxy);
|
||||
if (host->contents_width && host->contents_height)
|
||||
window->realized = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (host->contents_shm_mmap) {
|
||||
if (host->contents_shm_mmap->buffer_resource)
|
||||
wl_buffer_send_release(host->contents_shm_mmap->buffer_resource);
|
||||
sl_mmap_unref(host->contents_shm_mmap);
|
||||
host->contents_shm_mmap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_host_surface_set_buffer_transform(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t transform) {
|
||||
struct sl_host_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_surface_set_buffer_transform(host->proxy, transform);
|
||||
}
|
||||
|
||||
static void sl_host_surface_set_buffer_scale(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t scale) {
|
||||
struct sl_host_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
host->contents_scale = scale;
|
||||
}
|
||||
|
||||
static void sl_host_surface_damage_buffer(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static const struct wl_surface_interface sl_surface_implementation = {
|
||||
sl_host_surface_destroy,
|
||||
sl_host_surface_attach,
|
||||
sl_host_surface_damage,
|
||||
sl_host_surface_frame,
|
||||
sl_host_surface_set_opaque_region,
|
||||
sl_host_surface_set_input_region,
|
||||
sl_host_surface_commit,
|
||||
sl_host_surface_set_buffer_transform,
|
||||
sl_host_surface_set_buffer_scale,
|
||||
sl_host_surface_damage_buffer};
|
||||
|
||||
static void sl_destroy_host_surface(struct wl_resource* resource) {
|
||||
struct sl_host_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_window *window, *surface_window = NULL;
|
||||
struct sl_output_buffer* buffer;
|
||||
|
||||
wl_list_for_each(window, &host->ctx->windows, link) {
|
||||
if (window->host_surface_id == wl_resource_get_id(resource)) {
|
||||
surface_window = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (surface_window) {
|
||||
surface_window->host_surface_id = 0;
|
||||
sl_window_update(surface_window);
|
||||
}
|
||||
|
||||
if (host->contents_shm_mmap)
|
||||
sl_mmap_unref(host->contents_shm_mmap);
|
||||
|
||||
while (!wl_list_empty(&host->released_buffers)) {
|
||||
buffer = wl_container_of(host->released_buffers.next, buffer, link);
|
||||
sl_output_buffer_destroy(buffer);
|
||||
}
|
||||
while (!wl_list_empty(&host->busy_buffers)) {
|
||||
buffer = wl_container_of(host->busy_buffers.next, buffer, link);
|
||||
sl_output_buffer_destroy(buffer);
|
||||
}
|
||||
while (!wl_list_empty(&host->contents_viewport))
|
||||
wl_list_remove(host->contents_viewport.next);
|
||||
|
||||
if (host->viewport)
|
||||
wp_viewport_destroy(host->viewport);
|
||||
wl_surface_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_surface_enter(void* data,
|
||||
struct wl_surface* surface,
|
||||
struct wl_output* output) {
|
||||
struct sl_host_surface* host = wl_surface_get_user_data(surface);
|
||||
struct sl_host_output* host_output = wl_output_get_user_data(output);
|
||||
|
||||
wl_surface_send_enter(host->resource, host_output->resource);
|
||||
host->has_output = 1;
|
||||
}
|
||||
|
||||
static void sl_surface_leave(void* data,
|
||||
struct wl_surface* surface,
|
||||
struct wl_output* output) {
|
||||
struct sl_host_surface* host = wl_surface_get_user_data(surface);
|
||||
struct sl_host_output* host_output = wl_output_get_user_data(output);
|
||||
|
||||
wl_surface_send_leave(host->resource, host_output->resource);
|
||||
}
|
||||
|
||||
static const struct wl_surface_listener sl_surface_listener = {
|
||||
sl_surface_enter, sl_surface_leave};
|
||||
|
||||
static void sl_region_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_region_add(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_region* host = wl_resource_get_user_data(resource);
|
||||
double scale = host->ctx->scale;
|
||||
int32_t x1, y1, x2, y2;
|
||||
|
||||
x1 = x / scale;
|
||||
y1 = y / scale;
|
||||
x2 = (x + width) / scale;
|
||||
y2 = (y + height) / scale;
|
||||
|
||||
wl_region_add(host->proxy, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
static void sl_region_subtract(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_region* host = wl_resource_get_user_data(resource);
|
||||
double scale = host->ctx->scale;
|
||||
int32_t x1, y1, x2, y2;
|
||||
|
||||
x1 = x / scale;
|
||||
y1 = y / scale;
|
||||
x2 = (x + width) / scale;
|
||||
y2 = (y + height) / scale;
|
||||
|
||||
wl_region_subtract(host->proxy, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
static const struct wl_region_interface sl_region_implementation = {
|
||||
sl_region_destroy, sl_region_add, sl_region_subtract};
|
||||
|
||||
static void sl_destroy_host_region(struct wl_resource* resource) {
|
||||
struct sl_host_region* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_region_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_compositor_create_host_surface(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id) {
|
||||
struct sl_host_compositor* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_surface* host_surface;
|
||||
struct sl_window *window, *unpaired_window = NULL;
|
||||
|
||||
host_surface = malloc(sizeof(*host_surface));
|
||||
assert(host_surface);
|
||||
|
||||
host_surface->ctx = host->compositor->ctx;
|
||||
host_surface->contents_width = 0;
|
||||
host_surface->contents_height = 0;
|
||||
host_surface->contents_scale = 1;
|
||||
wl_list_init(&host_surface->contents_viewport);
|
||||
host_surface->contents_shm_mmap = NULL;
|
||||
host_surface->has_role = 0;
|
||||
host_surface->has_output = 0;
|
||||
host_surface->last_event_serial = 0;
|
||||
host_surface->current_buffer = NULL;
|
||||
wl_list_init(&host_surface->released_buffers);
|
||||
wl_list_init(&host_surface->busy_buffers);
|
||||
host_surface->resource = wl_resource_create(
|
||||
client, &wl_surface_interface, wl_resource_get_version(resource), id);
|
||||
wl_resource_set_implementation(host_surface->resource,
|
||||
&sl_surface_implementation, host_surface,
|
||||
sl_destroy_host_surface);
|
||||
host_surface->proxy = wl_compositor_create_surface(host->proxy);
|
||||
wl_surface_set_user_data(host_surface->proxy, host_surface);
|
||||
wl_surface_add_listener(host_surface->proxy, &sl_surface_listener,
|
||||
host_surface);
|
||||
host_surface->viewport = NULL;
|
||||
if (host_surface->ctx->viewporter) {
|
||||
host_surface->viewport = wp_viewporter_get_viewport(
|
||||
host_surface->ctx->viewporter->internal, host_surface->proxy);
|
||||
}
|
||||
|
||||
wl_list_for_each(window, &host->compositor->ctx->unpaired_windows, link) {
|
||||
if (window->host_surface_id == id) {
|
||||
unpaired_window = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unpaired_window)
|
||||
sl_window_update(window);
|
||||
}
|
||||
|
||||
static void sl_compositor_create_host_region(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id) {
|
||||
struct sl_host_compositor* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_region* host_region;
|
||||
|
||||
host_region = malloc(sizeof(*host_region));
|
||||
assert(host_region);
|
||||
|
||||
host_region->ctx = host->compositor->ctx;
|
||||
host_region->resource = wl_resource_create(
|
||||
client, &wl_region_interface, wl_resource_get_version(resource), id);
|
||||
wl_resource_set_implementation(host_region->resource,
|
||||
&sl_region_implementation, host_region,
|
||||
sl_destroy_host_region);
|
||||
host_region->proxy = wl_compositor_create_region(host->proxy);
|
||||
wl_region_set_user_data(host_region->proxy, host_region);
|
||||
}
|
||||
|
||||
static const struct wl_compositor_interface sl_compositor_implementation = {
|
||||
sl_compositor_create_host_surface, sl_compositor_create_host_region};
|
||||
|
||||
static void sl_destroy_host_compositor(struct wl_resource* resource) {
|
||||
struct sl_host_compositor* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_compositor_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_bind_host_compositor(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_host_compositor* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->compositor = ctx->compositor;
|
||||
host->resource =
|
||||
wl_resource_create(client, &wl_compositor_interface,
|
||||
MIN(version, ctx->compositor->version), id);
|
||||
wl_resource_set_implementation(host->resource, &sl_compositor_implementation,
|
||||
host, sl_destroy_host_compositor);
|
||||
host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display),
|
||||
ctx->compositor->id, &wl_compositor_interface,
|
||||
ctx->compositor->version);
|
||||
wl_compositor_set_user_data(host->proxy, host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_compositor_global_create(struct sl_context* ctx) {
|
||||
return sl_global_create(ctx, &wl_compositor_interface,
|
||||
ctx->compositor->version, ctx,
|
||||
sl_bind_host_compositor);
|
||||
}
|
580
sommelier/sommelier-data-device-manager.c
Normal file
580
sommelier/sommelier-data-device-manager.c
Normal file
@ -0,0 +1,580 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/virtwl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
struct sl_host_data_device_manager {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct wl_data_device_manager* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_data_device {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct wl_data_device* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_data_source {
|
||||
struct wl_resource* resource;
|
||||
struct wl_data_source* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_data_offer {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct wl_data_offer* proxy;
|
||||
};
|
||||
|
||||
struct sl_data_transfer {
|
||||
int read_fd;
|
||||
int write_fd;
|
||||
size_t offset;
|
||||
size_t bytes_left;
|
||||
uint8_t data[4096];
|
||||
struct wl_event_source* read_event_source;
|
||||
struct wl_event_source* write_event_source;
|
||||
};
|
||||
|
||||
static void sl_data_transfer_destroy(struct sl_data_transfer* transfer) {
|
||||
assert(transfer->read_event_source);
|
||||
wl_event_source_remove(transfer->read_event_source);
|
||||
assert(transfer->write_event_source);
|
||||
wl_event_source_remove(transfer->write_event_source);
|
||||
close(transfer->read_fd);
|
||||
close(transfer->write_fd);
|
||||
free(transfer);
|
||||
}
|
||||
|
||||
static int sl_handle_data_transfer_read(int fd, uint32_t mask, void* data) {
|
||||
struct sl_data_transfer* transfer = (struct sl_data_transfer*)data;
|
||||
if ((mask & WL_EVENT_READABLE) == 0) {
|
||||
assert(mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR));
|
||||
|
||||
// Epoll (and therefore wl_event_loop) will notify listeners of errors and
|
||||
// hangups even if all other events are disabled. Therefore, at this point,
|
||||
// we don't know whether we didn't get a readable event because the fd has
|
||||
// been exhausted, or because we aren't in the reading state and weren't
|
||||
// listening for one. We can make the distinction be checking if there's any
|
||||
// data left in the buffer. If there is, then we are just waiting for the
|
||||
// writing to finish, otherwise end the transfer.
|
||||
|
||||
// In the case of an error, where there is not likely to be any more data to
|
||||
// read, we still want to wait for any data we did get to be written out.
|
||||
if (!transfer->bytes_left) {
|
||||
sl_data_transfer_destroy(transfer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// At this point we must be in the reading state.
|
||||
assert(!transfer->bytes_left);
|
||||
|
||||
transfer->bytes_left =
|
||||
read(transfer->read_fd, transfer->data, sizeof(transfer->data));
|
||||
if (transfer->bytes_left > 0) {
|
||||
transfer->offset = 0;
|
||||
// There may still be data to read from the event source, but we have no
|
||||
// room in our buffer so move to the writing state.
|
||||
wl_event_source_fd_update(transfer->read_event_source, 0);
|
||||
wl_event_source_fd_update(transfer->write_event_source, WL_EVENT_WRITABLE);
|
||||
} else {
|
||||
// On a read error or EOF, end the transfer.
|
||||
sl_data_transfer_destroy(transfer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sl_handle_data_transfer_write(int fd, uint32_t mask, void* data) {
|
||||
struct sl_data_transfer* transfer = (struct sl_data_transfer*)data;
|
||||
int rv;
|
||||
|
||||
// If we receive a HANGUP or ERROR event on the write source then there is no
|
||||
// point in continuing the transfer. We could still read more data, but we
|
||||
// couldn't send it to the recipient, so just destroy the transfer now.
|
||||
if ((mask & WL_EVENT_WRITABLE) == 0) {
|
||||
assert(mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR));
|
||||
sl_data_transfer_destroy(transfer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// At this point we must be in the writing state.
|
||||
assert(transfer->bytes_left);
|
||||
|
||||
rv = write(transfer->write_fd, transfer->data + transfer->offset,
|
||||
transfer->bytes_left);
|
||||
|
||||
if (rv < 0) {
|
||||
// On a write error, end the transfer.
|
||||
sl_data_transfer_destroy(transfer);
|
||||
} else {
|
||||
assert(rv <= transfer->bytes_left);
|
||||
transfer->bytes_left -= rv;
|
||||
transfer->offset += rv;
|
||||
}
|
||||
|
||||
if (!transfer->bytes_left) {
|
||||
// If all data has been written, move back to the reading state.
|
||||
wl_event_source_fd_update(transfer->write_event_source, 0);
|
||||
wl_event_source_fd_update(transfer->read_event_source, WL_EVENT_READABLE);
|
||||
}
|
||||
|
||||
// If there is still data left, continue in the writing state.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sl_data_transfer_create(struct wl_event_loop* event_loop,
|
||||
int read_fd,
|
||||
int write_fd) {
|
||||
struct sl_data_transfer* transfer;
|
||||
int flags;
|
||||
int rv;
|
||||
|
||||
flags = fcntl(write_fd, F_GETFL, 0);
|
||||
rv = fcntl(write_fd, F_SETFL, flags | O_NONBLOCK);
|
||||
assert(!rv);
|
||||
UNUSED(rv);
|
||||
|
||||
// Start out the transfer in the reading state.
|
||||
transfer = malloc(sizeof(*transfer));
|
||||
assert(transfer);
|
||||
transfer->read_fd = read_fd;
|
||||
transfer->write_fd = write_fd;
|
||||
transfer->offset = 0;
|
||||
transfer->bytes_left = 0;
|
||||
transfer->read_event_source =
|
||||
wl_event_loop_add_fd(event_loop, read_fd, WL_EVENT_READABLE,
|
||||
sl_handle_data_transfer_read, transfer);
|
||||
transfer->write_event_source = wl_event_loop_add_fd(
|
||||
event_loop, write_fd, 0, sl_handle_data_transfer_write, transfer);
|
||||
}
|
||||
|
||||
static void sl_data_offer_accept(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t serial,
|
||||
const char* mime_type) {
|
||||
struct sl_host_data_offer* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_data_offer_accept(host->proxy, serial, mime_type);
|
||||
}
|
||||
|
||||
static void sl_data_offer_receive(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
const char* mime_type,
|
||||
int32_t fd) {
|
||||
struct sl_host_data_offer* host = wl_resource_get_user_data(resource);
|
||||
|
||||
switch (host->ctx->data_driver) {
|
||||
case DATA_DRIVER_VIRTWL: {
|
||||
struct virtwl_ioctl_new new_pipe = {
|
||||
.type = VIRTWL_IOCTL_NEW_PIPE_READ,
|
||||
.fd = -1,
|
||||
.flags = 0,
|
||||
.size = 0,
|
||||
};
|
||||
int rv;
|
||||
|
||||
rv = ioctl(host->ctx->virtwl_fd, VIRTWL_IOCTL_NEW, &new_pipe);
|
||||
if (rv) {
|
||||
fprintf(stderr, "error: failed to create virtwl pipe: %s\n",
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
sl_data_transfer_create(
|
||||
wl_display_get_event_loop(host->ctx->host_display), new_pipe.fd, fd);
|
||||
|
||||
wl_data_offer_receive(host->proxy, mime_type, new_pipe.fd);
|
||||
} break;
|
||||
case DATA_DRIVER_NOOP:
|
||||
wl_data_offer_receive(host->proxy, mime_type, fd);
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_data_offer_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_data_offer_finish(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_data_offer* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_data_offer_finish(host->proxy);
|
||||
}
|
||||
|
||||
static void sl_data_offer_set_actions(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t dnd_actions,
|
||||
uint32_t preferred_action) {
|
||||
struct sl_host_data_offer* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_data_offer_set_actions(host->proxy, dnd_actions, preferred_action);
|
||||
}
|
||||
|
||||
static const struct wl_data_offer_interface sl_data_offer_implementation = {
|
||||
sl_data_offer_accept, sl_data_offer_receive, sl_data_offer_destroy,
|
||||
sl_data_offer_finish, sl_data_offer_set_actions};
|
||||
|
||||
static void sl_data_offer_offer(void* data,
|
||||
struct wl_data_offer* data_offer,
|
||||
const char* mime_type) {
|
||||
struct sl_host_data_offer* host = wl_data_offer_get_user_data(data_offer);
|
||||
|
||||
wl_data_offer_send_offer(host->resource, mime_type);
|
||||
}
|
||||
|
||||
static void sl_data_offer_source_actions(void* data,
|
||||
struct wl_data_offer* data_offer,
|
||||
uint32_t source_actions) {
|
||||
struct sl_host_data_offer* host = wl_data_offer_get_user_data(data_offer);
|
||||
|
||||
wl_data_offer_send_source_actions(host->resource, source_actions);
|
||||
}
|
||||
|
||||
static void sl_data_offer_action(void* data,
|
||||
struct wl_data_offer* data_offer,
|
||||
uint32_t dnd_action) {
|
||||
struct sl_host_data_offer* host = wl_data_offer_get_user_data(data_offer);
|
||||
|
||||
wl_data_offer_send_action(host->resource, dnd_action);
|
||||
}
|
||||
|
||||
static const struct wl_data_offer_listener sl_data_offer_listener = {
|
||||
sl_data_offer_offer, sl_data_offer_source_actions, sl_data_offer_action};
|
||||
|
||||
static void sl_destroy_host_data_offer(struct wl_resource* resource) {
|
||||
struct sl_host_data_offer* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_data_offer_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_data_source_offer(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
const char* mime_type) {
|
||||
struct sl_host_data_source* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_data_source_offer(host->proxy, mime_type);
|
||||
}
|
||||
|
||||
static void sl_data_source_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_data_source_set_actions(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t dnd_actions) {
|
||||
struct sl_host_data_source* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_data_source_set_actions(host->proxy, dnd_actions);
|
||||
}
|
||||
|
||||
static const struct wl_data_source_interface sl_data_source_implementation = {
|
||||
sl_data_source_offer, sl_data_source_destroy, sl_data_source_set_actions};
|
||||
|
||||
static void sl_data_source_target(void* data,
|
||||
struct wl_data_source* data_source,
|
||||
const char* mime_type) {
|
||||
struct sl_host_data_source* host = wl_data_source_get_user_data(data_source);
|
||||
|
||||
wl_data_source_send_target(host->resource, mime_type);
|
||||
}
|
||||
|
||||
static void sl_data_source_send(void* data,
|
||||
struct wl_data_source* data_source,
|
||||
const char* mime_type,
|
||||
int32_t fd) {
|
||||
struct sl_host_data_source* host = wl_data_source_get_user_data(data_source);
|
||||
|
||||
wl_data_source_send_send(host->resource, mime_type, fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void sl_data_source_cancelled(void* data,
|
||||
struct wl_data_source* data_source) {
|
||||
struct sl_host_data_source* host = wl_data_source_get_user_data(data_source);
|
||||
|
||||
wl_data_source_send_cancelled(host->resource);
|
||||
}
|
||||
|
||||
void sl_data_source_dnd_drop_performed(void* data,
|
||||
struct wl_data_source* data_source) {
|
||||
struct sl_host_data_source* host = wl_data_source_get_user_data(data_source);
|
||||
|
||||
wl_data_source_send_dnd_drop_performed(host->resource);
|
||||
}
|
||||
|
||||
void sl_data_source_dnd_finished(void* data,
|
||||
struct wl_data_source* data_source) {
|
||||
struct sl_host_data_source* host = wl_data_source_get_user_data(data_source);
|
||||
|
||||
wl_data_source_send_dnd_finished(host->resource);
|
||||
}
|
||||
|
||||
void sl_data_source_actions(void* data,
|
||||
struct wl_data_source* data_source,
|
||||
uint32_t dnd_action) {
|
||||
struct sl_host_data_source* host = wl_data_source_get_user_data(data_source);
|
||||
|
||||
wl_data_source_send_action(host->resource, dnd_action);
|
||||
}
|
||||
|
||||
static const struct wl_data_source_listener sl_data_source_listener = {
|
||||
sl_data_source_target, sl_data_source_send,
|
||||
sl_data_source_cancelled, sl_data_source_dnd_drop_performed,
|
||||
sl_data_source_dnd_finished, sl_data_source_actions};
|
||||
|
||||
static void sl_destroy_host_data_source(struct wl_resource* resource) {
|
||||
struct sl_host_data_source* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_data_source_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_data_device_start_drag(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* source_resource,
|
||||
struct wl_resource* origin_resource,
|
||||
struct wl_resource* icon_resource,
|
||||
uint32_t serial) {
|
||||
struct sl_host_data_device* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_data_source* host_source =
|
||||
source_resource ? wl_resource_get_user_data(source_resource) : NULL;
|
||||
struct sl_host_surface* host_origin =
|
||||
origin_resource ? wl_resource_get_user_data(origin_resource) : NULL;
|
||||
struct sl_host_surface* host_icon =
|
||||
icon_resource ? wl_resource_get_user_data(icon_resource) : NULL;
|
||||
host_icon->has_role = 1;
|
||||
|
||||
wl_data_device_start_drag(host->proxy,
|
||||
host_source ? host_source->proxy : NULL,
|
||||
host_origin ? host_origin->proxy : NULL,
|
||||
host_icon ? host_icon->proxy : NULL, serial);
|
||||
}
|
||||
|
||||
static void sl_data_device_set_selection(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* source_resource,
|
||||
uint32_t serial) {
|
||||
struct sl_host_data_device* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_data_source* host_source =
|
||||
source_resource ? wl_resource_get_user_data(source_resource) : NULL;
|
||||
|
||||
wl_data_device_set_selection(host->proxy,
|
||||
host_source ? host_source->proxy : NULL, serial);
|
||||
}
|
||||
|
||||
static void sl_data_device_release(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static const struct wl_data_device_interface sl_data_device_implementation = {
|
||||
sl_data_device_start_drag, sl_data_device_set_selection,
|
||||
sl_data_device_release};
|
||||
|
||||
static void sl_data_device_data_offer(void* data,
|
||||
struct wl_data_device* data_device,
|
||||
struct wl_data_offer* data_offer) {
|
||||
struct sl_host_data_device* host = wl_data_device_get_user_data(data_device);
|
||||
struct sl_host_data_offer* host_data_offer;
|
||||
|
||||
host_data_offer = malloc(sizeof(*host_data_offer));
|
||||
assert(host_data_offer);
|
||||
|
||||
host_data_offer->ctx = host->ctx;
|
||||
host_data_offer->resource = wl_resource_create(
|
||||
wl_resource_get_client(host->resource), &wl_data_offer_interface,
|
||||
wl_resource_get_version(host->resource), 0);
|
||||
wl_resource_set_implementation(host_data_offer->resource,
|
||||
&sl_data_offer_implementation, host_data_offer,
|
||||
sl_destroy_host_data_offer);
|
||||
host_data_offer->proxy = data_offer;
|
||||
wl_data_offer_set_user_data(host_data_offer->proxy, host_data_offer);
|
||||
wl_data_offer_add_listener(host_data_offer->proxy, &sl_data_offer_listener,
|
||||
host_data_offer);
|
||||
|
||||
wl_data_device_send_data_offer(host->resource, host_data_offer->resource);
|
||||
}
|
||||
|
||||
static void sl_data_device_enter(void* data,
|
||||
struct wl_data_device* data_device,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y,
|
||||
struct wl_data_offer* data_offer) {
|
||||
struct sl_host_data_device* host = wl_data_device_get_user_data(data_device);
|
||||
struct sl_host_surface* host_surface = wl_surface_get_user_data(surface);
|
||||
struct sl_host_data_offer* host_data_offer =
|
||||
wl_data_offer_get_user_data(data_offer);
|
||||
double scale = host->ctx->scale;
|
||||
|
||||
wl_data_device_send_enter(host->resource, serial, host_surface->resource,
|
||||
wl_fixed_from_double(wl_fixed_to_double(x) * scale),
|
||||
wl_fixed_from_double(wl_fixed_to_double(y) * scale),
|
||||
host_data_offer->resource);
|
||||
}
|
||||
|
||||
static void sl_data_device_leave(void* data,
|
||||
struct wl_data_device* data_device) {
|
||||
struct sl_host_data_device* host = wl_data_device_get_user_data(data_device);
|
||||
|
||||
wl_data_device_send_leave(host->resource);
|
||||
}
|
||||
|
||||
static void sl_data_device_motion(void* data,
|
||||
struct wl_data_device* data_device,
|
||||
uint32_t time,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y) {
|
||||
struct sl_host_data_device* host = wl_data_device_get_user_data(data_device);
|
||||
double scale = host->ctx->scale;
|
||||
|
||||
wl_data_device_send_motion(
|
||||
host->resource, time, wl_fixed_from_double(wl_fixed_to_double(x) * scale),
|
||||
wl_fixed_from_double(wl_fixed_to_double(y) * scale));
|
||||
}
|
||||
|
||||
static void sl_data_device_drop(void* data,
|
||||
struct wl_data_device* data_device) {
|
||||
struct sl_host_data_device* host = wl_data_device_get_user_data(data_device);
|
||||
|
||||
wl_data_device_send_drop(host->resource);
|
||||
}
|
||||
|
||||
static void sl_data_device_selection(void* data,
|
||||
struct wl_data_device* data_device,
|
||||
struct wl_data_offer* data_offer) {
|
||||
struct sl_host_data_device* host = wl_data_device_get_user_data(data_device);
|
||||
struct sl_host_data_offer* host_data_offer =
|
||||
wl_data_offer_get_user_data(data_offer);
|
||||
|
||||
wl_data_device_send_selection(host->resource, host_data_offer->resource);
|
||||
}
|
||||
|
||||
static const struct wl_data_device_listener sl_data_device_listener = {
|
||||
sl_data_device_data_offer, sl_data_device_enter, sl_data_device_leave,
|
||||
sl_data_device_motion, sl_data_device_drop, sl_data_device_selection};
|
||||
|
||||
static void sl_destroy_host_data_device(struct wl_resource* resource) {
|
||||
struct sl_host_data_device* host = wl_resource_get_user_data(resource);
|
||||
|
||||
if (wl_data_device_get_version(host->proxy) >=
|
||||
WL_DATA_DEVICE_RELEASE_SINCE_VERSION) {
|
||||
wl_data_device_release(host->proxy);
|
||||
} else {
|
||||
wl_data_device_destroy(host->proxy);
|
||||
}
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_data_device_manager_create_data_source(
|
||||
struct wl_client* client, struct wl_resource* resource, uint32_t id) {
|
||||
struct sl_host_data_device_manager* host =
|
||||
wl_resource_get_user_data(resource);
|
||||
struct sl_host_data_source* host_data_source;
|
||||
|
||||
host_data_source = malloc(sizeof(*host_data_source));
|
||||
assert(host_data_source);
|
||||
|
||||
host_data_source->resource = wl_resource_create(
|
||||
client, &wl_data_source_interface, wl_resource_get_version(resource), id);
|
||||
wl_resource_set_implementation(host_data_source->resource,
|
||||
&sl_data_source_implementation,
|
||||
host_data_source, sl_destroy_host_data_source);
|
||||
host_data_source->proxy =
|
||||
wl_data_device_manager_create_data_source(host->proxy);
|
||||
wl_data_source_set_user_data(host_data_source->proxy, host_data_source);
|
||||
wl_data_source_add_listener(host_data_source->proxy, &sl_data_source_listener,
|
||||
host_data_source);
|
||||
}
|
||||
|
||||
static void sl_data_device_manager_get_data_device(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
struct wl_resource* seat_resource) {
|
||||
struct sl_host_data_device_manager* host =
|
||||
wl_resource_get_user_data(resource);
|
||||
struct sl_host_seat* host_seat = wl_resource_get_user_data(seat_resource);
|
||||
struct sl_host_data_device* host_data_device;
|
||||
|
||||
host_data_device = malloc(sizeof(*host_data_device));
|
||||
assert(host_data_device);
|
||||
|
||||
host_data_device->ctx = host->ctx;
|
||||
host_data_device->resource = wl_resource_create(
|
||||
client, &wl_data_device_interface, wl_resource_get_version(resource), id);
|
||||
wl_resource_set_implementation(host_data_device->resource,
|
||||
&sl_data_device_implementation,
|
||||
host_data_device, sl_destroy_host_data_device);
|
||||
host_data_device->proxy =
|
||||
wl_data_device_manager_get_data_device(host->proxy, host_seat->proxy);
|
||||
wl_data_device_set_user_data(host_data_device->proxy, host_data_device);
|
||||
wl_data_device_add_listener(host_data_device->proxy, &sl_data_device_listener,
|
||||
host_data_device);
|
||||
}
|
||||
|
||||
static const struct wl_data_device_manager_interface
|
||||
sl_data_device_manager_implementation = {
|
||||
sl_data_device_manager_create_data_source,
|
||||
sl_data_device_manager_get_data_device};
|
||||
|
||||
static void sl_destroy_host_data_device_manager(struct wl_resource* resource) {
|
||||
struct sl_host_data_device_manager* host =
|
||||
wl_resource_get_user_data(resource);
|
||||
|
||||
wl_data_device_manager_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_bind_host_data_device_manager(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_host_data_device_manager* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->ctx = ctx;
|
||||
host->resource =
|
||||
wl_resource_create(client, &wl_data_device_manager_interface,
|
||||
MIN(version, ctx->data_device_manager->version), id);
|
||||
wl_resource_set_implementation(host->resource,
|
||||
&sl_data_device_manager_implementation, host,
|
||||
sl_destroy_host_data_device_manager);
|
||||
host->proxy = wl_registry_bind(
|
||||
wl_display_get_registry(ctx->display), ctx->data_device_manager->id,
|
||||
&wl_data_device_manager_interface, ctx->data_device_manager->version);
|
||||
wl_data_device_manager_set_user_data(host->proxy, host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_data_device_manager_global_create(struct sl_context* ctx) {
|
||||
return sl_global_create(ctx, &wl_data_device_manager_interface,
|
||||
ctx->data_device_manager->version, ctx,
|
||||
sl_bind_host_data_device_manager);
|
||||
}
|
126
sommelier/sommelier-display.c
Normal file
126
sommelier/sommelier-display.c
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
static void sl_registry_bind(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t name,
|
||||
const char* interface,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_host_registry* host = wl_resource_get_user_data(resource);
|
||||
struct sl_global* global;
|
||||
|
||||
wl_list_for_each(global, &host->ctx->globals, link) {
|
||||
if (global->name == name)
|
||||
break;
|
||||
}
|
||||
|
||||
assert(&global->link != &host->ctx->globals);
|
||||
assert(version != 0);
|
||||
assert(global->version >= version);
|
||||
|
||||
global->bind(client, global->data, version, id);
|
||||
}
|
||||
|
||||
static const struct wl_registry_interface sl_registry_implementation = {
|
||||
sl_registry_bind};
|
||||
|
||||
static void sl_sync_callback_done(void* data,
|
||||
struct wl_callback* callback,
|
||||
uint32_t serial) {
|
||||
struct sl_host_callback* host = wl_callback_get_user_data(callback);
|
||||
|
||||
wl_callback_send_done(host->resource, serial);
|
||||
wl_resource_destroy(host->resource);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener sl_sync_callback_listener = {
|
||||
sl_sync_callback_done};
|
||||
|
||||
static void sl_host_callback_destroy(struct wl_resource* resource) {
|
||||
struct sl_host_callback* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_callback_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_display_sync(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = wl_resource_get_user_data(resource);
|
||||
struct sl_host_callback* host_callback;
|
||||
|
||||
host_callback = malloc(sizeof(*host_callback));
|
||||
assert(host_callback);
|
||||
|
||||
host_callback->resource =
|
||||
wl_resource_create(client, &wl_callback_interface, 1, id);
|
||||
wl_resource_set_implementation(host_callback->resource, NULL, host_callback,
|
||||
sl_host_callback_destroy);
|
||||
host_callback->proxy = wl_display_sync(ctx->display);
|
||||
wl_callback_set_user_data(host_callback->proxy, host_callback);
|
||||
wl_callback_add_listener(host_callback->proxy, &sl_sync_callback_listener,
|
||||
host_callback);
|
||||
}
|
||||
|
||||
static void sl_destroy_host_registry(struct wl_resource* resource) {
|
||||
struct sl_host_registry* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_list_remove(&host->link);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_display_get_registry(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = wl_resource_get_user_data(resource);
|
||||
struct sl_host_registry* host_registry;
|
||||
struct sl_global* global;
|
||||
|
||||
host_registry = malloc(sizeof(*host_registry));
|
||||
assert(host_registry);
|
||||
|
||||
host_registry->ctx = ctx;
|
||||
host_registry->resource =
|
||||
wl_resource_create(client, &wl_registry_interface, 1, id);
|
||||
wl_list_insert(&ctx->registries, &host_registry->link);
|
||||
wl_resource_set_implementation(host_registry->resource,
|
||||
&sl_registry_implementation, host_registry,
|
||||
sl_destroy_host_registry);
|
||||
|
||||
wl_list_for_each(global, &ctx->globals, link) {
|
||||
wl_resource_post_event(host_registry->resource, WL_REGISTRY_GLOBAL,
|
||||
global->name, global->interface->name,
|
||||
global->version);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_display_interface sl_display_implementation = {
|
||||
sl_display_sync, sl_display_get_registry};
|
||||
|
||||
static enum wl_iterator_result sl_set_implementation(
|
||||
struct wl_resource* resource, void* user_data) {
|
||||
struct sl_context* ctx = (struct sl_context*)user_data;
|
||||
|
||||
if (strcmp(wl_resource_get_class(resource), "wl_display") == 0) {
|
||||
wl_resource_set_implementation(resource, &sl_display_implementation, ctx,
|
||||
NULL);
|
||||
return WL_ITERATOR_STOP;
|
||||
}
|
||||
|
||||
return WL_ITERATOR_CONTINUE;
|
||||
}
|
||||
|
||||
void sl_set_display_implementation(struct sl_context* ctx) {
|
||||
// Find display resource and set implementation.
|
||||
wl_client_for_each_resource(ctx->client, sl_set_implementation, ctx);
|
||||
}
|
259
sommelier/sommelier-drm.c
Normal file
259
sommelier/sommelier-drm.c
Normal file
@ -0,0 +1,259 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <gbm.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <xf86drm.h>
|
||||
|
||||
#include "virtgpu_drm.h"
|
||||
|
||||
#include "drm-server-protocol.h"
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
|
||||
struct sl_host_drm {
|
||||
struct sl_context* ctx;
|
||||
uint32_t version;
|
||||
struct wl_resource* resource;
|
||||
struct zwp_linux_dmabuf_v1* linux_dmabuf_proxy;
|
||||
struct wl_callback* callback;
|
||||
};
|
||||
|
||||
static void sl_drm_authenticate(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id) {
|
||||
wl_drm_send_authenticated(resource);
|
||||
}
|
||||
|
||||
static void sl_drm_create_buffer(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
uint32_t name,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
uint32_t stride,
|
||||
uint32_t format) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void sl_drm_create_planar_buffer(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
uint32_t name,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
uint32_t format,
|
||||
int32_t offset0,
|
||||
int32_t stride0,
|
||||
int32_t offset1,
|
||||
int32_t stride1,
|
||||
int32_t offset2,
|
||||
int32_t stride2) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void sl_drm_sync(struct sl_context *ctx,
|
||||
struct sl_sync_point* sync_point)
|
||||
{
|
||||
int drm_fd = gbm_device_get_fd(ctx->gbm);
|
||||
struct drm_prime_handle prime_handle;
|
||||
int ret;
|
||||
|
||||
// First imports the prime fd to a gem handle. This will fail if this
|
||||
// function was not passed a prime handle that can be imported by the drm
|
||||
// device given to sommelier.
|
||||
memset(&prime_handle, 0, sizeof(prime_handle));
|
||||
prime_handle.fd = sync_point->fd;
|
||||
ret = drmIoctl(drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_handle);
|
||||
if (!ret) {
|
||||
struct drm_virtgpu_3d_wait wait_arg;
|
||||
struct drm_gem_close gem_close;
|
||||
|
||||
// Then attempts to wait for GPU operations to complete. This will fail
|
||||
// silently if the drm device passed to sommelier is not a virtio-gpu
|
||||
// device.
|
||||
memset(&wait_arg, 0, sizeof(wait_arg));
|
||||
wait_arg.handle = prime_handle.handle;
|
||||
drmIoctl(drm_fd, DRM_IOCTL_VIRTGPU_WAIT, &wait_arg);
|
||||
|
||||
// Always close the handle we imported.
|
||||
memset(&gem_close, 0, sizeof(gem_close));
|
||||
gem_close.handle = prime_handle.handle;
|
||||
drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_drm_create_prime_buffer(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
int32_t name,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
uint32_t format,
|
||||
int32_t offset0,
|
||||
int32_t stride0,
|
||||
int32_t offset1,
|
||||
int32_t stride1,
|
||||
int32_t offset2,
|
||||
int32_t stride2) {
|
||||
struct sl_host_drm* host = wl_resource_get_user_data(resource);
|
||||
struct zwp_linux_buffer_params_v1* buffer_params;
|
||||
|
||||
assert(name >= 0);
|
||||
assert(!offset1);
|
||||
assert(!stride1);
|
||||
assert(!offset2);
|
||||
assert(!stride2);
|
||||
|
||||
// Attempts to correct stride0 with virtio-gpu specific resource information,
|
||||
// if available. Ideally mesa/gbm should have the correct stride. Remove
|
||||
// after crbug.com/892242 is resolved in mesa.
|
||||
int is_gpu_buffer = 0;
|
||||
if (host->ctx->gbm) {
|
||||
int drm_fd = gbm_device_get_fd(host->ctx->gbm);
|
||||
struct drm_prime_handle prime_handle;
|
||||
int ret;
|
||||
|
||||
// First imports the prime fd to a gem handle. This will fail if this
|
||||
// function was not passed a prime handle that can be imported by the drm
|
||||
// device given to sommelier.
|
||||
memset(&prime_handle, 0, sizeof(prime_handle));
|
||||
prime_handle.fd = name;
|
||||
ret = drmIoctl(drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_handle);
|
||||
if (!ret) {
|
||||
struct drm_virtgpu_resource_info info_arg;
|
||||
struct drm_gem_close gem_close;
|
||||
|
||||
// Then attempts to get resource information. This will fail silently if
|
||||
// the drm device passed to sommelier is not a virtio-gpu device.
|
||||
memset(&info_arg, 0, sizeof(info_arg));
|
||||
info_arg.bo_handle = prime_handle.handle;
|
||||
ret = drmIoctl(drm_fd, DRM_IOCTL_VIRTGPU_RESOURCE_INFO, &info_arg);
|
||||
// Correct stride0 if we are able to get proper resource info.
|
||||
if (!ret) {
|
||||
stride0 = info_arg.stride;
|
||||
is_gpu_buffer = 1;
|
||||
}
|
||||
|
||||
// Always close the handle we imported.
|
||||
memset(&gem_close, 0, sizeof(gem_close));
|
||||
gem_close.handle = prime_handle.handle;
|
||||
drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
|
||||
}
|
||||
}
|
||||
|
||||
buffer_params =
|
||||
zwp_linux_dmabuf_v1_create_params(host->ctx->linux_dmabuf->internal);
|
||||
zwp_linux_buffer_params_v1_add(buffer_params, name, 0, offset0, stride0, 0,
|
||||
0);
|
||||
|
||||
struct sl_host_buffer* host_buffer =
|
||||
sl_create_host_buffer(client, id,
|
||||
zwp_linux_buffer_params_v1_create_immed(
|
||||
buffer_params, width, height, format, 0),
|
||||
width, height);
|
||||
if (is_gpu_buffer) {
|
||||
host_buffer->sync_point = sl_sync_point_create(name);
|
||||
host_buffer->sync_point->sync = sl_drm_sync;
|
||||
} else {
|
||||
close(name);
|
||||
}
|
||||
|
||||
zwp_linux_buffer_params_v1_destroy(buffer_params);
|
||||
}
|
||||
|
||||
static const struct wl_drm_interface sl_drm_implementation = {
|
||||
sl_drm_authenticate, sl_drm_create_buffer, sl_drm_create_planar_buffer,
|
||||
sl_drm_create_prime_buffer};
|
||||
|
||||
static void sl_destroy_host_drm(struct wl_resource* resource) {
|
||||
struct sl_host_drm* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_linux_dmabuf_v1_destroy(host->linux_dmabuf_proxy);
|
||||
wl_callback_destroy(host->callback);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_drm_format(void* data,
|
||||
struct zwp_linux_dmabuf_v1* linux_dmabuf,
|
||||
uint32_t format) {
|
||||
struct sl_host_drm* host = zwp_linux_dmabuf_v1_get_user_data(linux_dmabuf);
|
||||
|
||||
switch (format) {
|
||||
case WL_DRM_FORMAT_RGB565:
|
||||
case WL_DRM_FORMAT_ARGB8888:
|
||||
case WL_DRM_FORMAT_ABGR8888:
|
||||
case WL_DRM_FORMAT_XRGB8888:
|
||||
case WL_DRM_FORMAT_XBGR8888:
|
||||
wl_drm_send_format(host->resource, format);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_drm_modifier(void* data,
|
||||
struct zwp_linux_dmabuf_v1* linux_dmabuf,
|
||||
uint32_t format,
|
||||
uint32_t modifier_hi,
|
||||
uint32_t modifier_lo) {}
|
||||
|
||||
static const struct zwp_linux_dmabuf_v1_listener sl_linux_dmabuf_listener = {
|
||||
sl_drm_format, sl_drm_modifier};
|
||||
|
||||
static void sl_drm_callback_done(void* data,
|
||||
struct wl_callback* callback,
|
||||
uint32_t serial) {
|
||||
struct sl_host_drm* host = wl_callback_get_user_data(callback);
|
||||
|
||||
if (host->ctx->drm_device)
|
||||
wl_drm_send_device(host->resource, host->ctx->drm_device);
|
||||
if (host->version >= WL_DRM_CREATE_PRIME_BUFFER_SINCE_VERSION)
|
||||
wl_drm_send_capabilities(host->resource, WL_DRM_CAPABILITY_PRIME);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener sl_drm_callback_listener = {
|
||||
sl_drm_callback_done};
|
||||
|
||||
static void sl_bind_host_drm(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_host_drm* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->ctx = ctx;
|
||||
host->version = MIN(version, 2);
|
||||
host->resource =
|
||||
wl_resource_create(client, &wl_drm_interface, host->version, id);
|
||||
wl_resource_set_implementation(host->resource, &sl_drm_implementation, host,
|
||||
sl_destroy_host_drm);
|
||||
|
||||
host->linux_dmabuf_proxy = wl_registry_bind(
|
||||
wl_display_get_registry(ctx->display), ctx->linux_dmabuf->id,
|
||||
&zwp_linux_dmabuf_v1_interface, ctx->linux_dmabuf->version);
|
||||
zwp_linux_dmabuf_v1_set_user_data(host->linux_dmabuf_proxy, host);
|
||||
zwp_linux_dmabuf_v1_add_listener(host->linux_dmabuf_proxy,
|
||||
&sl_linux_dmabuf_listener, host);
|
||||
|
||||
host->callback = wl_display_sync(ctx->display);
|
||||
wl_callback_set_user_data(host->callback, host);
|
||||
wl_callback_add_listener(host->callback, &sl_drm_callback_listener, host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_drm_global_create(struct sl_context* ctx) {
|
||||
assert(ctx->linux_dmabuf);
|
||||
|
||||
// Early out if DMABuf protocol version is not sufficient.
|
||||
if (ctx->linux_dmabuf->version < 2)
|
||||
return NULL;
|
||||
|
||||
return sl_global_create(ctx, &wl_drm_interface, 2, ctx, sl_bind_host_drm);
|
||||
}
|
162
sommelier/sommelier-gtk-shell.c
Normal file
162
sommelier/sommelier-gtk-shell.c
Normal file
@ -0,0 +1,162 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aura-shell-client-protocol.h"
|
||||
#include "gtk-shell-server-protocol.h"
|
||||
|
||||
struct sl_host_gtk_shell {
|
||||
struct sl_aura_shell* aura_shell;
|
||||
struct wl_resource* resource;
|
||||
struct zaura_shell* proxy;
|
||||
struct wl_callback* callback;
|
||||
char* startup_id;
|
||||
struct wl_list surfaces;
|
||||
};
|
||||
|
||||
struct sl_host_gtk_surface {
|
||||
struct wl_resource* resource;
|
||||
struct zaura_surface* proxy;
|
||||
struct wl_list link;
|
||||
struct sl_aura_shell* aura_shell;
|
||||
};
|
||||
|
||||
static void sl_gtk_surface_set_dbus_properties(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
const char* application_id,
|
||||
const char* app_menu_path,
|
||||
const char* menubar_path,
|
||||
const char* window_object_path,
|
||||
const char* application_object_path,
|
||||
const char* unique_bus_name) {
|
||||
struct sl_host_gtk_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zaura_surface_set_application_id(host->proxy, application_id);
|
||||
}
|
||||
|
||||
static void sl_gtk_surface_set_modal(struct wl_client* client,
|
||||
struct wl_resource* resource) {}
|
||||
|
||||
static void sl_gtk_surface_unset_modal(struct wl_client* client,
|
||||
struct wl_resource* resource) {}
|
||||
|
||||
static void sl_gtk_surface_present(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t time) {}
|
||||
|
||||
static const struct gtk_surface1_interface sl_gtk_surface_implementation = {
|
||||
sl_gtk_surface_set_dbus_properties, sl_gtk_surface_set_modal,
|
||||
sl_gtk_surface_unset_modal, sl_gtk_surface_present};
|
||||
|
||||
static void sl_destroy_host_gtk_surface(struct wl_resource* resource) {
|
||||
struct sl_host_gtk_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zaura_surface_destroy(host->proxy);
|
||||
wl_list_remove(&host->link);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_gtk_shell_get_gtk_surface(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
struct wl_resource* surface_resource) {
|
||||
struct sl_host_gtk_shell* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_surface* host_surface =
|
||||
wl_resource_get_user_data(surface_resource);
|
||||
struct sl_host_gtk_surface* host_gtk_surface;
|
||||
|
||||
host_gtk_surface = malloc(sizeof(*host_gtk_surface));
|
||||
assert(host_gtk_surface);
|
||||
|
||||
wl_list_insert(&host->surfaces, &host_gtk_surface->link);
|
||||
host_gtk_surface->aura_shell = host->aura_shell;
|
||||
host_gtk_surface->resource =
|
||||
wl_resource_create(client, >k_surface1_interface, 1, id);
|
||||
wl_resource_set_implementation(host_gtk_surface->resource,
|
||||
&sl_gtk_surface_implementation,
|
||||
host_gtk_surface, sl_destroy_host_gtk_surface);
|
||||
host_gtk_surface->proxy =
|
||||
zaura_shell_get_aura_surface(host->proxy, host_surface->proxy);
|
||||
zaura_surface_set_startup_id(host_gtk_surface->proxy, host->startup_id);
|
||||
}
|
||||
|
||||
static void sl_gtk_shell_set_startup_id(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
const char* startup_id) {
|
||||
struct sl_host_gtk_shell* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_gtk_surface* surface;
|
||||
|
||||
free(host->startup_id);
|
||||
host->startup_id = startup_id ? strdup(startup_id) : NULL;
|
||||
|
||||
wl_list_for_each(surface, &host->surfaces, link)
|
||||
zaura_surface_set_startup_id(surface->proxy, host->startup_id);
|
||||
}
|
||||
|
||||
static void sl_gtk_shell_system_bell(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* surface_resource) {}
|
||||
|
||||
static const struct gtk_shell1_interface sl_gtk_shell_implementation = {
|
||||
sl_gtk_shell_get_gtk_surface, sl_gtk_shell_set_startup_id,
|
||||
sl_gtk_shell_system_bell};
|
||||
|
||||
static void sl_destroy_host_gtk_shell(struct wl_resource* resource) {
|
||||
struct sl_host_gtk_shell* host = wl_resource_get_user_data(resource);
|
||||
|
||||
free(host->startup_id);
|
||||
wl_callback_destroy(host->callback);
|
||||
zaura_shell_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_gtk_shell_callback_done(void* data,
|
||||
struct wl_callback* callback,
|
||||
uint32_t serial) {
|
||||
struct sl_host_gtk_shell* host = wl_callback_get_user_data(callback);
|
||||
|
||||
gtk_shell1_send_capabilities(host->resource, 0);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener sl_gtk_shell_callback_listener = {
|
||||
sl_gtk_shell_callback_done};
|
||||
|
||||
static void sl_bind_host_gtk_shell(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_host_gtk_shell* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->aura_shell = ctx->aura_shell;
|
||||
host->startup_id = NULL;
|
||||
wl_list_init(&host->surfaces);
|
||||
host->resource = wl_resource_create(client, >k_shell1_interface, 1, id);
|
||||
wl_resource_set_implementation(host->resource, &sl_gtk_shell_implementation,
|
||||
host, sl_destroy_host_gtk_shell);
|
||||
host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display),
|
||||
ctx->aura_shell->id, &zaura_shell_interface,
|
||||
ctx->aura_shell->version);
|
||||
zaura_shell_set_user_data(host->proxy, host);
|
||||
|
||||
host->callback = wl_display_sync(ctx->aura_shell->ctx->display);
|
||||
wl_callback_set_user_data(host->callback, host);
|
||||
wl_callback_add_listener(host->callback, &sl_gtk_shell_callback_listener,
|
||||
host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_gtk_shell_global_create(struct sl_context* ctx) {
|
||||
return sl_global_create(ctx, >k_shell1_interface, 1, ctx,
|
||||
sl_bind_host_gtk_shell);
|
||||
}
|
377
sommelier/sommelier-output.c
Normal file
377
sommelier/sommelier-output.c
Normal file
@ -0,0 +1,377 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "aura-shell-client-protocol.h"
|
||||
|
||||
#define MAX_OUTPUT_SCALE 2
|
||||
|
||||
#define INCH_IN_MM 25.4
|
||||
|
||||
// The ergonomic advice for monitor distance is 50-75cm away, with laptops
|
||||
// expected to be closer. This magic number is designed to correct that for the
|
||||
// purpose of calculating a "useful" DPI.
|
||||
//
|
||||
// TODO(crbug.com/988325) Fix sommelier's scaling logic s.t. this ratio is
|
||||
// unnecessary.
|
||||
#define LAPTOP_TO_DESKTOP_DISTANCE_RATIO (2.0 / 3.0)
|
||||
|
||||
double sl_output_aura_scale_factor_to_double(int scale_factor) {
|
||||
// Aura scale factor is an enum that for all currently know values
|
||||
// is a scale value multipled by 1000. For example, enum value for
|
||||
// 1.25 scale factor is 1250.
|
||||
return scale_factor / 1000.0;
|
||||
}
|
||||
|
||||
void sl_output_get_host_output_state(struct sl_host_output* host,
|
||||
int* scale,
|
||||
int* physical_width,
|
||||
int* physical_height,
|
||||
int* width,
|
||||
int* height) {
|
||||
double preferred_scale =
|
||||
sl_output_aura_scale_factor_to_double(host->preferred_scale);
|
||||
double current_scale =
|
||||
sl_output_aura_scale_factor_to_double(host->current_scale);
|
||||
// "Ideal" means the scale factor you would need in order to make a pixel in
|
||||
// the buffer map 1:1 with a physical pixel. In the absence of any better
|
||||
// information, we assume a device whose display density maps faithfully to
|
||||
// true pixels (i.e. 1.0).
|
||||
double ideal_scale_factor = 1.0;
|
||||
double scale_factor = host->scale_factor;
|
||||
|
||||
// Use the scale factor we received from aura shell protocol when available.
|
||||
if (host->ctx->aura_shell) {
|
||||
double device_scale_factor =
|
||||
sl_output_aura_scale_factor_to_double(host->device_scale_factor);
|
||||
|
||||
ideal_scale_factor = device_scale_factor * preferred_scale;
|
||||
scale_factor = device_scale_factor * current_scale;
|
||||
}
|
||||
|
||||
// Always use scale=1 and adjust geometry and mode based on ideal
|
||||
// scale factor for Xwayland client. For other clients, pick an optimal
|
||||
// scale and adjust geometry and mode based on it.
|
||||
if (host->ctx->xwayland) {
|
||||
if (scale)
|
||||
*scale = 1;
|
||||
*physical_width = host->physical_width * ideal_scale_factor / scale_factor;
|
||||
*physical_height =
|
||||
host->physical_height * ideal_scale_factor / scale_factor;
|
||||
*width = host->width * host->ctx->scale / scale_factor;
|
||||
*height = host->height * host->ctx->scale / scale_factor;
|
||||
|
||||
// Historically, X applications use DPI to decide their scale (which is not
|
||||
// ideal). The main problem is that in order to facilitate this, many X
|
||||
// utilities lie about the DPI of the device in order to achieve the desired
|
||||
// scaling, e.g. most laptops report a dpi of 96 even if that is inaccurate.
|
||||
//
|
||||
// The reason they have to lie is because laptop screens are typically
|
||||
// closer to your eye than desktop monitors (by a factor of roughly 2/3),
|
||||
// meaning they have to have proportionally higher DPI in order to "look" as
|
||||
// high-def as the monitor.
|
||||
//
|
||||
// Since sommelier is in the business of lying about the screen's
|
||||
// dimensions, we will also lie a bit more when we are dealing with the
|
||||
// internal display, to make its dpi scale like a desktop monitor's would.
|
||||
if (host->internal) {
|
||||
*physical_width /= LAPTOP_TO_DESKTOP_DISTANCE_RATIO;
|
||||
*physical_height /= LAPTOP_TO_DESKTOP_DISTANCE_RATIO;
|
||||
}
|
||||
} else {
|
||||
int s = MIN(ceil(scale_factor / host->ctx->scale), MAX_OUTPUT_SCALE);
|
||||
|
||||
if (scale)
|
||||
*scale = s;
|
||||
*physical_width = host->physical_width;
|
||||
*physical_height = host->physical_height;
|
||||
*width = host->width * host->ctx->scale * s / scale_factor;
|
||||
*height = host->height * host->ctx->scale * s / scale_factor;
|
||||
}
|
||||
|
||||
if (host->ctx->dpi.size) {
|
||||
int dpi = (*width * INCH_IN_MM) / *physical_width;
|
||||
int adjusted_dpi = *((int*)host->ctx->dpi.data);
|
||||
double mmpd;
|
||||
int* p;
|
||||
|
||||
// Choose the DPI bucket which is closest to the apparent DPI which we
|
||||
// calculated above.
|
||||
wl_array_for_each(p, &host->ctx->dpi) {
|
||||
if (abs(*p - dpi) < abs(adjusted_dpi - dpi))
|
||||
adjusted_dpi = *p;
|
||||
}
|
||||
|
||||
mmpd = INCH_IN_MM / adjusted_dpi;
|
||||
*physical_width = *width * mmpd + 0.5;
|
||||
*physical_height = *height * mmpd + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
void sl_output_send_host_output_state(struct sl_host_output* host) {
|
||||
int scale;
|
||||
int physical_width;
|
||||
int physical_height;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
sl_output_get_host_output_state(host, &scale, &physical_width,
|
||||
&physical_height, &width, &height);
|
||||
|
||||
// Use density of internal display for all Xwayland outputs. X11 clients
|
||||
// typically lack support for dynamically changing density so it's
|
||||
// preferred to always use the density of the internal display.
|
||||
if (host->ctx->xwayland) {
|
||||
struct sl_host_output* output;
|
||||
|
||||
wl_list_for_each(output, &host->ctx->host_outputs, link) {
|
||||
if (output->internal) {
|
||||
int internal_width;
|
||||
int internal_height;
|
||||
|
||||
sl_output_get_host_output_state(output, NULL, &physical_width,
|
||||
&physical_height, &internal_width,
|
||||
&internal_height);
|
||||
|
||||
physical_width = (physical_width * width) / internal_width;
|
||||
physical_height = (physical_height * height) / internal_height;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// X/Y are best left at origin as managed X windows are kept centered on
|
||||
// the root window. The result is that all outputs are overlapping and
|
||||
// pointer events can always be dispatched to the visible region of the
|
||||
// window.
|
||||
wl_output_send_geometry(host->resource, 0, 0, physical_width, physical_height,
|
||||
host->subpixel, host->make, host->model,
|
||||
host->transform);
|
||||
wl_output_send_mode(host->resource, host->flags | WL_OUTPUT_MODE_CURRENT,
|
||||
width, height, host->refresh);
|
||||
if (wl_resource_get_version(host->resource) >= WL_OUTPUT_SCALE_SINCE_VERSION)
|
||||
wl_output_send_scale(host->resource, scale);
|
||||
if (wl_resource_get_version(host->resource) >= WL_OUTPUT_DONE_SINCE_VERSION)
|
||||
wl_output_send_done(host->resource);
|
||||
}
|
||||
|
||||
static void sl_output_geometry(void* data,
|
||||
struct wl_output* output,
|
||||
int x,
|
||||
int y,
|
||||
int physical_width,
|
||||
int physical_height,
|
||||
int subpixel,
|
||||
const char* make,
|
||||
const char* model,
|
||||
int transform) {
|
||||
struct sl_host_output* host = wl_output_get_user_data(output);
|
||||
|
||||
host->x = x;
|
||||
host->y = y;
|
||||
host->physical_width = physical_width;
|
||||
host->physical_height = physical_height;
|
||||
host->subpixel = subpixel;
|
||||
free(host->model);
|
||||
host->model = strdup(model);
|
||||
free(host->make);
|
||||
host->make = strdup(make);
|
||||
host->transform = transform;
|
||||
}
|
||||
|
||||
static void sl_output_mode(void* data,
|
||||
struct wl_output* output,
|
||||
uint32_t flags,
|
||||
int width,
|
||||
int height,
|
||||
int refresh) {
|
||||
struct sl_host_output* host = wl_output_get_user_data(output);
|
||||
|
||||
host->flags = flags;
|
||||
host->width = width;
|
||||
host->height = height;
|
||||
host->refresh = refresh;
|
||||
}
|
||||
|
||||
static void sl_output_done(void* data, struct wl_output* output) {
|
||||
struct sl_host_output* host = wl_output_get_user_data(output);
|
||||
|
||||
// Early out if scale is expected but not yet know.
|
||||
if (host->expecting_scale)
|
||||
return;
|
||||
|
||||
sl_output_send_host_output_state(host);
|
||||
|
||||
// Expect scale if aura output exists.
|
||||
if (host->aura_output)
|
||||
host->expecting_scale = 1;
|
||||
}
|
||||
|
||||
static void sl_output_scale(void* data,
|
||||
struct wl_output* output,
|
||||
int32_t scale_factor) {
|
||||
struct sl_host_output* host = wl_output_get_user_data(output);
|
||||
|
||||
host->scale_factor = scale_factor;
|
||||
}
|
||||
|
||||
static const struct wl_output_listener sl_output_listener = {
|
||||
sl_output_geometry, sl_output_mode, sl_output_done, sl_output_scale};
|
||||
|
||||
static void sl_aura_output_scale(void* data,
|
||||
struct zaura_output* output,
|
||||
uint32_t flags,
|
||||
uint32_t scale) {
|
||||
struct sl_host_output* host = zaura_output_get_user_data(output);
|
||||
|
||||
switch (scale) {
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0400:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0500:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0550:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0600:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0625:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0650:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0700:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0750:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0800:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0850:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0900:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_0950:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1000:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1050:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1100:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1150:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1125:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1200:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1250:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1300:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1400:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1450:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1500:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1600:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1750:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_1800:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_2000:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_2200:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_2250:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_2500:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_2750:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_3000:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_3500:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_4000:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_4500:
|
||||
case ZAURA_OUTPUT_SCALE_FACTOR_5000:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "warning: unknown scale factor: %d\n", scale);
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT)
|
||||
host->current_scale = scale;
|
||||
if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED)
|
||||
host->preferred_scale = scale;
|
||||
|
||||
host->expecting_scale = 0;
|
||||
}
|
||||
|
||||
static void sl_aura_output_connection(void* data,
|
||||
struct zaura_output* output,
|
||||
uint32_t connection) {
|
||||
struct sl_host_output* host = zaura_output_get_user_data(output);
|
||||
|
||||
host->internal = connection == ZAURA_OUTPUT_CONNECTION_TYPE_INTERNAL;
|
||||
}
|
||||
|
||||
static void sl_aura_output_device_scale_factor(void* data,
|
||||
struct zaura_output* output,
|
||||
uint32_t device_scale_factor) {
|
||||
struct sl_host_output* host = zaura_output_get_user_data(output);
|
||||
|
||||
host->device_scale_factor = device_scale_factor;
|
||||
}
|
||||
|
||||
static const struct zaura_output_listener sl_aura_output_listener = {
|
||||
sl_aura_output_scale, sl_aura_output_connection,
|
||||
sl_aura_output_device_scale_factor};
|
||||
|
||||
static void sl_destroy_host_output(struct wl_resource* resource) {
|
||||
struct sl_host_output* host = wl_resource_get_user_data(resource);
|
||||
|
||||
if (host->aura_output)
|
||||
zaura_output_destroy(host->aura_output);
|
||||
if (wl_output_get_version(host->proxy) >= WL_OUTPUT_RELEASE_SINCE_VERSION) {
|
||||
wl_output_release(host->proxy);
|
||||
} else {
|
||||
wl_output_destroy(host->proxy);
|
||||
}
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
wl_list_remove(&host->link);
|
||||
free(host->make);
|
||||
free(host->model);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_bind_host_output(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_output* output = (struct sl_output*)data;
|
||||
struct sl_context* ctx = output->ctx;
|
||||
struct sl_host_output* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->ctx = ctx;
|
||||
host->resource = wl_resource_create(client, &wl_output_interface,
|
||||
MIN(version, output->version), id);
|
||||
wl_resource_set_implementation(host->resource, NULL, host,
|
||||
sl_destroy_host_output);
|
||||
host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display),
|
||||
output->id, &wl_output_interface,
|
||||
wl_resource_get_version(host->resource));
|
||||
wl_output_set_user_data(host->proxy, host);
|
||||
wl_output_add_listener(host->proxy, &sl_output_listener, host);
|
||||
host->aura_output = NULL;
|
||||
// We assume that first output is internal by default.
|
||||
host->internal = wl_list_empty(&ctx->host_outputs);
|
||||
host->x = 0;
|
||||
host->y = 0;
|
||||
host->physical_width = 0;
|
||||
host->physical_height = 0;
|
||||
host->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
|
||||
host->make = strdup("unknown");
|
||||
host->model = strdup("unknown");
|
||||
host->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
host->flags = 0;
|
||||
host->width = 1024;
|
||||
host->height = 768;
|
||||
host->refresh = 60000;
|
||||
host->scale_factor = 1;
|
||||
host->current_scale = 1000;
|
||||
host->preferred_scale = 1000;
|
||||
host->device_scale_factor = 1000;
|
||||
host->expecting_scale = 0;
|
||||
wl_list_insert(ctx->host_outputs.prev, &host->link);
|
||||
if (ctx->aura_shell) {
|
||||
host->expecting_scale = 1;
|
||||
host->internal = 0;
|
||||
host->aura_output =
|
||||
zaura_shell_get_aura_output(ctx->aura_shell->internal, host->proxy);
|
||||
zaura_output_set_user_data(host->aura_output, host);
|
||||
zaura_output_add_listener(host->aura_output, &sl_aura_output_listener,
|
||||
host);
|
||||
}
|
||||
}
|
||||
|
||||
struct sl_global* sl_output_global_create(struct sl_output* output) {
|
||||
return sl_global_create(output->ctx, &wl_output_interface, output->version,
|
||||
output, sl_bind_host_output);
|
||||
}
|
146
sommelier/sommelier-relative-pointer-manager.c
Normal file
146
sommelier/sommelier-relative-pointer-manager.c
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright 2019 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
#include "relative-pointer-unstable-v1-server-protocol.h"
|
||||
#include "relative-pointer-unstable-v1-client-protocol.h"
|
||||
|
||||
struct sl_host_relative_pointer_manager {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct zwp_relative_pointer_manager_v1* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_relative_pointer {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct zwp_relative_pointer_v1* proxy;
|
||||
};
|
||||
|
||||
static void sl_relative_pointer_relative_motion(
|
||||
void* data,
|
||||
struct zwp_relative_pointer_v1* relative_pointer,
|
||||
uint32_t utime_hi,
|
||||
uint32_t utime_lo,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy,
|
||||
wl_fixed_t dx_unaccel,
|
||||
wl_fixed_t dy_unaccel) {
|
||||
struct sl_host_relative_pointer* host =
|
||||
zwp_relative_pointer_v1_get_user_data(relative_pointer);
|
||||
|
||||
zwp_relative_pointer_v1_send_relative_motion(
|
||||
host->resource, utime_hi, utime_lo, dx, dy, dx_unaccel, dy_unaccel);
|
||||
}
|
||||
|
||||
static void sl_destroy_host_relative_pointer(struct wl_resource* resource) {
|
||||
struct sl_host_relative_pointer* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_relative_pointer_v1_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_relative_pointer_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static struct zwp_relative_pointer_v1_listener sl_relative_pointer_listener = {
|
||||
sl_relative_pointer_relative_motion,
|
||||
};
|
||||
|
||||
static struct zwp_relative_pointer_v1_interface
|
||||
sl_relative_pointer_implementation = {
|
||||
sl_relative_pointer_destroy,
|
||||
};
|
||||
|
||||
static void sl_destroy_host_relative_pointer_manager(
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_relative_pointer_manager* host =
|
||||
wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_relative_pointer_manager_v1_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_relative_pointer_manager_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_relative_pointer_manager_get_relative_pointer(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
struct wl_resource* pointer) {
|
||||
struct sl_host_relative_pointer_manager* host =
|
||||
wl_resource_get_user_data(resource);
|
||||
struct sl_host_pointer* host_pointer = wl_resource_get_user_data(pointer);
|
||||
struct wl_resource* relative_pointer_resource =
|
||||
wl_resource_create(client, &zwp_relative_pointer_v1_interface, 1, id);
|
||||
struct sl_host_relative_pointer* relative_pointer_host;
|
||||
|
||||
relative_pointer_host = malloc(sizeof(*relative_pointer_host));
|
||||
assert(relative_pointer_host);
|
||||
relative_pointer_host->resource = relative_pointer_resource;
|
||||
relative_pointer_host->ctx = host->ctx;
|
||||
relative_pointer_host->proxy =
|
||||
zwp_relative_pointer_manager_v1_get_relative_pointer(
|
||||
host->ctx->relative_pointer_manager->internal, host_pointer->proxy);
|
||||
wl_resource_set_implementation(
|
||||
relative_pointer_resource, &sl_relative_pointer_implementation,
|
||||
relative_pointer_host, sl_destroy_host_relative_pointer);
|
||||
zwp_relative_pointer_v1_set_user_data(relative_pointer_host->proxy,
|
||||
relative_pointer_host);
|
||||
zwp_relative_pointer_v1_add_listener(relative_pointer_host->proxy,
|
||||
&sl_relative_pointer_listener,
|
||||
relative_pointer_host);
|
||||
}
|
||||
|
||||
static struct zwp_relative_pointer_manager_v1_interface
|
||||
sl_relative_pointer_manager_implementation = {
|
||||
sl_relative_pointer_manager_destroy,
|
||||
sl_relative_pointer_manager_get_relative_pointer,
|
||||
};
|
||||
|
||||
static void sl_bind_host_relative_pointer_manager(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_relative_pointer_manager* relative_pointer_manager =
|
||||
ctx->relative_pointer_manager;
|
||||
struct sl_host_relative_pointer_manager* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->ctx = ctx;
|
||||
host->resource = wl_resource_create(
|
||||
client, &zwp_relative_pointer_manager_v1_interface, 1, id);
|
||||
wl_resource_set_implementation(
|
||||
host->resource, &sl_relative_pointer_manager_implementation, host,
|
||||
sl_destroy_host_relative_pointer_manager);
|
||||
host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display),
|
||||
relative_pointer_manager->id,
|
||||
&zwp_relative_pointer_manager_v1_interface,
|
||||
wl_resource_get_version(host->resource));
|
||||
zwp_relative_pointer_manager_v1_set_user_data(host->proxy, host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_relative_pointer_manager_global_create(
|
||||
struct sl_context* ctx) {
|
||||
return sl_global_create(ctx, &zwp_relative_pointer_manager_v1_interface, 1,
|
||||
ctx, sl_bind_host_relative_pointer_manager);
|
||||
}
|
778
sommelier/sommelier-seat.c
Normal file
778
sommelier/sommelier-seat.c
Normal file
@ -0,0 +1,778 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "keyboard-extension-unstable-v1-client-protocol.h"
|
||||
|
||||
struct sl_host_keyboard {
|
||||
struct sl_seat* seat;
|
||||
struct wl_resource* resource;
|
||||
struct wl_keyboard* proxy;
|
||||
struct zcr_extended_keyboard_v1* extended_keyboard_proxy;
|
||||
struct wl_resource* focus_resource;
|
||||
struct wl_listener focus_resource_listener;
|
||||
uint32_t focus_serial;
|
||||
struct xkb_keymap* keymap;
|
||||
struct xkb_state* state;
|
||||
xkb_mod_mask_t control_mask;
|
||||
xkb_mod_mask_t alt_mask;
|
||||
xkb_mod_mask_t shift_mask;
|
||||
uint32_t modifiers;
|
||||
struct wl_array pressed_keys;
|
||||
};
|
||||
|
||||
struct sl_host_touch {
|
||||
struct sl_seat* seat;
|
||||
struct wl_resource* resource;
|
||||
struct wl_touch* proxy;
|
||||
struct wl_resource* focus_resource;
|
||||
struct wl_listener focus_resource_listener;
|
||||
};
|
||||
|
||||
static void sl_host_pointer_set_cursor(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t serial,
|
||||
struct wl_resource* surface_resource,
|
||||
int32_t hotspot_x,
|
||||
int32_t hotspot_y) {
|
||||
struct sl_host_pointer* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_surface* host_surface = NULL;
|
||||
double scale = host->seat->ctx->scale;
|
||||
|
||||
if (surface_resource) {
|
||||
host_surface = wl_resource_get_user_data(surface_resource);
|
||||
host_surface->has_role = 1;
|
||||
if (host_surface->contents_width && host_surface->contents_height)
|
||||
wl_surface_commit(host_surface->proxy);
|
||||
}
|
||||
|
||||
wl_pointer_set_cursor(host->proxy, serial,
|
||||
host_surface ? host_surface->proxy : NULL,
|
||||
hotspot_x / scale, hotspot_y / scale);
|
||||
}
|
||||
|
||||
static void sl_host_pointer_release(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static const struct wl_pointer_interface sl_pointer_implementation = {
|
||||
sl_host_pointer_set_cursor, sl_host_pointer_release};
|
||||
|
||||
static void sl_set_last_event_serial(struct wl_resource* surface_resource,
|
||||
uint32_t serial) {
|
||||
struct sl_host_surface* host_surface =
|
||||
wl_resource_get_user_data(surface_resource);
|
||||
|
||||
host_surface->last_event_serial = serial;
|
||||
}
|
||||
|
||||
static void sl_pointer_set_focus(struct sl_host_pointer* host,
|
||||
uint32_t serial,
|
||||
struct sl_host_surface* host_surface,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y) {
|
||||
struct wl_resource* surface_resource =
|
||||
host_surface ? host_surface->resource : NULL;
|
||||
|
||||
if (surface_resource == host->focus_resource)
|
||||
return;
|
||||
|
||||
if (host->focus_resource)
|
||||
wl_pointer_send_leave(host->resource, serial, host->focus_resource);
|
||||
|
||||
wl_list_remove(&host->focus_resource_listener.link);
|
||||
wl_list_init(&host->focus_resource_listener.link);
|
||||
host->focus_resource = surface_resource;
|
||||
host->focus_serial = serial;
|
||||
|
||||
if (surface_resource) {
|
||||
double scale = host->seat->ctx->scale;
|
||||
|
||||
if (host->seat->ctx->xwayland) {
|
||||
// Make sure focus surface is on top before sending enter event.
|
||||
sl_restack_windows(host->seat->ctx, wl_resource_get_id(surface_resource));
|
||||
sl_roundtrip(host->seat->ctx);
|
||||
}
|
||||
|
||||
wl_resource_add_destroy_listener(surface_resource,
|
||||
&host->focus_resource_listener);
|
||||
|
||||
wl_pointer_send_enter(host->resource, serial, surface_resource, x * scale,
|
||||
y * scale);
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_pointer_enter(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y) {
|
||||
struct sl_host_pointer* host = wl_pointer_get_user_data(pointer);
|
||||
struct sl_host_surface* host_surface =
|
||||
surface ? wl_surface_get_user_data(surface) : NULL;
|
||||
|
||||
if (!host_surface)
|
||||
return;
|
||||
|
||||
sl_pointer_set_focus(host, serial, host_surface, x, y);
|
||||
|
||||
if (host->focus_resource)
|
||||
sl_set_last_event_serial(host->focus_resource, serial);
|
||||
host->seat->last_serial = serial;
|
||||
}
|
||||
|
||||
static void sl_pointer_leave(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface) {
|
||||
struct sl_host_pointer* host = wl_pointer_get_user_data(pointer);
|
||||
|
||||
sl_pointer_set_focus(host, serial, NULL, 0, 0);
|
||||
}
|
||||
|
||||
static void sl_pointer_motion(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t time,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y) {
|
||||
struct sl_host_pointer* host = wl_pointer_get_user_data(pointer);
|
||||
double scale = host->seat->ctx->scale;
|
||||
|
||||
wl_pointer_send_motion(host->resource, time, x * scale, y * scale);
|
||||
}
|
||||
|
||||
static void sl_pointer_button(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t button,
|
||||
uint32_t state) {
|
||||
struct sl_host_pointer* host = wl_pointer_get_user_data(pointer);
|
||||
|
||||
wl_pointer_send_button(host->resource, serial, time, button, state);
|
||||
|
||||
if (host->focus_resource)
|
||||
sl_set_last_event_serial(host->focus_resource, serial);
|
||||
host->seat->last_serial = serial;
|
||||
}
|
||||
|
||||
static void sl_pointer_axis(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t time,
|
||||
uint32_t axis,
|
||||
wl_fixed_t value) {
|
||||
struct sl_host_pointer* host = wl_pointer_get_user_data(pointer);
|
||||
double scale = host->seat->ctx->scale;
|
||||
|
||||
wl_pointer_send_axis(host->resource, time, axis, value * scale);
|
||||
}
|
||||
|
||||
static void sl_pointer_frame(void* data, struct wl_pointer* pointer) {
|
||||
struct sl_host_pointer* host = wl_pointer_get_user_data(pointer);
|
||||
|
||||
wl_pointer_send_frame(host->resource);
|
||||
}
|
||||
|
||||
void sl_pointer_axis_source(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t axis_source) {
|
||||
struct sl_host_pointer* host = wl_pointer_get_user_data(pointer);
|
||||
|
||||
wl_pointer_send_axis_source(host->resource, axis_source);
|
||||
}
|
||||
|
||||
static void sl_pointer_axis_stop(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t time,
|
||||
uint32_t axis) {
|
||||
struct sl_host_pointer* host = wl_pointer_get_user_data(pointer);
|
||||
|
||||
wl_pointer_send_axis_stop(host->resource, time, axis);
|
||||
}
|
||||
|
||||
static void sl_pointer_axis_discrete(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t axis,
|
||||
int32_t discrete) {
|
||||
struct sl_host_pointer* host = wl_pointer_get_user_data(pointer);
|
||||
|
||||
wl_pointer_send_axis_discrete(host->resource, axis, discrete);
|
||||
}
|
||||
|
||||
static const struct wl_pointer_listener sl_pointer_listener = {
|
||||
sl_pointer_enter, sl_pointer_leave, sl_pointer_motion,
|
||||
sl_pointer_button, sl_pointer_axis, sl_pointer_frame,
|
||||
sl_pointer_axis_source, sl_pointer_axis_stop, sl_pointer_axis_discrete};
|
||||
|
||||
static void sl_host_keyboard_release(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static const struct wl_keyboard_interface sl_keyboard_implementation = {
|
||||
sl_host_keyboard_release};
|
||||
|
||||
static void sl_keyboard_keymap(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t format,
|
||||
int32_t fd,
|
||||
uint32_t size) {
|
||||
struct sl_host_keyboard* host = wl_keyboard_get_user_data(keyboard);
|
||||
|
||||
wl_keyboard_send_keymap(host->resource, format, fd, size);
|
||||
|
||||
if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
||||
void* data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
|
||||
assert(data != MAP_FAILED);
|
||||
|
||||
if (host->keymap)
|
||||
xkb_keymap_unref(host->keymap);
|
||||
|
||||
host->keymap = xkb_keymap_new_from_string(
|
||||
host->seat->ctx->xkb_context, data, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
|
||||
assert(host->keymap);
|
||||
|
||||
munmap(data, size);
|
||||
|
||||
if (host->state)
|
||||
xkb_state_unref(host->state);
|
||||
host->state = xkb_state_new(host->keymap);
|
||||
assert(host->state);
|
||||
|
||||
host->control_mask = 1 << xkb_keymap_mod_get_index(host->keymap, "Control");
|
||||
host->alt_mask = 1 << xkb_keymap_mod_get_index(host->keymap, "Mod1");
|
||||
host->shift_mask = 1 << xkb_keymap_mod_get_index(host->keymap, "Shift");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void sl_keyboard_set_focus(struct sl_host_keyboard* host,
|
||||
uint32_t serial,
|
||||
struct sl_host_surface* host_surface,
|
||||
struct wl_array* keys) {
|
||||
struct wl_resource* surface_resource =
|
||||
host_surface ? host_surface->resource : NULL;
|
||||
|
||||
if (surface_resource == host->focus_resource)
|
||||
return;
|
||||
|
||||
if (host->focus_resource)
|
||||
wl_keyboard_send_leave(host->resource, serial, host->focus_resource);
|
||||
|
||||
wl_list_remove(&host->focus_resource_listener.link);
|
||||
wl_list_init(&host->focus_resource_listener.link);
|
||||
host->focus_resource = surface_resource;
|
||||
host->focus_serial = serial;
|
||||
|
||||
if (surface_resource) {
|
||||
wl_resource_add_destroy_listener(surface_resource,
|
||||
&host->focus_resource_listener);
|
||||
wl_keyboard_send_enter(host->resource, serial, surface_resource, keys);
|
||||
}
|
||||
|
||||
host->seat->last_serial = serial;
|
||||
}
|
||||
|
||||
static void sl_keyboard_enter(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface,
|
||||
struct wl_array* keys) {
|
||||
struct sl_host_keyboard* host = wl_keyboard_get_user_data(keyboard);
|
||||
struct sl_host_surface* host_surface =
|
||||
surface ? wl_surface_get_user_data(surface) : NULL;
|
||||
|
||||
if (!host_surface)
|
||||
return;
|
||||
|
||||
wl_array_copy(&host->pressed_keys, keys);
|
||||
sl_keyboard_set_focus(host, serial, host_surface, keys);
|
||||
|
||||
host->seat->last_serial = serial;
|
||||
}
|
||||
|
||||
static void sl_keyboard_leave(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface) {
|
||||
struct sl_host_keyboard* host = wl_keyboard_get_user_data(keyboard);
|
||||
struct wl_array array;
|
||||
|
||||
wl_array_init(&array);
|
||||
sl_keyboard_set_focus(host, serial, NULL, &array);
|
||||
}
|
||||
|
||||
static int sl_array_set_add(struct wl_array* array, uint32_t key) {
|
||||
uint32_t* k;
|
||||
|
||||
wl_array_for_each(k, array) {
|
||||
if (*k == key)
|
||||
return 0;
|
||||
}
|
||||
k = wl_array_add(array, sizeof(key));
|
||||
assert(k);
|
||||
*k = key;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sl_array_set_remove(struct wl_array* array, uint32_t key) {
|
||||
uint32_t* k;
|
||||
|
||||
wl_array_for_each(k, array) {
|
||||
if (*k == key) {
|
||||
uint32_t* end = (uint32_t*)((char*)array->data + array->size);
|
||||
|
||||
*k = *(end - 1);
|
||||
array->size -= sizeof(*k);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sl_keyboard_key(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t key,
|
||||
uint32_t state) {
|
||||
struct sl_host_keyboard* host = wl_keyboard_get_user_data(keyboard);
|
||||
int handled = 1;
|
||||
|
||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
if (host->state) {
|
||||
const xkb_keysym_t* symbols;
|
||||
uint32_t num_symbols;
|
||||
xkb_keysym_t symbol = XKB_KEY_NoSymbol;
|
||||
uint32_t code = key + 8;
|
||||
struct sl_accelerator* accelerator;
|
||||
|
||||
num_symbols = xkb_state_key_get_syms(host->state, code, &symbols);
|
||||
if (num_symbols == 1)
|
||||
symbol = symbols[0];
|
||||
|
||||
wl_list_for_each(accelerator, &host->seat->ctx->accelerators, link) {
|
||||
if (host->modifiers != accelerator->modifiers)
|
||||
continue;
|
||||
if (symbol != accelerator->symbol)
|
||||
continue;
|
||||
|
||||
handled = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Forward key pressed event if it should be handled and not
|
||||
// already pressed.
|
||||
if (handled) {
|
||||
if (sl_array_set_add(&host->pressed_keys, key))
|
||||
wl_keyboard_send_key(host->resource, serial, time, key, state);
|
||||
}
|
||||
} else {
|
||||
// Forward key release event if currently pressed.
|
||||
handled = sl_array_set_remove(&host->pressed_keys, key);
|
||||
if (handled)
|
||||
wl_keyboard_send_key(host->resource, serial, time, key, state);
|
||||
}
|
||||
|
||||
if (host->focus_resource)
|
||||
sl_set_last_event_serial(host->focus_resource, serial);
|
||||
host->seat->last_serial = serial;
|
||||
|
||||
if (host->extended_keyboard_proxy) {
|
||||
zcr_extended_keyboard_v1_ack_key(
|
||||
host->extended_keyboard_proxy, serial,
|
||||
handled ? ZCR_EXTENDED_KEYBOARD_V1_HANDLED_STATE_HANDLED
|
||||
: ZCR_EXTENDED_KEYBOARD_V1_HANDLED_STATE_NOT_HANDLED);
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_keyboard_modifiers(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
uint32_t mods_depressed,
|
||||
uint32_t mods_latched,
|
||||
uint32_t mods_locked,
|
||||
uint32_t group) {
|
||||
struct sl_host_keyboard* host = wl_keyboard_get_user_data(keyboard);
|
||||
xkb_mod_mask_t mask;
|
||||
|
||||
wl_keyboard_send_modifiers(host->resource, serial, mods_depressed,
|
||||
mods_latched, mods_locked, group);
|
||||
|
||||
if (host->focus_resource)
|
||||
sl_set_last_event_serial(host->focus_resource, serial);
|
||||
host->seat->last_serial = serial;
|
||||
|
||||
if (!host->keymap)
|
||||
return;
|
||||
|
||||
xkb_state_update_mask(host->state, mods_depressed, mods_latched, mods_locked,
|
||||
0, 0, group);
|
||||
mask = xkb_state_serialize_mods(
|
||||
host->state, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
|
||||
host->modifiers = 0;
|
||||
if (mask & host->control_mask)
|
||||
host->modifiers |= CONTROL_MASK;
|
||||
if (mask & host->alt_mask)
|
||||
host->modifiers |= ALT_MASK;
|
||||
if (mask & host->shift_mask)
|
||||
host->modifiers |= SHIFT_MASK;
|
||||
}
|
||||
|
||||
static void sl_keyboard_repeat_info(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
int32_t rate,
|
||||
int32_t delay) {
|
||||
struct sl_host_keyboard* host = wl_keyboard_get_user_data(keyboard);
|
||||
|
||||
wl_keyboard_send_repeat_info(host->resource, rate, delay);
|
||||
}
|
||||
|
||||
static const struct wl_keyboard_listener sl_keyboard_listener = {
|
||||
sl_keyboard_keymap, sl_keyboard_enter, sl_keyboard_leave,
|
||||
sl_keyboard_key, sl_keyboard_modifiers, sl_keyboard_repeat_info};
|
||||
|
||||
static void sl_host_touch_release(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static const struct wl_touch_interface sl_touch_implementation = {
|
||||
sl_host_touch_release};
|
||||
|
||||
static void sl_host_touch_down(void* data,
|
||||
struct wl_touch* touch,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
struct wl_surface* surface,
|
||||
int32_t id,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y) {
|
||||
struct sl_host_touch* host = wl_touch_get_user_data(touch);
|
||||
struct sl_host_surface* host_surface =
|
||||
surface ? wl_surface_get_user_data(surface) : NULL;
|
||||
double scale = host->seat->ctx->scale;
|
||||
|
||||
if (!host_surface)
|
||||
return;
|
||||
|
||||
if (host_surface->resource != host->focus_resource) {
|
||||
wl_list_remove(&host->focus_resource_listener.link);
|
||||
wl_list_init(&host->focus_resource_listener.link);
|
||||
host->focus_resource = host_surface->resource;
|
||||
wl_resource_add_destroy_listener(host_surface->resource,
|
||||
&host->focus_resource_listener);
|
||||
}
|
||||
|
||||
if (host->seat->ctx->xwayland) {
|
||||
// Make sure focus surface is on top before sending down event.
|
||||
sl_restack_windows(host->seat->ctx,
|
||||
wl_resource_get_id(host_surface->resource));
|
||||
sl_roundtrip(host->seat->ctx);
|
||||
}
|
||||
|
||||
wl_touch_send_down(host->resource, serial, time, host_surface->resource, id,
|
||||
x * scale, y * scale);
|
||||
|
||||
if (host->focus_resource)
|
||||
sl_set_last_event_serial(host->focus_resource, serial);
|
||||
host->seat->last_serial = serial;
|
||||
}
|
||||
|
||||
static void sl_host_touch_up(void* data,
|
||||
struct wl_touch* touch,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
int32_t id) {
|
||||
struct sl_host_touch* host = wl_touch_get_user_data(touch);
|
||||
|
||||
wl_list_remove(&host->focus_resource_listener.link);
|
||||
wl_list_init(&host->focus_resource_listener.link);
|
||||
host->focus_resource = NULL;
|
||||
|
||||
wl_touch_send_up(host->resource, serial, time, id);
|
||||
|
||||
if (host->focus_resource)
|
||||
sl_set_last_event_serial(host->focus_resource, serial);
|
||||
host->seat->last_serial = serial;
|
||||
}
|
||||
|
||||
static void sl_host_touch_motion(void* data,
|
||||
struct wl_touch* touch,
|
||||
uint32_t time,
|
||||
int32_t id,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y) {
|
||||
struct sl_host_touch* host = wl_touch_get_user_data(touch);
|
||||
double scale = host->seat->ctx->scale;
|
||||
|
||||
wl_touch_send_motion(host->resource, time, id, x * scale, y * scale);
|
||||
}
|
||||
|
||||
static void sl_host_touch_frame(void* data, struct wl_touch* touch) {
|
||||
struct sl_host_touch* host = wl_touch_get_user_data(touch);
|
||||
|
||||
wl_touch_send_frame(host->resource);
|
||||
}
|
||||
|
||||
static void sl_host_touch_cancel(void* data, struct wl_touch* touch) {
|
||||
struct sl_host_touch* host = wl_touch_get_user_data(touch);
|
||||
|
||||
wl_touch_send_cancel(host->resource);
|
||||
}
|
||||
|
||||
static const struct wl_touch_listener sl_touch_listener = {
|
||||
sl_host_touch_down, sl_host_touch_up, sl_host_touch_motion,
|
||||
sl_host_touch_frame, sl_host_touch_cancel};
|
||||
|
||||
static void sl_destroy_host_pointer(struct wl_resource* resource) {
|
||||
struct sl_host_pointer* host = wl_resource_get_user_data(resource);
|
||||
|
||||
if (wl_pointer_get_version(host->proxy) >= WL_POINTER_RELEASE_SINCE_VERSION) {
|
||||
wl_pointer_release(host->proxy);
|
||||
} else {
|
||||
wl_pointer_destroy(host->proxy);
|
||||
}
|
||||
wl_list_remove(&host->focus_resource_listener.link);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_pointer_focus_resource_destroyed(struct wl_listener* listener,
|
||||
void* data) {
|
||||
struct sl_host_pointer* host;
|
||||
|
||||
host = wl_container_of(listener, host, focus_resource_listener);
|
||||
sl_pointer_set_focus(host, host->focus_serial, NULL, 0, 0);
|
||||
}
|
||||
|
||||
static void sl_host_seat_get_host_pointer(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id) {
|
||||
struct sl_host_seat* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_pointer* host_pointer;
|
||||
|
||||
host_pointer = malloc(sizeof(*host_pointer));
|
||||
assert(host_pointer);
|
||||
|
||||
host_pointer->seat = host->seat;
|
||||
host_pointer->resource = wl_resource_create(
|
||||
client, &wl_pointer_interface, wl_resource_get_version(resource), id);
|
||||
wl_resource_set_implementation(host_pointer->resource,
|
||||
&sl_pointer_implementation, host_pointer,
|
||||
sl_destroy_host_pointer);
|
||||
host_pointer->proxy = wl_seat_get_pointer(host->proxy);
|
||||
wl_pointer_set_user_data(host_pointer->proxy, host_pointer);
|
||||
wl_pointer_add_listener(host_pointer->proxy, &sl_pointer_listener,
|
||||
host_pointer);
|
||||
wl_list_init(&host_pointer->focus_resource_listener.link);
|
||||
host_pointer->focus_resource_listener.notify =
|
||||
sl_pointer_focus_resource_destroyed;
|
||||
host_pointer->focus_resource = NULL;
|
||||
host_pointer->focus_serial = 0;
|
||||
}
|
||||
|
||||
static void sl_destroy_host_keyboard(struct wl_resource* resource) {
|
||||
struct sl_host_keyboard* host = wl_resource_get_user_data(resource);
|
||||
|
||||
if (host->extended_keyboard_proxy)
|
||||
zcr_extended_keyboard_v1_destroy(host->extended_keyboard_proxy);
|
||||
|
||||
wl_array_release(&host->pressed_keys);
|
||||
if (host->keymap)
|
||||
xkb_keymap_unref(host->keymap);
|
||||
if (host->state)
|
||||
xkb_state_unref(host->state);
|
||||
|
||||
if (wl_keyboard_get_version(host->proxy) >=
|
||||
WL_KEYBOARD_RELEASE_SINCE_VERSION) {
|
||||
wl_keyboard_release(host->proxy);
|
||||
} else {
|
||||
wl_keyboard_destroy(host->proxy);
|
||||
}
|
||||
|
||||
wl_list_remove(&host->focus_resource_listener.link);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_keyboard_focus_resource_destroyed(struct wl_listener* listener,
|
||||
void* data) {
|
||||
struct sl_host_keyboard* host;
|
||||
struct wl_array array;
|
||||
|
||||
host = wl_container_of(listener, host, focus_resource_listener);
|
||||
wl_array_init(&array);
|
||||
sl_keyboard_set_focus(host, host->focus_serial, NULL, &array);
|
||||
}
|
||||
|
||||
static void sl_host_seat_get_host_keyboard(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id) {
|
||||
struct sl_host_seat* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_keyboard* host_keyboard;
|
||||
|
||||
host_keyboard = malloc(sizeof(*host_keyboard));
|
||||
assert(host_keyboard);
|
||||
|
||||
host_keyboard->seat = host->seat;
|
||||
host_keyboard->resource = wl_resource_create(
|
||||
client, &wl_keyboard_interface, wl_resource_get_version(resource), id);
|
||||
wl_resource_set_implementation(host_keyboard->resource,
|
||||
&sl_keyboard_implementation, host_keyboard,
|
||||
sl_destroy_host_keyboard);
|
||||
host_keyboard->proxy = wl_seat_get_keyboard(host->proxy);
|
||||
wl_keyboard_set_user_data(host_keyboard->proxy, host_keyboard);
|
||||
wl_keyboard_add_listener(host_keyboard->proxy, &sl_keyboard_listener,
|
||||
host_keyboard);
|
||||
wl_list_init(&host_keyboard->focus_resource_listener.link);
|
||||
host_keyboard->focus_resource_listener.notify =
|
||||
sl_keyboard_focus_resource_destroyed;
|
||||
host_keyboard->focus_resource = NULL;
|
||||
host_keyboard->focus_serial = 0;
|
||||
host_keyboard->keymap = NULL;
|
||||
host_keyboard->state = NULL;
|
||||
host_keyboard->control_mask = 0;
|
||||
host_keyboard->alt_mask = 0;
|
||||
host_keyboard->shift_mask = 0;
|
||||
host_keyboard->modifiers = 0;
|
||||
wl_array_init(&host_keyboard->pressed_keys);
|
||||
|
||||
if (host->seat->ctx->keyboard_extension) {
|
||||
host_keyboard->extended_keyboard_proxy =
|
||||
zcr_keyboard_extension_v1_get_extended_keyboard(
|
||||
host->seat->ctx->keyboard_extension->internal,
|
||||
host_keyboard->proxy);
|
||||
} else {
|
||||
host_keyboard->extended_keyboard_proxy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_destroy_host_touch(struct wl_resource* resource) {
|
||||
struct sl_host_touch* host = wl_resource_get_user_data(resource);
|
||||
|
||||
if (wl_touch_get_version(host->proxy) >= WL_TOUCH_RELEASE_SINCE_VERSION) {
|
||||
wl_touch_release(host->proxy);
|
||||
} else {
|
||||
wl_touch_destroy(host->proxy);
|
||||
}
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_touch_focus_resource_destroyed(struct wl_listener* listener,
|
||||
void* data) {
|
||||
struct sl_host_touch* host;
|
||||
|
||||
host = wl_container_of(listener, host, focus_resource_listener);
|
||||
wl_list_remove(&host->focus_resource_listener.link);
|
||||
wl_list_init(&host->focus_resource_listener.link);
|
||||
host->focus_resource = NULL;
|
||||
}
|
||||
|
||||
static void sl_host_seat_get_host_touch(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id) {
|
||||
struct sl_host_seat* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_touch* host_touch;
|
||||
|
||||
host_touch = malloc(sizeof(*host_touch));
|
||||
assert(host_touch);
|
||||
|
||||
host_touch->seat = host->seat;
|
||||
host_touch->resource = wl_resource_create(
|
||||
client, &wl_touch_interface, wl_resource_get_version(resource), id);
|
||||
wl_resource_set_implementation(host_touch->resource, &sl_touch_implementation,
|
||||
host_touch, sl_destroy_host_touch);
|
||||
host_touch->proxy = wl_seat_get_touch(host->proxy);
|
||||
wl_touch_set_user_data(host_touch->proxy, host_touch);
|
||||
wl_touch_add_listener(host_touch->proxy, &sl_touch_listener, host_touch);
|
||||
wl_list_init(&host_touch->focus_resource_listener.link);
|
||||
host_touch->focus_resource_listener.notify =
|
||||
sl_touch_focus_resource_destroyed;
|
||||
host_touch->focus_resource = NULL;
|
||||
}
|
||||
|
||||
static void sl_host_seat_release(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_seat* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_seat_release(host->proxy);
|
||||
}
|
||||
|
||||
static const struct wl_seat_interface sl_seat_implementation = {
|
||||
sl_host_seat_get_host_pointer, sl_host_seat_get_host_keyboard,
|
||||
sl_host_seat_get_host_touch, sl_host_seat_release};
|
||||
|
||||
static void sl_seat_capabilities(void* data,
|
||||
struct wl_seat* seat,
|
||||
uint32_t capabilities) {
|
||||
struct sl_host_seat* host = wl_seat_get_user_data(seat);
|
||||
|
||||
wl_seat_send_capabilities(host->resource, capabilities);
|
||||
}
|
||||
|
||||
static void sl_seat_name(void* data, struct wl_seat* seat, const char* name) {
|
||||
struct sl_host_seat* host = wl_seat_get_user_data(seat);
|
||||
|
||||
if (wl_resource_get_version(host->resource) >= WL_SEAT_NAME_SINCE_VERSION)
|
||||
wl_seat_send_name(host->resource, name);
|
||||
}
|
||||
|
||||
static const struct wl_seat_listener sl_seat_listener = {sl_seat_capabilities,
|
||||
sl_seat_name};
|
||||
|
||||
static void sl_destroy_host_seat(struct wl_resource* resource) {
|
||||
struct sl_host_seat* host = wl_resource_get_user_data(resource);
|
||||
|
||||
sl_host_seat_removed(host);
|
||||
|
||||
if (wl_seat_get_version(host->proxy) >= WL_SEAT_RELEASE_SINCE_VERSION)
|
||||
wl_seat_release(host->proxy);
|
||||
else
|
||||
wl_seat_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_bind_host_seat(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_seat* seat = (struct sl_seat*)data;
|
||||
struct sl_host_seat* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->seat = seat;
|
||||
host->resource = wl_resource_create(client, &wl_seat_interface,
|
||||
MIN(version, seat->version), id);
|
||||
wl_resource_set_implementation(host->resource, &sl_seat_implementation, host,
|
||||
sl_destroy_host_seat);
|
||||
host->proxy = wl_registry_bind(wl_display_get_registry(seat->ctx->display),
|
||||
seat->id, &wl_seat_interface,
|
||||
wl_resource_get_version(host->resource));
|
||||
wl_seat_set_user_data(host->proxy, host);
|
||||
wl_seat_add_listener(host->proxy, &sl_seat_listener, host);
|
||||
|
||||
sl_host_seat_added(host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_seat_global_create(struct sl_seat* seat) {
|
||||
return sl_global_create(seat->ctx, &wl_seat_interface, seat->version, seat,
|
||||
sl_bind_host_seat);
|
||||
}
|
234
sommelier/sommelier-shell.c
Normal file
234
sommelier/sommelier-shell.c
Normal file
@ -0,0 +1,234 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
struct sl_host_shell_surface {
|
||||
struct wl_resource* resource;
|
||||
struct wl_shell_surface* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_shell {
|
||||
struct sl_shell* shell;
|
||||
struct wl_resource* resource;
|
||||
struct wl_shell* proxy;
|
||||
};
|
||||
|
||||
static void sl_shell_surface_pong(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t serial) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_shell_surface_pong(host->proxy, serial);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_move(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* seat_resource,
|
||||
uint32_t serial) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_seat* host_seat = wl_resource_get_user_data(seat_resource);
|
||||
|
||||
wl_shell_surface_move(host->proxy, host_seat->proxy, serial);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_resize(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* seat_resource,
|
||||
uint32_t serial,
|
||||
uint32_t edges) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_seat* host_seat = wl_resource_get_user_data(seat_resource);
|
||||
|
||||
wl_shell_surface_resize(host->proxy, host_seat->proxy, serial, edges);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_set_toplevel(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_shell_surface_set_toplevel(host->proxy);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_set_transient(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* parent_resource,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
uint32_t flags) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_surface* host_parent =
|
||||
wl_resource_get_user_data(parent_resource);
|
||||
|
||||
wl_shell_surface_set_transient(host->proxy, host_parent->proxy, x, y, flags);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_set_fullscreen(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t method,
|
||||
uint32_t framerate,
|
||||
struct wl_resource* output_resource) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_output* host_output =
|
||||
output_resource ? wl_resource_get_user_data(output_resource) : NULL;
|
||||
|
||||
wl_shell_surface_set_fullscreen(host->proxy, method, framerate,
|
||||
host_output ? host_output->proxy : NULL);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_set_popup(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* seat_resource,
|
||||
uint32_t serial,
|
||||
struct wl_resource* parent_resource,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
uint32_t flags) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_seat* host_seat = wl_resource_get_user_data(seat_resource);
|
||||
struct sl_host_surface* host_parent =
|
||||
wl_resource_get_user_data(parent_resource);
|
||||
|
||||
wl_shell_surface_set_popup(host->proxy, host_seat->proxy, serial,
|
||||
host_parent->proxy, x, y, flags);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_set_maximized(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* output_resource) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_output* host_output =
|
||||
output_resource ? wl_resource_get_user_data(output_resource) : NULL;
|
||||
|
||||
wl_shell_surface_set_maximized(host->proxy,
|
||||
host_output ? host_output->proxy : NULL);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_set_title(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
const char* title) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_shell_surface_set_title(host->proxy, title);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_set_class(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
const char* clazz) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_shell_surface_set_class(host->proxy, clazz);
|
||||
}
|
||||
|
||||
static const struct wl_shell_surface_interface sl_shell_surface_implementation =
|
||||
{sl_shell_surface_pong, sl_shell_surface_move,
|
||||
sl_shell_surface_resize, sl_shell_surface_set_toplevel,
|
||||
sl_shell_surface_set_transient, sl_shell_surface_set_fullscreen,
|
||||
sl_shell_surface_set_popup, sl_shell_surface_set_maximized,
|
||||
sl_shell_surface_set_title, sl_shell_surface_set_class};
|
||||
|
||||
static void sl_shell_surface_ping(void* data,
|
||||
struct wl_shell_surface* shell_surface,
|
||||
uint32_t serial) {
|
||||
struct sl_host_shell_surface* host =
|
||||
wl_shell_surface_get_user_data(shell_surface);
|
||||
|
||||
wl_shell_surface_send_ping(host->resource, serial);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_configure(void* data,
|
||||
struct wl_shell_surface* shell_surface,
|
||||
uint32_t edges,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_shell_surface* host =
|
||||
wl_shell_surface_get_user_data(shell_surface);
|
||||
|
||||
wl_shell_surface_send_configure(host->resource, edges, width, height);
|
||||
}
|
||||
|
||||
static void sl_shell_surface_popup_done(
|
||||
void* data, struct wl_shell_surface* shell_surface) {
|
||||
struct sl_host_shell_surface* host =
|
||||
wl_shell_surface_get_user_data(shell_surface);
|
||||
|
||||
wl_shell_surface_send_popup_done(host->resource);
|
||||
}
|
||||
|
||||
static const struct wl_shell_surface_listener sl_shell_surface_listener = {
|
||||
sl_shell_surface_ping, sl_shell_surface_configure,
|
||||
sl_shell_surface_popup_done};
|
||||
|
||||
static void sl_destroy_host_shell_surface(struct wl_resource* resource) {
|
||||
struct sl_host_shell_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_shell_surface_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_host_shell_get_shell_surface(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
struct wl_resource* surface_resource) {
|
||||
struct sl_host_shell* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_surface* host_surface =
|
||||
wl_resource_get_user_data(surface_resource);
|
||||
struct sl_host_shell_surface* host_shell_surface;
|
||||
|
||||
host_shell_surface = malloc(sizeof(*host_shell_surface));
|
||||
assert(host_shell_surface);
|
||||
host_shell_surface->resource =
|
||||
wl_resource_create(client, &wl_shell_surface_interface, 1, id);
|
||||
wl_resource_set_implementation(
|
||||
host_shell_surface->resource, &sl_shell_surface_implementation,
|
||||
host_shell_surface, sl_destroy_host_shell_surface);
|
||||
host_shell_surface->proxy =
|
||||
wl_shell_get_shell_surface(host->proxy, host_surface->proxy);
|
||||
wl_shell_surface_set_user_data(host_shell_surface->proxy, host_shell_surface);
|
||||
wl_shell_surface_add_listener(host_shell_surface->proxy,
|
||||
&sl_shell_surface_listener, host_shell_surface);
|
||||
host_surface->has_role = 1;
|
||||
}
|
||||
|
||||
static const struct wl_shell_interface sl_shell_implementation = {
|
||||
sl_host_shell_get_shell_surface};
|
||||
|
||||
static void sl_destroy_host_shell(struct wl_resource* resource) {
|
||||
struct sl_host_shell* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_shell_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_bind_host_shell(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_host_shell* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->shell = ctx->shell;
|
||||
host->resource = wl_resource_create(client, &wl_shell_interface, 1, id);
|
||||
wl_resource_set_implementation(host->resource, &sl_shell_implementation, host,
|
||||
sl_destroy_host_shell);
|
||||
host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display),
|
||||
ctx->shell->id, &wl_shell_interface,
|
||||
wl_resource_get_version(host->resource));
|
||||
wl_shell_set_user_data(host->proxy, host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_shell_global_create(struct sl_context* ctx) {
|
||||
return sl_global_create(ctx, &wl_shell_interface, 1, ctx, sl_bind_host_shell);
|
||||
}
|
328
sommelier/sommelier-shm.c
Normal file
328
sommelier/sommelier-shm.c
Normal file
@ -0,0 +1,328 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "drm-server-protocol.h"
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
|
||||
struct sl_host_shm_pool {
|
||||
struct sl_shm* shm;
|
||||
struct wl_resource* resource;
|
||||
struct wl_shm_pool* proxy;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct sl_host_shm {
|
||||
struct sl_shm* shm;
|
||||
struct wl_resource* resource;
|
||||
struct wl_shm* shm_proxy;
|
||||
struct zwp_linux_dmabuf_v1* linux_dmabuf_proxy;
|
||||
};
|
||||
|
||||
size_t sl_shm_bpp_for_shm_format(uint32_t format) {
|
||||
switch (format) {
|
||||
case WL_SHM_FORMAT_NV12:
|
||||
return 1;
|
||||
case WL_SHM_FORMAT_RGB565:
|
||||
return 2;
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
case WL_SHM_FORMAT_ABGR8888:
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
case WL_SHM_FORMAT_XBGR8888:
|
||||
return 4;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t sl_shm_num_planes_for_shm_format(uint32_t format) {
|
||||
switch (format) {
|
||||
case WL_SHM_FORMAT_NV12:
|
||||
return 2;
|
||||
case WL_SHM_FORMAT_RGB565:
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
case WL_SHM_FORMAT_ABGR8888:
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
case WL_SHM_FORMAT_XBGR8888:
|
||||
return 1;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t sl_y_subsampling_for_shm_format_plane(uint32_t format,
|
||||
size_t plane) {
|
||||
switch (format) {
|
||||
case WL_SHM_FORMAT_NV12: {
|
||||
const size_t subsampling[] = {1, 2};
|
||||
|
||||
assert(plane < ARRAY_SIZE(subsampling));
|
||||
return subsampling[plane];
|
||||
}
|
||||
case WL_SHM_FORMAT_RGB565:
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
case WL_SHM_FORMAT_ABGR8888:
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
case WL_SHM_FORMAT_XBGR8888:
|
||||
return 1;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sl_offset_for_shm_format_plane(uint32_t format,
|
||||
size_t height,
|
||||
size_t stride,
|
||||
size_t plane) {
|
||||
switch (format) {
|
||||
case WL_SHM_FORMAT_NV12: {
|
||||
const size_t offset[] = {0, 1};
|
||||
|
||||
assert(plane < ARRAY_SIZE(offset));
|
||||
return offset[plane] * height * stride;
|
||||
}
|
||||
case WL_SHM_FORMAT_RGB565:
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
case WL_SHM_FORMAT_ABGR8888:
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
case WL_SHM_FORMAT_XBGR8888:
|
||||
return 0;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t sl_size_for_shm_format_plane(uint32_t format,
|
||||
size_t height,
|
||||
size_t stride,
|
||||
size_t plane) {
|
||||
return height / sl_y_subsampling_for_shm_format_plane(format, plane) * stride;
|
||||
}
|
||||
|
||||
static size_t sl_size_for_shm_format(uint32_t format,
|
||||
size_t height,
|
||||
size_t stride) {
|
||||
size_t i, num_planes = sl_shm_num_planes_for_shm_format(format);
|
||||
size_t total_size = 0;
|
||||
|
||||
for (i = 0; i < num_planes; ++i) {
|
||||
size_t size = sl_size_for_shm_format_plane(format, height, stride, i);
|
||||
size_t offset = sl_offset_for_shm_format_plane(format, height, stride, i);
|
||||
total_size = MAX(total_size, size + offset);
|
||||
}
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
static void sl_host_shm_pool_create_host_buffer(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
int32_t offset,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
int32_t stride,
|
||||
uint32_t format) {
|
||||
struct sl_host_shm_pool* host = wl_resource_get_user_data(resource);
|
||||
|
||||
if (host->shm->ctx->shm_driver == SHM_DRIVER_NOOP) {
|
||||
assert(host->proxy);
|
||||
sl_create_host_buffer(client, id,
|
||||
wl_shm_pool_create_buffer(host->proxy, offset, width,
|
||||
height, stride, format),
|
||||
width, height);
|
||||
} else {
|
||||
struct sl_host_buffer* host_buffer =
|
||||
sl_create_host_buffer(client, id, NULL, width, height);
|
||||
|
||||
host_buffer->shm_format = format;
|
||||
host_buffer->shm_mmap = sl_mmap_create(
|
||||
dup(host->fd), sl_size_for_shm_format(format, height, stride),
|
||||
sl_shm_bpp_for_shm_format(format),
|
||||
sl_shm_num_planes_for_shm_format(format), offset, stride,
|
||||
offset + sl_offset_for_shm_format_plane(format, height, stride, 1),
|
||||
stride, sl_y_subsampling_for_shm_format_plane(format, 0),
|
||||
sl_y_subsampling_for_shm_format_plane(format, 1));
|
||||
host_buffer->shm_mmap->buffer_resource = host_buffer->resource;
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_host_shm_pool_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_host_shm_pool_resize(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t size) {
|
||||
struct sl_host_shm_pool* host = wl_resource_get_user_data(resource);
|
||||
|
||||
if (host->proxy)
|
||||
wl_shm_pool_resize(host->proxy, size);
|
||||
}
|
||||
|
||||
static const struct wl_shm_pool_interface sl_shm_pool_implementation = {
|
||||
sl_host_shm_pool_create_host_buffer, sl_host_shm_pool_destroy,
|
||||
sl_host_shm_pool_resize};
|
||||
|
||||
static void sl_destroy_host_shm_pool(struct wl_resource* resource) {
|
||||
struct sl_host_shm_pool* host = wl_resource_get_user_data(resource);
|
||||
|
||||
if (host->fd >= 0)
|
||||
close(host->fd);
|
||||
if (host->proxy)
|
||||
wl_shm_pool_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_shm_create_host_pool(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
int fd,
|
||||
int32_t size) {
|
||||
struct sl_host_shm* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_shm_pool* host_shm_pool;
|
||||
|
||||
host_shm_pool = malloc(sizeof(*host_shm_pool));
|
||||
assert(host_shm_pool);
|
||||
|
||||
host_shm_pool->shm = host->shm;
|
||||
host_shm_pool->fd = -1;
|
||||
host_shm_pool->proxy = NULL;
|
||||
host_shm_pool->resource =
|
||||
wl_resource_create(client, &wl_shm_pool_interface, 1, id);
|
||||
wl_resource_set_implementation(host_shm_pool->resource,
|
||||
&sl_shm_pool_implementation, host_shm_pool,
|
||||
sl_destroy_host_shm_pool);
|
||||
|
||||
switch (host->shm->ctx->shm_driver) {
|
||||
case SHM_DRIVER_NOOP:
|
||||
host_shm_pool->proxy = wl_shm_create_pool(host->shm_proxy, fd, size);
|
||||
wl_shm_pool_set_user_data(host_shm_pool->proxy, host_shm_pool);
|
||||
close(fd);
|
||||
break;
|
||||
case SHM_DRIVER_DMABUF:
|
||||
case SHM_DRIVER_VIRTWL:
|
||||
case SHM_DRIVER_VIRTWL_DMABUF:
|
||||
host_shm_pool->fd = fd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_shm_interface sl_shm_implementation = {
|
||||
sl_shm_create_host_pool};
|
||||
|
||||
static void sl_shm_format(void* data, struct wl_shm* shm, uint32_t format) {
|
||||
struct sl_host_shm* host = wl_shm_get_user_data(shm);
|
||||
|
||||
switch (format) {
|
||||
case WL_SHM_FORMAT_RGB565:
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
case WL_SHM_FORMAT_ABGR8888:
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
case WL_SHM_FORMAT_XBGR8888:
|
||||
wl_shm_send_format(host->resource, format);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_shm_listener sl_shm_listener = {sl_shm_format};
|
||||
|
||||
static void sl_drm_format(void* data,
|
||||
struct zwp_linux_dmabuf_v1* linux_dmabuf,
|
||||
uint32_t format) {
|
||||
struct sl_host_shm* host = zwp_linux_dmabuf_v1_get_user_data(linux_dmabuf);
|
||||
|
||||
// Forward SHM versions of supported formats.
|
||||
switch (format) {
|
||||
case WL_DRM_FORMAT_NV12:
|
||||
wl_shm_send_format(host->resource, WL_SHM_FORMAT_NV12);
|
||||
break;
|
||||
case WL_DRM_FORMAT_RGB565:
|
||||
wl_shm_send_format(host->resource, WL_SHM_FORMAT_RGB565);
|
||||
break;
|
||||
case WL_DRM_FORMAT_ARGB8888:
|
||||
wl_shm_send_format(host->resource, WL_SHM_FORMAT_ARGB8888);
|
||||
break;
|
||||
case WL_DRM_FORMAT_ABGR8888:
|
||||
wl_shm_send_format(host->resource, WL_SHM_FORMAT_ABGR8888);
|
||||
break;
|
||||
case WL_DRM_FORMAT_XRGB8888:
|
||||
wl_shm_send_format(host->resource, WL_SHM_FORMAT_XRGB8888);
|
||||
break;
|
||||
case WL_DRM_FORMAT_XBGR8888:
|
||||
wl_shm_send_format(host->resource, WL_SHM_FORMAT_XBGR8888);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_drm_modifier(void* data,
|
||||
struct zwp_linux_dmabuf_v1* linux_dmabuf,
|
||||
uint32_t format,
|
||||
uint32_t modifier_hi,
|
||||
uint32_t modifier_lo) {}
|
||||
|
||||
static const struct zwp_linux_dmabuf_v1_listener sl_linux_dmabuf_listener = {
|
||||
sl_drm_format, sl_drm_modifier};
|
||||
|
||||
static void sl_destroy_host_shm(struct wl_resource* resource) {
|
||||
struct sl_host_shm* host = wl_resource_get_user_data(resource);
|
||||
|
||||
if (host->shm_proxy)
|
||||
wl_shm_destroy(host->shm_proxy);
|
||||
if (host->linux_dmabuf_proxy)
|
||||
zwp_linux_dmabuf_v1_destroy(host->linux_dmabuf_proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_bind_host_shm(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_host_shm* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->shm = ctx->shm;
|
||||
host->shm_proxy = NULL;
|
||||
host->linux_dmabuf_proxy = NULL;
|
||||
host->resource = wl_resource_create(client, &wl_shm_interface, 1, id);
|
||||
wl_resource_set_implementation(host->resource, &sl_shm_implementation, host,
|
||||
sl_destroy_host_shm);
|
||||
|
||||
switch (ctx->shm_driver) {
|
||||
case SHM_DRIVER_NOOP:
|
||||
case SHM_DRIVER_VIRTWL:
|
||||
host->shm_proxy = wl_registry_bind(
|
||||
wl_display_get_registry(ctx->display), ctx->shm->id,
|
||||
&wl_shm_interface, wl_resource_get_version(host->resource));
|
||||
wl_shm_set_user_data(host->shm_proxy, host);
|
||||
wl_shm_add_listener(host->shm_proxy, &sl_shm_listener, host);
|
||||
break;
|
||||
case SHM_DRIVER_VIRTWL_DMABUF:
|
||||
case SHM_DRIVER_DMABUF:
|
||||
assert(ctx->linux_dmabuf);
|
||||
host->linux_dmabuf_proxy = wl_registry_bind(
|
||||
wl_display_get_registry(ctx->display), ctx->linux_dmabuf->id,
|
||||
&zwp_linux_dmabuf_v1_interface,
|
||||
wl_resource_get_version(host->resource));
|
||||
zwp_linux_dmabuf_v1_set_user_data(host->linux_dmabuf_proxy, host);
|
||||
zwp_linux_dmabuf_v1_add_listener(host->linux_dmabuf_proxy,
|
||||
&sl_linux_dmabuf_listener, host);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct sl_global* sl_shm_global_create(struct sl_context* ctx) {
|
||||
return sl_global_create(ctx, &wl_shm_interface, 1, ctx, sl_bind_host_shm);
|
||||
}
|
153
sommelier/sommelier-subcompositor.c
Normal file
153
sommelier/sommelier-subcompositor.c
Normal file
@ -0,0 +1,153 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
struct sl_host_subcompositor {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct wl_subcompositor* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_subsurface {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct wl_subsurface* proxy;
|
||||
};
|
||||
|
||||
static void sl_subsurface_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_subsurface_set_position(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t x,
|
||||
int32_t y) {
|
||||
struct sl_host_subsurface* host = wl_resource_get_user_data(resource);
|
||||
double scale = host->ctx->scale;
|
||||
|
||||
wl_subsurface_set_position(host->proxy, x / scale, y / scale);
|
||||
}
|
||||
|
||||
static void sl_subsurface_place_above(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* sibling_resource) {
|
||||
struct sl_host_subsurface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_surface* host_sibling =
|
||||
wl_resource_get_user_data(sibling_resource);
|
||||
|
||||
wl_subsurface_place_above(host->proxy, host_sibling->proxy);
|
||||
}
|
||||
|
||||
static void sl_subsurface_place_below(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* sibling_resource) {
|
||||
struct sl_host_subsurface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_surface* host_sibling =
|
||||
wl_resource_get_user_data(sibling_resource);
|
||||
|
||||
wl_subsurface_place_below(host->proxy, host_sibling->proxy);
|
||||
}
|
||||
|
||||
static void sl_subsurface_set_sync(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_subsurface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_subsurface_set_sync(host->proxy);
|
||||
}
|
||||
|
||||
static void sl_subsurface_set_desync(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_subsurface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_subsurface_set_desync(host->proxy);
|
||||
}
|
||||
|
||||
static const struct wl_subsurface_interface sl_subsurface_implementation = {
|
||||
sl_subsurface_destroy, sl_subsurface_set_position,
|
||||
sl_subsurface_place_above, sl_subsurface_place_below,
|
||||
sl_subsurface_set_sync, sl_subsurface_set_desync};
|
||||
|
||||
static void sl_destroy_host_subsurface(struct wl_resource* resource) {
|
||||
struct sl_host_subsurface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_subsurface_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_subcompositor_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_subcompositor_get_subsurface(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
struct wl_resource* surface_resource,
|
||||
struct wl_resource* parent_resource) {
|
||||
struct sl_host_subcompositor* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_surface* host_surface =
|
||||
wl_resource_get_user_data(surface_resource);
|
||||
struct sl_host_surface* host_parent =
|
||||
wl_resource_get_user_data(parent_resource);
|
||||
struct sl_host_subsurface* host_subsurface;
|
||||
|
||||
host_subsurface = malloc(sizeof(*host_subsurface));
|
||||
assert(host_subsurface);
|
||||
|
||||
host_subsurface->ctx = host->ctx;
|
||||
host_subsurface->resource =
|
||||
wl_resource_create(client, &wl_subsurface_interface, 1, id);
|
||||
wl_resource_set_implementation(host_subsurface->resource,
|
||||
&sl_subsurface_implementation, host_subsurface,
|
||||
sl_destroy_host_subsurface);
|
||||
host_subsurface->proxy = wl_subcompositor_get_subsurface(
|
||||
host->proxy, host_surface->proxy, host_parent->proxy);
|
||||
wl_subsurface_set_user_data(host_subsurface->proxy, host_subsurface);
|
||||
host_surface->has_role = 1;
|
||||
}
|
||||
|
||||
static const struct wl_subcompositor_interface sl_subcompositor_implementation =
|
||||
{sl_subcompositor_destroy, sl_subcompositor_get_subsurface};
|
||||
|
||||
static void sl_destroy_host_subcompositor(struct wl_resource* resource) {
|
||||
struct sl_host_subcompositor* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_subcompositor_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_bind_host_subcompositor(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_host_subcompositor* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->ctx = ctx;
|
||||
host->resource =
|
||||
wl_resource_create(client, &wl_subcompositor_interface, 1, id);
|
||||
wl_resource_set_implementation(host->resource,
|
||||
&sl_subcompositor_implementation, host,
|
||||
sl_destroy_host_subcompositor);
|
||||
host->proxy =
|
||||
wl_registry_bind(wl_display_get_registry(ctx->display),
|
||||
ctx->subcompositor->id, &wl_subcompositor_interface, 1);
|
||||
wl_subcompositor_set_user_data(host->proxy, host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_subcompositor_global_create(struct sl_context* ctx) {
|
||||
return sl_global_create(ctx, &wl_subcompositor_interface, 1, ctx,
|
||||
sl_bind_host_subcompositor);
|
||||
}
|
332
sommelier/sommelier-text-input.c
Normal file
332
sommelier/sommelier-text-input.c
Normal file
@ -0,0 +1,332 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "text-input-unstable-v1-client-protocol.h"
|
||||
#include "text-input-unstable-v1-server-protocol.h"
|
||||
|
||||
struct sl_host_text_input_manager {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct zwp_text_input_manager_v1* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_text_input {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct zwp_text_input_v1* proxy;
|
||||
};
|
||||
|
||||
static void sl_text_input_activate(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* seat,
|
||||
struct wl_resource* surface) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_seat* host_seat = wl_resource_get_user_data(seat);
|
||||
struct sl_host_surface* host_surface = wl_resource_get_user_data(surface);
|
||||
|
||||
zwp_text_input_v1_activate(host->proxy, host_seat->proxy,
|
||||
host_surface->proxy);
|
||||
}
|
||||
|
||||
static void sl_text_input_deactivate(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* seat) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_seat* host_seat = wl_resource_get_user_data(seat);
|
||||
|
||||
zwp_text_input_v1_deactivate(host->proxy, host_seat->proxy);
|
||||
}
|
||||
|
||||
static void sl_text_input_show_input_panel(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_v1_show_input_panel(host->proxy);
|
||||
}
|
||||
|
||||
static void sl_text_input_hide_input_panel(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_v1_hide_input_panel(host->proxy);
|
||||
}
|
||||
|
||||
static void sl_text_input_reset(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_v1_reset(host->proxy);
|
||||
}
|
||||
|
||||
static void sl_text_input_set_surrounding_text(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
const char* text,
|
||||
uint32_t cursor,
|
||||
uint32_t anchor) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_v1_set_surrounding_text(host->proxy, text, cursor, anchor);
|
||||
}
|
||||
|
||||
static void sl_text_input_set_content_type(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t hint,
|
||||
uint32_t purpose) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_v1_set_content_type(host->proxy, hint, purpose);
|
||||
}
|
||||
|
||||
static void sl_text_input_set_cursor_rectangle(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_v1_set_cursor_rectangle(host->proxy, x, y, width, height);
|
||||
}
|
||||
|
||||
static void sl_text_input_set_preferred_language(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
const char* language) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_v1_set_preferred_language(host->proxy, language);
|
||||
}
|
||||
|
||||
static void sl_text_input_commit_state(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t serial) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_v1_commit_state(host->proxy, serial);
|
||||
}
|
||||
|
||||
static void sl_text_input_invoke_action(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t button,
|
||||
uint32_t index) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_v1_invoke_action(host->proxy, button, index);
|
||||
}
|
||||
|
||||
static const struct zwp_text_input_v1_interface sl_text_input_implementation = {
|
||||
sl_text_input_activate,
|
||||
sl_text_input_deactivate,
|
||||
sl_text_input_show_input_panel,
|
||||
sl_text_input_hide_input_panel,
|
||||
sl_text_input_reset,
|
||||
sl_text_input_set_surrounding_text,
|
||||
sl_text_input_set_content_type,
|
||||
sl_text_input_set_cursor_rectangle,
|
||||
sl_text_input_set_preferred_language,
|
||||
sl_text_input_commit_state,
|
||||
sl_text_input_invoke_action,
|
||||
};
|
||||
|
||||
static void sl_text_input_enter(void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
struct wl_surface* surface) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
struct sl_host_surface* host_surface = wl_surface_get_user_data(surface);
|
||||
|
||||
zwp_text_input_v1_send_enter(host->resource, host_surface->resource);
|
||||
}
|
||||
|
||||
static void sl_text_input_leave(void* data,
|
||||
struct zwp_text_input_v1* text_input) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_leave(host->resource);
|
||||
}
|
||||
|
||||
static void sl_text_input_modifiers_map(void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
struct wl_array* map) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_modifiers_map(host->resource, map);
|
||||
}
|
||||
|
||||
static void sl_text_input_input_panel_state(
|
||||
void* data, struct zwp_text_input_v1* text_input, uint32_t state) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_input_panel_state(host->resource, state);
|
||||
}
|
||||
|
||||
static void sl_text_input_preedit_string(void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
uint32_t serial,
|
||||
const char* text,
|
||||
const char* commit) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_preedit_string(host->resource, serial, text, commit);
|
||||
}
|
||||
|
||||
static void sl_text_input_preedit_styling(void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
uint32_t index,
|
||||
uint32_t length,
|
||||
uint32_t style) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_preedit_styling(host->resource, index, length, style);
|
||||
}
|
||||
|
||||
static void sl_text_input_preedit_cursor(void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
int32_t index) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_preedit_cursor(host->resource, index);
|
||||
}
|
||||
|
||||
static void sl_text_input_commit_string(void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
uint32_t serial,
|
||||
const char* text) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_commit_string(host->resource, serial, text);
|
||||
}
|
||||
|
||||
static void sl_text_input_cursor_position(void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
int32_t index,
|
||||
int32_t anchor) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_cursor_position(host->resource, index, anchor);
|
||||
}
|
||||
|
||||
static void sl_text_input_delete_surrounding_text(
|
||||
void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
int32_t index,
|
||||
uint32_t length) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_delete_surrounding_text(host->resource, index, length);
|
||||
}
|
||||
|
||||
static void sl_text_input_keysym(void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t sym,
|
||||
uint32_t state,
|
||||
uint32_t modifiers) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_keysym(host->resource, serial, time, sym, state,
|
||||
modifiers);
|
||||
}
|
||||
|
||||
static void sl_text_input_language(void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
uint32_t serial,
|
||||
const char* language) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_language(host->resource, serial, language);
|
||||
}
|
||||
|
||||
static void sl_text_input_text_direction(void* data,
|
||||
struct zwp_text_input_v1* text_input,
|
||||
uint32_t serial,
|
||||
uint32_t direction) {
|
||||
struct sl_host_text_input* host = zwp_text_input_v1_get_user_data(text_input);
|
||||
|
||||
zwp_text_input_v1_send_text_direction(host->resource, serial, direction);
|
||||
}
|
||||
|
||||
static const struct zwp_text_input_v1_listener sl_text_input_listener = {
|
||||
sl_text_input_enter, sl_text_input_leave,
|
||||
sl_text_input_modifiers_map, sl_text_input_input_panel_state,
|
||||
sl_text_input_preedit_string, sl_text_input_preedit_styling,
|
||||
sl_text_input_preedit_cursor, sl_text_input_commit_string,
|
||||
sl_text_input_cursor_position, sl_text_input_delete_surrounding_text,
|
||||
sl_text_input_keysym, sl_text_input_language,
|
||||
sl_text_input_text_direction,
|
||||
};
|
||||
|
||||
static void sl_destroy_host_text_input(struct wl_resource* resource) {
|
||||
struct sl_host_text_input* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_v1_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_text_input_manager_create_text_input(
|
||||
struct wl_client* client, struct wl_resource* resource, uint32_t id) {
|
||||
struct sl_host_text_input_manager* host = wl_resource_get_user_data(resource);
|
||||
struct wl_resource* text_input_resource =
|
||||
wl_resource_create(client, &zwp_text_input_v1_interface, 1, id);
|
||||
struct sl_host_text_input* text_input_host =
|
||||
malloc(sizeof(struct sl_host_text_input));
|
||||
|
||||
text_input_host->resource = text_input_resource;
|
||||
text_input_host->ctx = host->ctx;
|
||||
text_input_host->proxy = zwp_text_input_manager_v1_create_text_input(
|
||||
host->ctx->text_input_manager->internal);
|
||||
wl_resource_set_implementation(text_input_resource,
|
||||
&sl_text_input_implementation, text_input_host,
|
||||
sl_destroy_host_text_input);
|
||||
zwp_text_input_v1_set_user_data(text_input_host->proxy, text_input_host);
|
||||
zwp_text_input_v1_add_listener(text_input_host->proxy,
|
||||
&sl_text_input_listener, text_input_host);
|
||||
}
|
||||
|
||||
static void sl_destroy_host_text_input_manager(struct wl_resource* resource) {
|
||||
struct sl_host_text_input_manager* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zwp_text_input_manager_v1_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static struct zwp_text_input_manager_v1_interface
|
||||
sl_text_input_manager_implementation = {
|
||||
sl_text_input_manager_create_text_input,
|
||||
};
|
||||
|
||||
static void sl_bind_host_text_input_manager(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_text_input_manager* text_input_manager = ctx->text_input_manager;
|
||||
struct sl_host_text_input_manager* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->ctx = ctx;
|
||||
host->resource =
|
||||
wl_resource_create(client, &zwp_text_input_manager_v1_interface, 1, id);
|
||||
wl_resource_set_implementation(host->resource,
|
||||
&sl_text_input_manager_implementation, host,
|
||||
sl_destroy_host_text_input_manager);
|
||||
host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display),
|
||||
text_input_manager->id,
|
||||
&zwp_text_input_manager_v1_interface,
|
||||
wl_resource_get_version(host->resource));
|
||||
zwp_text_input_manager_v1_set_user_data(host->proxy, host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_text_input_manager_global_create(struct sl_context* ctx) {
|
||||
return sl_global_create(ctx, &zwp_text_input_manager_v1_interface, 1, ctx,
|
||||
sl_bind_host_text_input_manager);
|
||||
}
|
128
sommelier/sommelier-viewporter.c
Normal file
128
sommelier/sommelier-viewporter.c
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "viewporter-client-protocol.h"
|
||||
#include "viewporter-server-protocol.h"
|
||||
|
||||
struct sl_host_viewporter {
|
||||
struct sl_viewporter* viewporter;
|
||||
struct wl_resource* resource;
|
||||
struct wp_viewporter* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_viewport {
|
||||
struct wl_resource* resource;
|
||||
struct sl_viewport viewport;
|
||||
};
|
||||
|
||||
static void sl_viewport_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_viewport_set_source(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y,
|
||||
wl_fixed_t width,
|
||||
wl_fixed_t height) {
|
||||
struct sl_host_viewport* host = wl_resource_get_user_data(resource);
|
||||
|
||||
host->viewport.src_x = x;
|
||||
host->viewport.src_y = y;
|
||||
host->viewport.src_width = width;
|
||||
host->viewport.src_height = height;
|
||||
}
|
||||
|
||||
static void sl_viewport_set_destination(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_viewport* host = wl_resource_get_user_data(resource);
|
||||
|
||||
host->viewport.dst_width = width;
|
||||
host->viewport.dst_height = height;
|
||||
}
|
||||
|
||||
static const struct wp_viewport_interface sl_viewport_implementation = {
|
||||
sl_viewport_destroy, sl_viewport_set_source, sl_viewport_set_destination};
|
||||
|
||||
static void sl_destroy_host_viewport(struct wl_resource* resource) {
|
||||
struct sl_host_viewport* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
wl_list_remove(&host->viewport.link);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_viewporter_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_viewporter_get_viewport(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
struct wl_resource* surface_resource) {
|
||||
struct sl_host_surface* host_surface =
|
||||
wl_resource_get_user_data(surface_resource);
|
||||
struct sl_host_viewport* host_viewport;
|
||||
|
||||
host_viewport = malloc(sizeof(*host_viewport));
|
||||
assert(host_viewport);
|
||||
|
||||
host_viewport->viewport.src_x = -1;
|
||||
host_viewport->viewport.src_y = -1;
|
||||
host_viewport->viewport.src_width = -1;
|
||||
host_viewport->viewport.src_height = -1;
|
||||
host_viewport->viewport.dst_width = -1;
|
||||
host_viewport->viewport.dst_height = -1;
|
||||
wl_list_insert(&host_surface->contents_viewport,
|
||||
&host_viewport->viewport.link);
|
||||
host_viewport->resource =
|
||||
wl_resource_create(client, &wp_viewport_interface, 1, id);
|
||||
wl_resource_set_implementation(host_viewport->resource,
|
||||
&sl_viewport_implementation, host_viewport,
|
||||
sl_destroy_host_viewport);
|
||||
}
|
||||
|
||||
static const struct wp_viewporter_interface sl_viewporter_implementation = {
|
||||
sl_viewporter_destroy, sl_viewporter_get_viewport};
|
||||
|
||||
static void sl_destroy_host_viewporter(struct wl_resource* resource) {
|
||||
struct sl_host_viewporter* host = wl_resource_get_user_data(resource);
|
||||
|
||||
wp_viewporter_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_bind_host_viewporter(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_host_viewporter* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->viewporter = ctx->viewporter;
|
||||
host->resource = wl_resource_create(client, &wp_viewporter_interface, 1, id);
|
||||
wl_resource_set_implementation(host->resource, &sl_viewporter_implementation,
|
||||
host, sl_destroy_host_viewporter);
|
||||
host->proxy =
|
||||
wl_registry_bind(wl_display_get_registry(ctx->display),
|
||||
ctx->viewporter->id, &wp_viewporter_interface, 1);
|
||||
wp_viewporter_set_user_data(host->proxy, host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_viewporter_global_create(struct sl_context* ctx) {
|
||||
return sl_global_create(ctx, &wp_viewporter_interface, 1, ctx,
|
||||
sl_bind_host_viewporter);
|
||||
}
|
563
sommelier/sommelier-xdg-shell.c
Normal file
563
sommelier/sommelier-xdg-shell.c
Normal file
@ -0,0 +1,563 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sommelier.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "xdg-shell-unstable-v6-client-protocol.h"
|
||||
#include "xdg-shell-unstable-v6-server-protocol.h"
|
||||
|
||||
struct sl_host_xdg_shell {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct zxdg_shell_v6* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_xdg_surface {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct zxdg_surface_v6* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_xdg_toplevel {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct zxdg_toplevel_v6* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_xdg_popup {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct zxdg_popup_v6* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_xdg_positioner {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct zxdg_positioner_v6* proxy;
|
||||
};
|
||||
|
||||
static void sl_xdg_positioner_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_xdg_positioner_set_size(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
|
||||
double scale = host->ctx->scale;
|
||||
|
||||
zxdg_positioner_v6_set_size(host->proxy, width / scale, height / scale);
|
||||
}
|
||||
|
||||
static void sl_xdg_positioner_set_anchor_rect(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
|
||||
double scale = host->ctx->scale;
|
||||
int32_t x1, y1, x2, y2;
|
||||
|
||||
x1 = x / scale;
|
||||
y1 = y / scale;
|
||||
x2 = (x + width) / scale;
|
||||
y2 = (y + height) / scale;
|
||||
|
||||
zxdg_positioner_v6_set_anchor_rect(host->proxy, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
static void sl_xdg_positioner_set_anchor(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t anchor) {
|
||||
struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_positioner_v6_set_anchor(host->proxy, anchor);
|
||||
}
|
||||
|
||||
static void sl_xdg_positioner_set_gravity(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t gravity) {
|
||||
struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_positioner_v6_set_gravity(host->proxy, gravity);
|
||||
}
|
||||
|
||||
static void sl_xdg_positioner_set_constraint_adjustment(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t constraint_adjustment) {
|
||||
struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_positioner_v6_set_constraint_adjustment(host->proxy,
|
||||
constraint_adjustment);
|
||||
}
|
||||
|
||||
static void sl_xdg_positioner_set_offset(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t x,
|
||||
int32_t y) {
|
||||
struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
|
||||
double scale = host->ctx->scale;
|
||||
|
||||
zxdg_positioner_v6_set_offset(host->proxy, x / scale, y / scale);
|
||||
}
|
||||
|
||||
static const struct zxdg_positioner_v6_interface
|
||||
sl_xdg_positioner_implementation = {
|
||||
sl_xdg_positioner_destroy,
|
||||
sl_xdg_positioner_set_size,
|
||||
sl_xdg_positioner_set_anchor_rect,
|
||||
sl_xdg_positioner_set_anchor,
|
||||
sl_xdg_positioner_set_gravity,
|
||||
sl_xdg_positioner_set_constraint_adjustment,
|
||||
sl_xdg_positioner_set_offset};
|
||||
|
||||
static void sl_destroy_host_xdg_positioner(struct wl_resource* resource) {
|
||||
struct sl_host_xdg_positioner* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_positioner_v6_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_xdg_popup_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_xdg_popup_grab(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* seat_resource,
|
||||
uint32_t serial) {
|
||||
struct sl_host_xdg_popup* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_seat* host_seat = wl_resource_get_user_data(seat_resource);
|
||||
|
||||
zxdg_popup_v6_grab(host->proxy, host_seat->proxy, serial);
|
||||
}
|
||||
|
||||
static const struct zxdg_popup_v6_interface sl_xdg_popup_implementation = {
|
||||
sl_xdg_popup_destroy, sl_xdg_popup_grab};
|
||||
|
||||
static void sl_xdg_popup_configure(void* data,
|
||||
struct zxdg_popup_v6* xdg_popup,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_xdg_popup* host = zxdg_popup_v6_get_user_data(xdg_popup);
|
||||
double scale = host->ctx->scale;
|
||||
int32_t x1, y1, x2, y2;
|
||||
|
||||
x1 = x * scale;
|
||||
y1 = y * scale;
|
||||
x2 = (x + width) * scale;
|
||||
y2 = (y + height) * scale;
|
||||
|
||||
zxdg_popup_v6_send_configure(host->resource, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
static void sl_xdg_popup_popup_done(void* data,
|
||||
struct zxdg_popup_v6* xdg_popup) {
|
||||
struct sl_host_xdg_popup* host = zxdg_popup_v6_get_user_data(xdg_popup);
|
||||
|
||||
zxdg_popup_v6_send_popup_done(host->resource);
|
||||
}
|
||||
|
||||
static const struct zxdg_popup_v6_listener sl_xdg_popup_listener = {
|
||||
sl_xdg_popup_configure, sl_xdg_popup_popup_done};
|
||||
|
||||
static void sl_destroy_host_xdg_popup(struct wl_resource* resource) {
|
||||
struct sl_host_xdg_popup* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_popup_v6_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_set_parent(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* parent_resource) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_xdg_toplevel* host_parent =
|
||||
parent_resource ? wl_resource_get_user_data(parent_resource) : NULL;
|
||||
|
||||
zxdg_toplevel_v6_set_parent(host->proxy,
|
||||
host_parent ? host_parent->proxy : NULL);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_set_title(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
const char* title) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_toplevel_v6_set_title(host->proxy, title);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_set_app_id(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
const char* app_id) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_toplevel_v6_set_app_id(host->proxy, app_id);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_show_window_menu(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* seat_resource,
|
||||
uint32_t serial,
|
||||
int32_t x,
|
||||
int32_t y) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_seat* host_seat =
|
||||
seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
|
||||
|
||||
zxdg_toplevel_v6_show_window_menu(
|
||||
host->proxy, host_seat ? host_seat->proxy : NULL, serial, x, y);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_move(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* seat_resource,
|
||||
uint32_t serial) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_seat* host_seat =
|
||||
seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
|
||||
|
||||
zxdg_toplevel_v6_move(host->proxy, host_seat ? host_seat->proxy : NULL,
|
||||
serial);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_resize(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* seat_resource,
|
||||
uint32_t serial,
|
||||
uint32_t edges) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_seat* host_seat =
|
||||
seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
|
||||
|
||||
zxdg_toplevel_v6_resize(host->proxy, host_seat ? host_seat->proxy : NULL,
|
||||
serial, edges);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_set_max_size(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_toplevel_v6_set_max_size(host->proxy, width, height);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_set_min_size(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_toplevel_v6_set_min_size(host->proxy, width, height);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_set_maximized(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_toplevel_v6_set_maximized(host->proxy);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_unset_maximized(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_toplevel_v6_unset_maximized(host->proxy);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_set_fullscreen(
|
||||
struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
struct wl_resource* output_resource) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_output* host_output =
|
||||
output_resource ? wl_resource_get_user_data(resource) : NULL;
|
||||
|
||||
zxdg_toplevel_v6_set_fullscreen(host->proxy,
|
||||
host_output ? host_output->proxy : NULL);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_unset_fullscreen(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_toplevel_v6_unset_fullscreen(host->proxy);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_set_minimized(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_toplevel_v6_set_minimized(host->proxy);
|
||||
}
|
||||
|
||||
static const struct zxdg_toplevel_v6_interface sl_xdg_toplevel_implementation =
|
||||
{sl_xdg_toplevel_destroy, sl_xdg_toplevel_set_parent,
|
||||
sl_xdg_toplevel_set_title, sl_xdg_toplevel_set_app_id,
|
||||
sl_xdg_toplevel_show_window_menu, sl_xdg_toplevel_move,
|
||||
sl_xdg_toplevel_resize, sl_xdg_toplevel_set_max_size,
|
||||
sl_xdg_toplevel_set_min_size, sl_xdg_toplevel_set_maximized,
|
||||
sl_xdg_toplevel_unset_maximized, sl_xdg_toplevel_set_fullscreen,
|
||||
sl_xdg_toplevel_unset_fullscreen, sl_xdg_toplevel_set_minimized};
|
||||
|
||||
static void sl_xdg_toplevel_configure(void* data,
|
||||
struct zxdg_toplevel_v6* xdg_toplevel,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
struct wl_array* states) {
|
||||
struct sl_host_xdg_toplevel* host =
|
||||
zxdg_toplevel_v6_get_user_data(xdg_toplevel);
|
||||
double scale = host->ctx->scale;
|
||||
|
||||
zxdg_toplevel_v6_send_configure(host->resource, width * scale, height * scale,
|
||||
states);
|
||||
}
|
||||
|
||||
static void sl_xdg_toplevel_close(void* data,
|
||||
struct zxdg_toplevel_v6* xdg_toplevel) {
|
||||
struct sl_host_xdg_toplevel* host =
|
||||
zxdg_toplevel_v6_get_user_data(xdg_toplevel);
|
||||
|
||||
zxdg_toplevel_v6_send_close(host->resource);
|
||||
}
|
||||
|
||||
static const struct zxdg_toplevel_v6_listener sl_xdg_toplevel_listener = {
|
||||
sl_xdg_toplevel_configure, sl_xdg_toplevel_close};
|
||||
|
||||
static void sl_destroy_host_xdg_toplevel(struct wl_resource* resource) {
|
||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_toplevel_v6_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_xdg_surface_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_xdg_surface_get_toplevel(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id) {
|
||||
struct sl_host_xdg_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_xdg_toplevel* host_xdg_toplevel;
|
||||
|
||||
host_xdg_toplevel = malloc(sizeof(*host_xdg_toplevel));
|
||||
assert(host_xdg_toplevel);
|
||||
|
||||
host_xdg_toplevel->ctx = host->ctx;
|
||||
host_xdg_toplevel->resource =
|
||||
wl_resource_create(client, &zxdg_toplevel_v6_interface, 1, id);
|
||||
wl_resource_set_implementation(
|
||||
host_xdg_toplevel->resource, &sl_xdg_toplevel_implementation,
|
||||
host_xdg_toplevel, sl_destroy_host_xdg_toplevel);
|
||||
host_xdg_toplevel->proxy = zxdg_surface_v6_get_toplevel(host->proxy);
|
||||
zxdg_toplevel_v6_set_user_data(host_xdg_toplevel->proxy, host_xdg_toplevel);
|
||||
zxdg_toplevel_v6_add_listener(host_xdg_toplevel->proxy,
|
||||
&sl_xdg_toplevel_listener, host_xdg_toplevel);
|
||||
}
|
||||
|
||||
static void sl_xdg_surface_get_popup(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
struct wl_resource* parent_resource,
|
||||
struct wl_resource* positioner_resource) {
|
||||
struct sl_host_xdg_surface* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_xdg_surface* host_parent =
|
||||
wl_resource_get_user_data(parent_resource);
|
||||
struct sl_host_xdg_positioner* host_positioner =
|
||||
wl_resource_get_user_data(positioner_resource);
|
||||
struct sl_host_xdg_popup* host_xdg_popup;
|
||||
|
||||
host_xdg_popup = malloc(sizeof(*host_xdg_popup));
|
||||
assert(host_xdg_popup);
|
||||
|
||||
host_xdg_popup->ctx = host->ctx;
|
||||
host_xdg_popup->resource =
|
||||
wl_resource_create(client, &zxdg_popup_v6_interface, 1, id);
|
||||
wl_resource_set_implementation(host_xdg_popup->resource,
|
||||
&sl_xdg_popup_implementation, host_xdg_popup,
|
||||
sl_destroy_host_xdg_popup);
|
||||
host_xdg_popup->proxy = zxdg_surface_v6_get_popup(
|
||||
host->proxy, host_parent->proxy, host_positioner->proxy);
|
||||
zxdg_popup_v6_set_user_data(host_xdg_popup->proxy, host_xdg_popup);
|
||||
zxdg_popup_v6_add_listener(host_xdg_popup->proxy, &sl_xdg_popup_listener,
|
||||
host_xdg_popup);
|
||||
}
|
||||
|
||||
static void sl_xdg_surface_set_window_geometry(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t width,
|
||||
int32_t height) {
|
||||
struct sl_host_xdg_surface* host = wl_resource_get_user_data(resource);
|
||||
double scale = host->ctx->scale;
|
||||
int32_t x1, y1, x2, y2;
|
||||
|
||||
x1 = x / scale;
|
||||
y1 = y / scale;
|
||||
x2 = (x + width) / scale;
|
||||
y2 = (y + height) / scale;
|
||||
|
||||
zxdg_surface_v6_set_window_geometry(host->proxy, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
static void sl_xdg_surface_ack_configure(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t serial) {
|
||||
struct sl_host_xdg_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_surface_v6_ack_configure(host->proxy, serial);
|
||||
}
|
||||
|
||||
static const struct zxdg_surface_v6_interface sl_xdg_surface_implementation = {
|
||||
sl_xdg_surface_destroy, sl_xdg_surface_get_toplevel,
|
||||
sl_xdg_surface_get_popup, sl_xdg_surface_set_window_geometry,
|
||||
sl_xdg_surface_ack_configure};
|
||||
|
||||
static void sl_xdg_surface_configure(void* data,
|
||||
struct zxdg_surface_v6* xdg_surface,
|
||||
uint32_t serial) {
|
||||
struct sl_host_xdg_surface* host = zxdg_surface_v6_get_user_data(xdg_surface);
|
||||
|
||||
zxdg_surface_v6_send_configure(host->resource, serial);
|
||||
}
|
||||
|
||||
static const struct zxdg_surface_v6_listener sl_xdg_surface_listener = {
|
||||
sl_xdg_surface_configure};
|
||||
|
||||
static void sl_destroy_host_xdg_surface(struct wl_resource* resource) {
|
||||
struct sl_host_xdg_surface* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_surface_v6_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_xdg_shell_destroy(struct wl_client* client,
|
||||
struct wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void sl_xdg_shell_create_positioner(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id) {
|
||||
struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_xdg_positioner* host_xdg_positioner;
|
||||
|
||||
host_xdg_positioner = malloc(sizeof(*host_xdg_positioner));
|
||||
assert(host_xdg_positioner);
|
||||
|
||||
host_xdg_positioner->ctx = host->ctx;
|
||||
host_xdg_positioner->resource =
|
||||
wl_resource_create(client, &zxdg_positioner_v6_interface, 1, id);
|
||||
wl_resource_set_implementation(
|
||||
host_xdg_positioner->resource, &sl_xdg_positioner_implementation,
|
||||
host_xdg_positioner, sl_destroy_host_xdg_positioner);
|
||||
host_xdg_positioner->proxy = zxdg_shell_v6_create_positioner(host->proxy);
|
||||
zxdg_positioner_v6_set_user_data(host_xdg_positioner->proxy,
|
||||
host_xdg_positioner);
|
||||
}
|
||||
|
||||
static void sl_xdg_shell_get_xdg_surface(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t id,
|
||||
struct wl_resource* surface_resource) {
|
||||
struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
|
||||
struct sl_host_surface* host_surface =
|
||||
wl_resource_get_user_data(surface_resource);
|
||||
struct sl_host_xdg_surface* host_xdg_surface;
|
||||
|
||||
host_xdg_surface = malloc(sizeof(*host_xdg_surface));
|
||||
assert(host_xdg_surface);
|
||||
|
||||
host_xdg_surface->ctx = host->ctx;
|
||||
host_xdg_surface->resource =
|
||||
wl_resource_create(client, &zxdg_surface_v6_interface, 1, id);
|
||||
wl_resource_set_implementation(host_xdg_surface->resource,
|
||||
&sl_xdg_surface_implementation,
|
||||
host_xdg_surface, sl_destroy_host_xdg_surface);
|
||||
host_xdg_surface->proxy =
|
||||
zxdg_shell_v6_get_xdg_surface(host->proxy, host_surface->proxy);
|
||||
zxdg_surface_v6_set_user_data(host_xdg_surface->proxy, host_xdg_surface);
|
||||
zxdg_surface_v6_add_listener(host_xdg_surface->proxy,
|
||||
&sl_xdg_surface_listener, host_xdg_surface);
|
||||
host_surface->has_role = 1;
|
||||
}
|
||||
|
||||
static void sl_xdg_shell_pong(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t serial) {
|
||||
struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_shell_v6_pong(host->proxy, serial);
|
||||
}
|
||||
|
||||
static const struct zxdg_shell_v6_interface sl_xdg_shell_implementation = {
|
||||
sl_xdg_shell_destroy, sl_xdg_shell_create_positioner,
|
||||
sl_xdg_shell_get_xdg_surface, sl_xdg_shell_pong};
|
||||
|
||||
static void sl_xdg_shell_ping(void* data,
|
||||
struct zxdg_shell_v6* xdg_shell,
|
||||
uint32_t serial) {
|
||||
struct sl_host_xdg_shell* host = zxdg_shell_v6_get_user_data(xdg_shell);
|
||||
|
||||
zxdg_shell_v6_send_ping(host->resource, serial);
|
||||
}
|
||||
|
||||
static const struct zxdg_shell_v6_listener sl_xdg_shell_listener = {
|
||||
sl_xdg_shell_ping};
|
||||
|
||||
static void sl_destroy_host_xdg_shell(struct wl_resource* resource) {
|
||||
struct sl_host_xdg_shell* host = wl_resource_get_user_data(resource);
|
||||
|
||||
zxdg_shell_v6_destroy(host->proxy);
|
||||
wl_resource_set_user_data(resource, NULL);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void sl_bind_host_xdg_shell(struct wl_client* client,
|
||||
void* data,
|
||||
uint32_t version,
|
||||
uint32_t id) {
|
||||
struct sl_context* ctx = (struct sl_context*)data;
|
||||
struct sl_host_xdg_shell* host;
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
assert(host);
|
||||
host->ctx = ctx;
|
||||
host->resource = wl_resource_create(client, &zxdg_shell_v6_interface, 1, id);
|
||||
wl_resource_set_implementation(host->resource, &sl_xdg_shell_implementation,
|
||||
host, sl_destroy_host_xdg_shell);
|
||||
host->proxy =
|
||||
wl_registry_bind(wl_display_get_registry(ctx->display),
|
||||
ctx->xdg_shell->id, &zxdg_shell_v6_interface, 1);
|
||||
zxdg_shell_v6_set_user_data(host->proxy, host);
|
||||
zxdg_shell_v6_add_listener(host->proxy, &sl_xdg_shell_listener, host);
|
||||
}
|
||||
|
||||
struct sl_global* sl_xdg_shell_global_create(struct sl_context* ctx) {
|
||||
return sl_global_create(ctx, &zxdg_shell_v6_interface, 1, ctx,
|
||||
sl_bind_host_xdg_shell);
|
||||
}
|
4146
sommelier/sommelier.c
Normal file
4146
sommelier/sommelier.c
Normal file
File diff suppressed because it is too large
Load Diff
547
sommelier/sommelier.h
Normal file
547
sommelier/sommelier.h
Normal file
@ -0,0 +1,547 @@
|
||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef VM_TOOLS_SOMMELIER_SOMMELIER_H_
|
||||
#define VM_TOOLS_SOMMELIER_SOMMELIER_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wayland-util.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define SOMMELIER_VERSION "0.20"
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
#define UNUSED(x) ((void)(x))
|
||||
|
||||
#define CONTROL_MASK (1 << 0)
|
||||
#define ALT_MASK (1 << 1)
|
||||
#define SHIFT_MASK (1 << 2)
|
||||
|
||||
struct sl_global;
|
||||
struct sl_compositor;
|
||||
struct sl_shm;
|
||||
struct sl_shell;
|
||||
struct sl_data_device_manager;
|
||||
struct sl_data_offer;
|
||||
struct sl_data_source;
|
||||
struct sl_xdg_shell;
|
||||
struct sl_subcompositor;
|
||||
struct sl_aura_shell;
|
||||
struct sl_viewporter;
|
||||
struct sl_linux_dmabuf;
|
||||
struct sl_keyboard_extension;
|
||||
struct sl_text_input_manager;
|
||||
struct sl_relative_pointer_manager;
|
||||
struct sl_window;
|
||||
struct zaura_shell;
|
||||
struct zcr_keyboard_extension_v1;
|
||||
|
||||
enum {
|
||||
ATOM_WM_S0,
|
||||
ATOM_WM_PROTOCOLS,
|
||||
ATOM_WM_STATE,
|
||||
ATOM_WM_CHANGE_STATE,
|
||||
ATOM_WM_DELETE_WINDOW,
|
||||
ATOM_WM_TAKE_FOCUS,
|
||||
ATOM_WM_CLIENT_LEADER,
|
||||
ATOM_WL_SURFACE_ID,
|
||||
ATOM_UTF8_STRING,
|
||||
ATOM_MOTIF_WM_HINTS,
|
||||
ATOM_NET_FRAME_EXTENTS,
|
||||
ATOM_NET_STARTUP_ID,
|
||||
ATOM_NET_SUPPORTING_WM_CHECK,
|
||||
ATOM_NET_WM_NAME,
|
||||
ATOM_NET_WM_MOVERESIZE,
|
||||
ATOM_NET_WM_STATE,
|
||||
ATOM_NET_WM_STATE_FULLSCREEN,
|
||||
ATOM_NET_WM_STATE_MAXIMIZED_VERT,
|
||||
ATOM_NET_WM_STATE_MAXIMIZED_HORZ,
|
||||
ATOM_CLIPBOARD,
|
||||
ATOM_CLIPBOARD_MANAGER,
|
||||
ATOM_TARGETS,
|
||||
ATOM_TIMESTAMP,
|
||||
ATOM_TEXT,
|
||||
ATOM_INCR,
|
||||
ATOM_WL_SELECTION,
|
||||
ATOM_GTK_THEME_VARIANT,
|
||||
ATOM_LAST = ATOM_GTK_THEME_VARIANT,
|
||||
};
|
||||
|
||||
enum {
|
||||
SHM_DRIVER_NOOP,
|
||||
SHM_DRIVER_DMABUF,
|
||||
SHM_DRIVER_VIRTWL,
|
||||
SHM_DRIVER_VIRTWL_DMABUF,
|
||||
};
|
||||
|
||||
enum {
|
||||
DATA_DRIVER_NOOP,
|
||||
DATA_DRIVER_VIRTWL,
|
||||
};
|
||||
|
||||
struct sl_context {
|
||||
char** runprog;
|
||||
struct wl_display* display;
|
||||
struct wl_display* host_display;
|
||||
struct wl_client* client;
|
||||
struct sl_compositor* compositor;
|
||||
struct sl_subcompositor* subcompositor;
|
||||
struct sl_shm* shm;
|
||||
struct sl_shell* shell;
|
||||
struct sl_data_device_manager* data_device_manager;
|
||||
struct sl_xdg_shell* xdg_shell;
|
||||
struct sl_aura_shell* aura_shell;
|
||||
struct sl_viewporter* viewporter;
|
||||
struct sl_linux_dmabuf* linux_dmabuf;
|
||||
struct sl_keyboard_extension* keyboard_extension;
|
||||
struct sl_text_input_manager* text_input_manager;
|
||||
struct sl_relative_pointer_manager* relative_pointer_manager;
|
||||
struct wl_list outputs;
|
||||
struct wl_list seats;
|
||||
struct wl_event_source* display_event_source;
|
||||
struct wl_event_source* display_ready_event_source;
|
||||
struct wl_event_source* sigchld_event_source;
|
||||
struct wl_array dpi;
|
||||
int shm_driver;
|
||||
int data_driver;
|
||||
int wm_fd;
|
||||
int virtwl_fd;
|
||||
int virtwl_ctx_fd;
|
||||
int virtwl_socket_fd;
|
||||
struct wl_event_source* virtwl_ctx_event_source;
|
||||
struct wl_event_source* virtwl_socket_event_source;
|
||||
const char* drm_device;
|
||||
struct gbm_device* gbm;
|
||||
int xwayland;
|
||||
pid_t xwayland_pid;
|
||||
pid_t child_pid;
|
||||
pid_t peer_pid;
|
||||
struct xkb_context* xkb_context;
|
||||
struct wl_list accelerators;
|
||||
struct wl_list registries;
|
||||
struct wl_list globals;
|
||||
struct wl_list host_outputs;
|
||||
int next_global_id;
|
||||
xcb_connection_t* connection;
|
||||
struct wl_event_source* connection_event_source;
|
||||
const xcb_query_extension_reply_t* xfixes_extension;
|
||||
xcb_screen_t* screen;
|
||||
xcb_window_t window;
|
||||
struct wl_list windows, unpaired_windows;
|
||||
struct sl_window* host_focus_window;
|
||||
int needs_set_input_focus;
|
||||
double desired_scale;
|
||||
double scale;
|
||||
const char* application_id;
|
||||
int exit_with_child;
|
||||
const char* sd_notify;
|
||||
int clipboard_manager;
|
||||
uint32_t frame_color;
|
||||
uint32_t dark_frame_color;
|
||||
struct sl_host_seat* default_seat;
|
||||
xcb_window_t selection_window;
|
||||
xcb_window_t selection_owner;
|
||||
int selection_incremental_transfer;
|
||||
xcb_selection_request_event_t selection_request;
|
||||
xcb_timestamp_t selection_timestamp;
|
||||
struct wl_data_device* selection_data_device;
|
||||
struct sl_data_offer* selection_data_offer;
|
||||
struct sl_data_source* selection_data_source;
|
||||
int selection_data_source_send_fd;
|
||||
struct wl_list selection_data_source_send_pending;
|
||||
struct wl_event_source* selection_send_event_source;
|
||||
xcb_get_property_reply_t* selection_property_reply;
|
||||
int selection_property_offset;
|
||||
struct wl_event_source* selection_event_source;
|
||||
xcb_atom_t selection_data_type;
|
||||
struct wl_array selection_data;
|
||||
int selection_data_offer_receive_fd;
|
||||
int selection_data_ack_pending;
|
||||
union {
|
||||
const char* name;
|
||||
xcb_intern_atom_cookie_t cookie;
|
||||
xcb_atom_t value;
|
||||
} atoms[ATOM_LAST + 1];
|
||||
xcb_visualid_t visual_ids[256];
|
||||
xcb_colormap_t colormaps[256];
|
||||
};
|
||||
|
||||
struct sl_compositor {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
uint32_t version;
|
||||
struct sl_global* host_global;
|
||||
struct wl_compositor* internal;
|
||||
};
|
||||
|
||||
struct sl_shm {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
struct sl_global* host_global;
|
||||
struct wl_shm* internal;
|
||||
};
|
||||
|
||||
struct sl_seat {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
uint32_t version;
|
||||
struct sl_global* host_global;
|
||||
uint32_t last_serial;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct sl_host_pointer {
|
||||
struct sl_seat* seat;
|
||||
struct wl_resource* resource;
|
||||
struct wl_pointer* proxy;
|
||||
struct wl_resource* focus_resource;
|
||||
struct wl_listener focus_resource_listener;
|
||||
uint32_t focus_serial;
|
||||
};
|
||||
|
||||
struct sl_relative_pointer_manager {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
struct sl_global* host_global;
|
||||
struct zwp_relative_pointer_manager_v1* internal;
|
||||
};
|
||||
|
||||
struct sl_viewport {
|
||||
struct wl_list link;
|
||||
wl_fixed_t src_x;
|
||||
wl_fixed_t src_y;
|
||||
wl_fixed_t src_width;
|
||||
wl_fixed_t src_height;
|
||||
int32_t dst_width;
|
||||
int32_t dst_height;
|
||||
};
|
||||
|
||||
struct sl_host_callback {
|
||||
struct wl_resource* resource;
|
||||
struct wl_callback* proxy;
|
||||
};
|
||||
|
||||
struct sl_host_surface {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct wl_surface* proxy;
|
||||
struct wp_viewport* viewport;
|
||||
uint32_t contents_width;
|
||||
uint32_t contents_height;
|
||||
int32_t contents_scale;
|
||||
struct wl_list contents_viewport;
|
||||
struct sl_mmap* contents_shm_mmap;
|
||||
int has_role;
|
||||
int has_output;
|
||||
uint32_t last_event_serial;
|
||||
struct sl_output_buffer* current_buffer;
|
||||
struct wl_list released_buffers;
|
||||
struct wl_list busy_buffers;
|
||||
};
|
||||
|
||||
struct sl_host_buffer {
|
||||
struct wl_resource* resource;
|
||||
struct wl_buffer* proxy;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
struct sl_mmap* shm_mmap;
|
||||
uint32_t shm_format;
|
||||
struct sl_sync_point* sync_point;
|
||||
};
|
||||
|
||||
struct sl_data_source_send_request {
|
||||
int fd;
|
||||
xcb_intern_atom_cookie_t cookie;
|
||||
struct sl_data_source* data_source;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct sl_subcompositor {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
struct sl_global* host_global;
|
||||
};
|
||||
|
||||
struct sl_shell {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
struct sl_global* host_global;
|
||||
};
|
||||
|
||||
struct sl_output {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
uint32_t version;
|
||||
struct sl_global* host_global;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct sl_host_output {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct wl_output* proxy;
|
||||
struct zaura_output* aura_output;
|
||||
int internal;
|
||||
int x;
|
||||
int y;
|
||||
int physical_width;
|
||||
int physical_height;
|
||||
int subpixel;
|
||||
char* make;
|
||||
char* model;
|
||||
int transform;
|
||||
uint32_t flags;
|
||||
int width;
|
||||
int height;
|
||||
int refresh;
|
||||
int scale_factor;
|
||||
int current_scale;
|
||||
int preferred_scale;
|
||||
int device_scale_factor;
|
||||
int expecting_scale;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct sl_host_seat {
|
||||
struct sl_seat* seat;
|
||||
struct wl_resource* resource;
|
||||
struct wl_seat* proxy;
|
||||
};
|
||||
|
||||
struct sl_accelerator {
|
||||
struct wl_list link;
|
||||
uint32_t modifiers;
|
||||
xkb_keysym_t symbol;
|
||||
};
|
||||
|
||||
struct sl_keyboard_extension {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
struct zcr_keyboard_extension_v1* internal;
|
||||
};
|
||||
|
||||
struct sl_data_device_manager {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
uint32_t version;
|
||||
struct sl_global* host_global;
|
||||
struct wl_data_device_manager* internal;
|
||||
};
|
||||
|
||||
struct sl_data_offer {
|
||||
struct sl_context* ctx;
|
||||
struct wl_data_offer* internal;
|
||||
struct wl_array atoms; // Contains xcb_atom_t
|
||||
struct wl_array cookies; // Contains xcb_intern_atom_cookie_t
|
||||
};
|
||||
|
||||
struct sl_text_input_manager {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
struct sl_global* host_global;
|
||||
struct zwp_text_input_manager_v1* internal;
|
||||
};
|
||||
|
||||
struct sl_viewporter {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
struct sl_global* host_viewporter_global;
|
||||
struct wp_viewporter* internal;
|
||||
};
|
||||
|
||||
struct sl_xdg_shell {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
struct sl_global* host_global;
|
||||
struct zxdg_shell_v6* internal;
|
||||
};
|
||||
|
||||
struct sl_aura_shell {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
uint32_t version;
|
||||
struct sl_global* host_gtk_shell_global;
|
||||
struct zaura_shell* internal;
|
||||
};
|
||||
|
||||
struct sl_linux_dmabuf {
|
||||
struct sl_context* ctx;
|
||||
uint32_t id;
|
||||
uint32_t version;
|
||||
struct sl_global* host_drm_global;
|
||||
struct zwp_linux_dmabuf_v1* internal;
|
||||
};
|
||||
|
||||
struct sl_global {
|
||||
struct sl_context* ctx;
|
||||
const struct wl_interface* interface;
|
||||
uint32_t name;
|
||||
uint32_t version;
|
||||
void* data;
|
||||
wl_global_bind_func_t bind;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct sl_host_registry {
|
||||
struct sl_context* ctx;
|
||||
struct wl_resource* resource;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
typedef void (*sl_begin_end_access_func_t)(int fd);
|
||||
|
||||
struct sl_mmap {
|
||||
int refcount;
|
||||
int fd;
|
||||
void* addr;
|
||||
size_t size;
|
||||
size_t bpp;
|
||||
size_t num_planes;
|
||||
size_t offset[2];
|
||||
size_t stride[2];
|
||||
size_t y_ss[2];
|
||||
sl_begin_end_access_func_t begin_write;
|
||||
sl_begin_end_access_func_t end_write;
|
||||
struct wl_resource* buffer_resource;
|
||||
};
|
||||
|
||||
typedef void (*sl_sync_func_t)(struct sl_context *ctx,
|
||||
struct sl_sync_point* sync_point);
|
||||
|
||||
struct sl_sync_point {
|
||||
int fd;
|
||||
sl_sync_func_t sync;
|
||||
};
|
||||
|
||||
struct sl_config {
|
||||
uint32_t serial;
|
||||
uint32_t mask;
|
||||
uint32_t values[5];
|
||||
uint32_t states_length;
|
||||
uint32_t states[3];
|
||||
};
|
||||
|
||||
struct sl_window {
|
||||
struct sl_context* ctx;
|
||||
xcb_window_t id;
|
||||
xcb_window_t frame_id;
|
||||
uint32_t host_surface_id;
|
||||
int unpaired;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
int border_width;
|
||||
int depth;
|
||||
int managed;
|
||||
int realized;
|
||||
int activated;
|
||||
int allow_resize;
|
||||
xcb_window_t transient_for;
|
||||
xcb_window_t client_leader;
|
||||
int decorated;
|
||||
char* name;
|
||||
char* clazz;
|
||||
char* startup_id;
|
||||
int dark_frame;
|
||||
uint32_t size_flags;
|
||||
int min_width;
|
||||
int min_height;
|
||||
int max_width;
|
||||
int max_height;
|
||||
struct sl_config next_config;
|
||||
struct sl_config pending_config;
|
||||
struct zxdg_surface_v6* xdg_surface;
|
||||
struct zxdg_toplevel_v6* xdg_toplevel;
|
||||
struct zxdg_popup_v6* xdg_popup;
|
||||
struct zaura_surface* aura_surface;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct sl_host_buffer* sl_create_host_buffer(struct wl_client* client,
|
||||
uint32_t id,
|
||||
struct wl_buffer* proxy,
|
||||
int32_t width,
|
||||
int32_t height);
|
||||
|
||||
struct sl_global* sl_global_create(struct sl_context* ctx,
|
||||
const struct wl_interface* interface,
|
||||
int version,
|
||||
void* data,
|
||||
wl_global_bind_func_t bind);
|
||||
|
||||
struct sl_global* sl_compositor_global_create(struct sl_context* ctx);
|
||||
|
||||
size_t sl_shm_bpp_for_shm_format(uint32_t format);
|
||||
|
||||
size_t sl_shm_num_planes_for_shm_format(uint32_t format);
|
||||
|
||||
struct sl_global* sl_shm_global_create(struct sl_context* ctx);
|
||||
|
||||
struct sl_global* sl_subcompositor_global_create(struct sl_context* ctx);
|
||||
|
||||
struct sl_global* sl_shell_global_create(struct sl_context* ctx);
|
||||
|
||||
double sl_output_aura_scale_factor_to_double(int scale_factor);
|
||||
|
||||
void sl_output_send_host_output_state(struct sl_host_output* host);
|
||||
|
||||
struct sl_global* sl_output_global_create(struct sl_output* output);
|
||||
|
||||
struct sl_global* sl_seat_global_create(struct sl_seat* seat);
|
||||
|
||||
struct sl_global* sl_relative_pointer_manager_global_create(
|
||||
struct sl_context* ctx);
|
||||
|
||||
struct sl_global* sl_data_device_manager_global_create(struct sl_context* ctx);
|
||||
|
||||
struct sl_global* sl_viewporter_global_create(struct sl_context* ctx);
|
||||
|
||||
struct sl_global* sl_xdg_shell_global_create(struct sl_context* ctx);
|
||||
|
||||
struct sl_global* sl_gtk_shell_global_create(struct sl_context* ctx);
|
||||
|
||||
struct sl_global* sl_drm_global_create(struct sl_context* ctx);
|
||||
|
||||
struct sl_global* sl_text_input_manager_global_create(struct sl_context* ctx);
|
||||
|
||||
void sl_set_display_implementation(struct sl_context* ctx);
|
||||
|
||||
struct sl_mmap* sl_mmap_create(int fd,
|
||||
size_t size,
|
||||
size_t bpp,
|
||||
size_t num_planes,
|
||||
size_t offset0,
|
||||
size_t stride0,
|
||||
size_t offset1,
|
||||
size_t stride1,
|
||||
size_t y_ss0,
|
||||
size_t y_ss1);
|
||||
struct sl_mmap* sl_mmap_ref(struct sl_mmap* map);
|
||||
void sl_mmap_unref(struct sl_mmap* map);
|
||||
|
||||
struct sl_sync_point* sl_sync_point_create(int fd);
|
||||
void sl_sync_point_destroy(struct sl_sync_point* sync_point);
|
||||
|
||||
void sl_host_seat_added(struct sl_host_seat* host);
|
||||
void sl_host_seat_removed(struct sl_host_seat* host);
|
||||
|
||||
void sl_restack_windows(struct sl_context* ctx, uint32_t focus_resource_id);
|
||||
|
||||
void sl_roundtrip(struct sl_context* ctx);
|
||||
|
||||
int sl_process_pending_configure_acks(struct sl_window* window,
|
||||
struct sl_host_surface* host_surface);
|
||||
|
||||
void sl_window_update(struct sl_window* window);
|
||||
|
||||
#endif // VM_TOOLS_SOMMELIER_SOMMELIER_H_
|
34
sommelier/wayland-protocol.gypi
Normal file
34
sommelier/wayland-protocol.gypi
Normal file
@ -0,0 +1,34 @@
|
||||
# Caution!: GYP to GN migration is happening. If you update this file, please
|
||||
# update vm_tools/sommelier/wayland-protocol.gni too accordingly.
|
||||
{
|
||||
'variables': {
|
||||
'wayland_dir': '<(SHARED_INTERMEDIATE_DIR)/<(wayland_out_dir)',
|
||||
'wayland_in_dir%': '.',
|
||||
},
|
||||
'rules': [
|
||||
{
|
||||
'rule_name': 'genwayland',
|
||||
'extension': 'xml',
|
||||
'outputs': [
|
||||
'<(wayland_dir)/<(RULE_INPUT_ROOT)-protocol.c',
|
||||
'<(wayland_dir)/<(RULE_INPUT_ROOT)-client-protocol.h',
|
||||
'<(wayland_dir)/<(RULE_INPUT_ROOT)-server-protocol.h',
|
||||
],
|
||||
'action': [
|
||||
'sh',
|
||||
'-c',
|
||||
'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',
|
||||
],
|
||||
'message': 'Generating Wayland C code from <(RULE_INPUT_PATH)',
|
||||
'process_outputs_as_sources': 1,
|
||||
},
|
||||
],
|
||||
# This target exports a hard dependency because it generates header
|
||||
# files.
|
||||
'hard_dependency': 1,
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'<(wayland_dir)',
|
||||
],
|
||||
},
|
||||
}
|
65
sommelier/wayland_protocol.gni
Normal file
65
sommelier/wayland_protocol.gni
Normal file
@ -0,0 +1,65 @@
|
||||
# Copyright 2019 The Chromium OS Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# GN template to generate static library for given Wayland protorol description files.
|
||||
# Parameters:
|
||||
# sources
|
||||
# Wayland protocol description XML file paths.
|
||||
# out_dir (optional)
|
||||
# Directory to output generated source files. Relative to gen/ directory.
|
||||
template("wayland_protocol_library") {
|
||||
forward_variables_from(invoker, [ "out_dir" ])
|
||||
if (!defined(out_dir)) {
|
||||
out_dir = "."
|
||||
}
|
||||
wayland_dir = "${root_gen_dir}/${out_dir}"
|
||||
|
||||
generators = [
|
||||
{
|
||||
subcommand = "code"
|
||||
output_suffix = "-protocol.c"
|
||||
},
|
||||
{
|
||||
subcommand = "client-header"
|
||||
output_suffix = "-client-protocol.h"
|
||||
},
|
||||
{
|
||||
subcommand = "server-header"
|
||||
output_suffix = "-server-protocol.h"
|
||||
},
|
||||
]
|
||||
generator_actions = []
|
||||
foreach(g, generators) {
|
||||
action_name = "${target_name}_${g.subcommand}"
|
||||
generator_actions += [ ":" + action_name ]
|
||||
action_foreach(action_name) {
|
||||
sources = invoker.sources
|
||||
script = "//common-mk/file_generator_wrapper.py"
|
||||
output_file = "${wayland_dir}/{{source_name_part}}${g.output_suffix}"
|
||||
outputs = [
|
||||
output_file,
|
||||
]
|
||||
args = [
|
||||
"wayland-scanner",
|
||||
g.subcommand,
|
||||
"{{source}}",
|
||||
output_file,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
static_library(target_name) {
|
||||
if (defined(invoker.configs)) {
|
||||
configs += invoker.configs
|
||||
}
|
||||
deps = generator_actions
|
||||
sources = []
|
||||
foreach(t, deps) {
|
||||
sources += get_target_outputs(t)
|
||||
}
|
||||
if (defined(invoker.deps)) {
|
||||
deps += invoker.deps
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user